1 // This is gel/vtol/vtol_two_chain.cxx
2 #include <vector>
3 #include <iostream>
4 #include <algorithm>
5 #include "vtol_two_chain.h"
6 //:
7 // \file
8 // \verbatim
9 //  Modifications
10 //   05/13/98  RIH replaced append by insert_after to avoid n^2 behavior
11 // \endverbatim
12 
13 #ifdef _MSC_VER
14 #  include "vcl_msvc_warnings.h"
15 #endif
16 
17 #include <vtol/vtol_list_functions.h>
18 #include <vtol/vtol_face.h>
19 #include <vtol/vtol_edge.h>
20 #include <vtol/vtol_vertex.h>
21 #include <vtol/vtol_block.h>
22 #include <vtol/vtol_macros.h>
23 #include <cassert>
24 
25 //***************************************************************************
26 // Initialization
27 //***************************************************************************
28 
link_inferior(const vtol_face_sptr & inf)29 void vtol_two_chain::link_inferior(const vtol_face_sptr& inf)
30 {
31   vtol_topology_object::link_inferior(inf->cast_to_topology_object());
32 }
33 
unlink_inferior(const vtol_face_sptr & inf)34 void vtol_two_chain::unlink_inferior(const vtol_face_sptr& inf)
35 {
36   vtol_topology_object::unlink_inferior(inf->cast_to_topology_object());
37 }
38 
link_chain_inferior(const vtol_two_chain_sptr & chain_inferior)39 void vtol_two_chain::link_chain_inferior(const vtol_two_chain_sptr& chain_inferior)
40 {
41   vtol_chain::link_chain_inferior(chain_inferior->cast_to_chain());
42 }
43 
unlink_chain_inferior(const vtol_two_chain_sptr & chain_inferior)44 void vtol_two_chain::unlink_chain_inferior(const vtol_two_chain_sptr& chain_inferior)
45 {
46   vtol_chain::unlink_chain_inferior(chain_inferior->cast_to_chain());
47 }
48 
49 //---------------------------------------------------------------------------
50 //: Constructor
51 //---------------------------------------------------------------------------
vtol_two_chain(face_list const & faces,bool new_is_cycle)52 vtol_two_chain::vtol_two_chain(face_list const& faces,
53                                bool new_is_cycle)
54 {
55   for (const auto & face : faces)
56   {
57     link_inferior(face);
58     // all face normals point outward.
59     directions_.push_back((signed char)1);
60   }
61   is_cycle_=new_is_cycle;
62 }
63 
64 //---------------------------------------------------------------------------
65 //: Constructor
66 //---------------------------------------------------------------------------
vtol_two_chain(face_list const & faces,std::vector<signed char> const & dirs,bool new_is_cycle)67 vtol_two_chain::vtol_two_chain(face_list const& faces,
68                                std::vector<signed char> const& dirs,
69                                bool new_is_cycle)
70 {
71   std::vector<signed char>::const_iterator di;
72   face_list::const_iterator fi;
73 
74   for (di=dirs.begin(),fi=faces.begin();
75        fi!=faces.end()&&di!=dirs.end();
76        ++fi,++di)
77   {
78     if ((*di)<0)
79       (*fi)->reverse_normal();
80     link_inferior(*fi);
81     directions_.push_back(*di);
82   }
83   is_cycle_=new_is_cycle;
84 }
85 
86 //---------------------------------------------------------------------------
87 //: Pseudo copy constructor.  Deep copy.
88 //---------------------------------------------------------------------------
vtol_two_chain(vtol_two_chain_sptr const & other)89 vtol_two_chain::vtol_two_chain(vtol_two_chain_sptr const& other)
90 {
91   // make a copy of the vertices
92   vertex_list verts; other->vertices(verts);
93   int vlen=verts.size();
94   topology_list newverts(vlen);
95 
96   int i=0;
97   for (auto vi=verts.begin();vi!=verts.end();++vi,++i)
98   {
99     vtol_vertex_sptr v = *vi;
100     newverts[i] = v->clone()->cast_to_topology_object();
101     v->set_id(i);
102   }
103 
104   // make a copy of the edges
105   edge_list edges; other->edges(edges);
106   int elen=edges.size();
107   topology_list newedges(elen);
108 
109   int j=0;
110   for (auto ei=edges.begin();ei!= edges.end();++ei,++j)
111   {
112     vtol_edge_sptr e = *ei;
113     newedges[j] = newverts[e->v1()->get_id()]->cast_to_vertex()->new_edge(
114                   newverts[e->v2()->get_id()]->cast_to_vertex())->cast_to_topology_object();
115     e->set_id(j);
116   }
117 
118   std::vector<signed char> &dirs=other->directions_;
119   topology_list &infs=other->inferiors_;
120 
121   std::vector<signed char>::iterator ddi;
122   topology_list::const_iterator tti;
123   for (ddi=dirs.begin(),tti=infs.begin(); tti!=infs.end()&&ddi!=dirs.end(); ++ddi,++tti)
124   {
125     vtol_face_sptr f=(*tti)->cast_to_face();
126     vtol_face_sptr new_f = f->copy_with_arrays(newverts,newedges);
127 #ifdef DEBUG
128     std::cout << "f\n";
129     f->describe();
130     std::cout << "new f\n";
131     new_f->describe();
132 #endif
133     assert(*new_f == *f);
134 
135     link_inferior(new_f);
136     directions_.push_back((*ddi));
137   }
138 
139   set_cycle(other->is_cycle());
140   const chain_list *hierarchy_infs=other->chain_inferiors();
141 
142   for (const auto & hierarchy_inf : *hierarchy_infs)
143     link_chain_inferior(hierarchy_inf->cast_to_two_chain()->copy_with_arrays(newverts,newedges));
144 }
145 
146 vtol_two_chain *
copy_with_arrays(topology_list & newverts,topology_list & newedges) const147 vtol_two_chain::copy_with_arrays(topology_list &newverts,
148                                  topology_list &newedges) const
149 {
150   const std::vector<signed char> &dirs=directions_;
151   const topology_list &infs=inferiors_;
152 
153   auto *result=new vtol_two_chain(infs.size());
154 
155   std::vector<signed char>::const_iterator di;
156   topology_list::const_iterator ti;
157   for (di=dirs.begin(),ti=infs.begin();
158        ti!=infs.end()&&di!=dirs.end();
159        ++ti,++di)
160   {
161     vtol_face *f=(*ti)->cast_to_face();
162     result->link_inferior(f->copy_with_arrays(newverts,newedges));
163     result->directions_.push_back((*di));
164   }
165 
166   result->set_cycle(is_cycle());
167   const chain_list *hierarchy_infs=chain_inferiors();
168 
169   for (const auto & hierarchy_inf : *hierarchy_infs)
170     result->link_chain_inferior(hierarchy_inf->cast_to_two_chain()->copy_with_arrays(newverts,newedges));
171   return result;
172 }
173 
174 //---------------------------------------------------------------------------
175 // Destructor
176 //---------------------------------------------------------------------------
~vtol_two_chain()177 vtol_two_chain::~vtol_two_chain()
178 {
179   clear();
180   unlink_all_chain_inferiors();
181 }
182 
183 //---------------------------------------------------------------------------
184 //: Clone `this': creation of a new object and initialization
185 // See Prototype pattern
186 //---------------------------------------------------------------------------
clone() const187 vsol_spatial_object_2d* vtol_two_chain::clone() const
188 {
189   return new vtol_two_chain(vtol_two_chain_sptr(const_cast<vtol_two_chain*>(this)));
190 }
191 
192 //---------------------------------------------------------------------------
193 //: Shallow copy with no links
194 //---------------------------------------------------------------------------
195 vtol_topology_object *
shallow_copy_with_no_links() const196 vtol_two_chain::shallow_copy_with_no_links() const
197 {
198   auto *result=new vtol_two_chain();
199   result->is_cycle_=is_cycle_;
200   std::vector<signed char>::const_iterator di;
201 
202   for (di=directions_.begin();di!=directions_.end();++di)
203     result->directions_.push_back((*di));
204   return result;
205 }
206 
207 //***************************************************************************
208 //   Editing Functions
209 //***************************************************************************
210 
211 //: add the superiors from the parent
212 
add_superiors_from_parent(topology_list & sups)213 void vtol_two_chain::add_superiors_from_parent(topology_list &sups)
214 {
215   for (auto & sup : sups)
216     sup->link_inferior(this);
217 
218   chain_list::iterator hi;
219   for (hi=chain_inferiors_.begin();hi!=chain_inferiors_.end();++hi)
220     (*hi)->cast_to_two_chain()->add_superiors_from_parent(sups);
221 }
222 
remove_superiors_of_parent(topology_list & sups)223 void vtol_two_chain::remove_superiors_of_parent(topology_list &sups)
224 {
225   for (auto & sup : sups)
226     sup->unlink_inferior(this);
227 
228   chain_list::iterator hi;
229   for (hi=chain_inferiors_.begin();hi!=chain_inferiors_.end();++hi)
230     (*hi)->cast_to_two_chain()->remove_superiors_of_parent(sups);
231 }
232 
remove_superiors()233 void vtol_two_chain::remove_superiors()
234 {
235   superiors_.clear();
236   chain_list::iterator hi;
237   for (hi=chain_inferiors_.begin();hi!=chain_inferiors_.end();++hi)
238     (*hi)->cast_to_two_chain()->remove_superiors();
239 }
240 
update_superior_list_p_from_hierarchy_parent()241 void vtol_two_chain::update_superior_list_p_from_hierarchy_parent()
242 {
243   // Check to see if there is a parent node in the tree.
244   const vtol_two_chain *hierarchy_parent=nullptr;
245   if (!chain_superiors_.empty())
246     hierarchy_parent = chain_superiors_.front()->cast_to_two_chain();
247 
248   // If vtol_two_chain is a child of another vtol_two_chain...the superiors
249   // lists are updated.
250 
251   if (hierarchy_parent!=nullptr)
252   {
253     const std::list<vtol_topology_object*> *parent_superiors = hierarchy_parent->superiors_list();
254 
255     // Clear all previous superiors.
256     superiors_.clear();
257     std::list<vtol_topology_object*>::const_iterator ti;
258     for (ti=parent_superiors->begin();ti!= parent_superiors->end();++ti)
259       if (std::find(superiors_.begin(),superiors_.end(),*ti)==superiors_.end())
260         superiors_.push_back(*ti);
261 
262     // Recursively update all children.
263     two_chain_list *chains=inferior_two_chains();
264 
265     for (auto & chain : *chains)
266       chain->update_superior_list_p_from_hierarchy_parent();
267     delete chains;
268   }
269 }
270 
271 bool
break_into_connected_components(topology_list &)272 vtol_two_chain::break_into_connected_components( topology_list& /*components*/ )
273 {
274   std::cerr << "vtol_two_chain::break_into_connected_components() not yet implemented\n";
275 #if 0 // TODO
276   topology_list * tmp = get_inferiors();
277   int numfaces = tmp->size();
278   if ( numfaces == 0 ) return false;
279   std::vector< vtol_face * > faces( numfaces );
280   int i=0;
281   for (topology_list::iterator ti= tmp->begin(); ti!=tmp->end();++ti, ++i )
282     faces[ i ] = (*ti)->cast_to_face();
283 
284   // compnum[i] stores the component number of the ith face
285   int * compnum = new int[ numfaces ];
286   assert( compnum );
287 
288   // adjslists stores the adjacency lists representation of the face graph
289   std::vector< int > * adjlists = new std::vector< int > [ numfaces ];
290   assert( adjlists );
291 
292   // build the adjacency list representation
293   for ( i = 0; i < numfaces; ++i )
294   {
295     compnum[ i ] = -1;  // -1 signals it is not part of any component yet
296     for (int j = i+1; j < numfaces; ++j )
297       if ( faces[ i ]->shares_edge_with( faces[ j ] ) )
298       {
299         adjlists[i].push_back( j );
300         adjlists[j].push_back( i );
301       }
302   }
303 
304   // use depth first search to find connected components
305   int numcomps = 0;
306   for ( i = 0; i < numfaces; ++i )
307   {
308     if ( compnum[ i ] == -1 ) // unvisited
309     {
310       compnum[ i ] = numcomps;
311       std::vector<int> to_be_explored;
312       to_be_explored.push( i );
313       while ( to_be_explored.size() )
314       {
315         int f = to_be_explored.pop();
316         for ( adjlists[ f ].begin(); adjlists[ f ].end(); )
317         {
318           if ( compnum[ adjlists[ f ].value() ] == -1 )
319           {
320             compnum[ adjlists[ f ].value() ] = numcomps;
321             to_be_explored.push( adjlists[ f ].value() );
322           }
323         }
324       }
325       ++numcomps;
326     }
327   }
328 
329   if ( numcomps > 1 )
330     for ( i = 0; i < numcomps; ++i )
331     {
332       std::vector< vtol_face * > component_faces;
333       // gather faces belonging to the ith component
334       for ( j = 0; j < numfaces; ++j )
335         if ( compnum[ j ] == i )
336           component_faces.push_back( faces[ j ] );
337       // create either a two chain or a face out of the component
338       if ( component_faces.size() == 1 )
339         components.push_back( component_faces.get( 0 ) );
340       else
341       {
342         vtol_two_chain * newvtol_two_chain = new vtol_two_chain(component_faces, false);
343         // need to check if it is a cycle??
344         components.push_back( newvtol_two_chain );
345       }
346       component_faces.clear(); // necessary??
347     }
348 
349   delete []compnum;
350   delete []adjlists;
351 
352   if ( numcomps == 1 ) return false;
353   else return true;
354 #else // 0
355   std::cerr << "vtol_two_chain::break_into_connected_components() not implemented yet\n";
356   return false; // TODO
357 #endif // 0
358 }
359 
add_face(vtol_face_sptr const & new_face,signed char dir)360 void vtol_two_chain::add_face(vtol_face_sptr const& new_face,
361                               signed char dir)
362 {
363   directions_.push_back(dir);
364   link_inferior(new_face);
365 }
366 
367 #if 1 // deprecated
add_face(vtol_face & new_face,signed char dir)368 void vtol_two_chain::add_face(vtol_face &new_face,
369                               signed char dir)
370 {
371   std::cerr << "Warning: deprecated form of vtol_face::add_face()\n";
372   directions_.push_back(dir);
373   link_inferior(&new_face);
374 }
375 #endif
376 
remove_face(vtol_face_sptr const & doomed_face)377 void vtol_two_chain::remove_face(vtol_face_sptr const& doomed_face)
378 {
379   vtol_topology_object_sptr t=doomed_face->cast_to_topology_object();
380   topology_list::const_iterator i=std::find(inferiors()->begin(),inferiors()->end(),t);
381   topology_list::difference_type index=i-inferiors()->begin();
382 
383   if (index>=0 && i!= inferiors()->end())
384   {
385     auto j = directions_.begin() + index;
386     directions_.erase(j);
387     touch();
388     unlink_inferior(doomed_face);
389   }
390 }
391 
392 #if 1 // deprecated
remove_face(vtol_face & doomed_face)393 void vtol_two_chain::remove_face(vtol_face &doomed_face)
394 {
395   std::cerr << "Warning: deprecated form of vtol_face::remove_face()\n";
396   vtol_topology_object_sptr t=&doomed_face;
397   topology_list::const_iterator i=std::find(inferiors()->begin(),inferiors()->end(),t);
398   topology_list::difference_type index=i-inferiors()->begin();
399 
400   if (index>=0 && i!= inferiors()->end())
401   {
402     auto j = directions_.begin() + index;
403     directions_.erase(j);
404     touch();
405     unlink_inferior(&doomed_face);
406   }
407 }
408 #endif
409 
410 //***************************************************************************
411 //    Accessor Functions
412 //***************************************************************************
413 
face(int i)414 vtol_face_sptr vtol_two_chain::face(int i)
415 {
416   return inferiors_[i]->cast_to_face();
417 }
418 
419 //: outside boundary vertices
420 
outside_boundary_vertices()421 vertex_list *vtol_two_chain::outside_boundary_vertices()
422 {
423   auto *new_ref_list = new vertex_list;
424   std::vector<vtol_vertex*>* ptr_list = this->outside_boundary_compute_vertices();
425   // copy the lists
426 
427   for (auto & ti : *ptr_list)
428     new_ref_list->push_back(ti);
429 
430   delete ptr_list;
431 
432   return new_ref_list;
433 }
434 
435 std::vector<vtol_vertex *> *
outside_boundary_compute_vertices()436 vtol_two_chain::outside_boundary_compute_vertices()
437 {
438   SEL_INF(vtol_vertex,compute_vertices);
439 }
440 
441 //: list of vertices
442 
compute_vertices()443 std::vector<vtol_vertex *> *vtol_two_chain::compute_vertices()
444 {
445   std::vector<vtol_vertex *> *verts = outside_boundary_compute_vertices();
446 
447   // Set current position to the end
448   // verts->set_position(verts->size()-1); - not sure what is supposed to happen here
449 
450   SUBCHAIN_INF(verts,two_chain,vtol_vertex,compute_vertices);
451 }
452 
453 //: outside boundary zero chains
454 
outside_boundary_zero_chains()455 zero_chain_list *vtol_two_chain::outside_boundary_zero_chains()
456 {
457   auto *new_ref_list = new zero_chain_list;
458   std::vector<vtol_zero_chain*>* ptr_list = this->outside_boundary_compute_zero_chains();
459   // copy the lists
460 
461   for (auto & ti : *ptr_list)
462     new_ref_list->push_back(ti);
463 
464   delete ptr_list;
465 
466   return new_ref_list;
467 }
468 
outside_boundary_compute_zero_chains()469 std::vector<vtol_zero_chain*> *vtol_two_chain::outside_boundary_compute_zero_chains()
470 {
471   SEL_INF(vtol_zero_chain,compute_zero_chains);
472 }
473 
474 //: list of zero chains
compute_zero_chains()475 std::vector<vtol_zero_chain*> *vtol_two_chain::compute_zero_chains()
476 {
477   std::vector<vtol_zero_chain*> *zchs;
478   zchs=outside_boundary_compute_zero_chains();
479 
480   SUBCHAIN_INF(zchs,two_chain,vtol_zero_chain,compute_zero_chains);
481 }
482 
483 //: outside boundary edges
outside_boundary_edges()484 edge_list *vtol_two_chain::outside_boundary_edges()
485 {
486   auto *new_ref_list = new edge_list;
487   std::vector<vtol_edge*>* ptr_list = this->outside_boundary_compute_edges();
488   // copy the lists
489 
490   for (auto & ti : *ptr_list)
491     new_ref_list->push_back(ti);
492 
493   delete ptr_list;
494 
495   return new_ref_list;
496 }
497 
498 //: outside boundary edges
outside_boundary_compute_edges()499 std::vector<vtol_edge*> *vtol_two_chain::outside_boundary_compute_edges()
500 {
501   SEL_INF(vtol_edge,compute_edges);
502 }
503 
504 //: list of edges
compute_edges()505 std::vector<vtol_edge*> *vtol_two_chain::compute_edges()
506 {
507   std::vector<vtol_edge*> *edgs;
508   edgs=outside_boundary_compute_edges();
509 
510   SUBCHAIN_INF(edgs,two_chain,vtol_edge,compute_edges);
511 }
512 
513 //: outside one chains
outside_boundary_one_chains()514 one_chain_list *vtol_two_chain::outside_boundary_one_chains()
515 {
516   std::vector<vtol_one_chain*>* ptr_list= outside_boundary_compute_one_chains();
517   auto *ref_list= new one_chain_list;
518 
519   std::vector<vtol_one_chain*>::iterator i;
520   for (i=ptr_list->begin();i!=ptr_list->end();++i)
521     ref_list->push_back(*i);
522 
523   delete ptr_list;
524   return ref_list;
525 }
526 
outside_boundary_compute_one_chains()527 std::vector<vtol_one_chain*> *vtol_two_chain::outside_boundary_compute_one_chains()
528 {
529  SEL_INF(vtol_one_chain,compute_one_chains);
530 }
531 
532 //: one chains
compute_one_chains()533 std::vector<vtol_one_chain*> *vtol_two_chain::compute_one_chains()
534 {
535   std::vector<vtol_one_chain*> *onechs;
536   onechs=outside_boundary_compute_one_chains();
537   SUBCHAIN_INF(onechs,two_chain,vtol_one_chain,compute_one_chains);
538 }
539 
540 //: outside faces
outside_boundary_faces()541 face_list *vtol_two_chain::outside_boundary_faces()
542 {
543   std::vector<vtol_face*>* ptr_list= outside_boundary_compute_faces();
544   auto *ref_list= new face_list;
545 
546   std::vector<vtol_face*>::iterator i;
547   for (i=ptr_list->begin();i!=ptr_list->end();++i)
548     ref_list->push_back(*i);
549 
550   delete ptr_list;
551   return ref_list;
552 }
553 
554 // outside faces
outside_boundary_compute_faces()555 std::vector<vtol_face*> *vtol_two_chain::outside_boundary_compute_faces()
556 {
557  COPY_INF(face);
558 }
559 
560 //: faces
compute_faces()561 std::vector<vtol_face*> *vtol_two_chain::compute_faces()
562 {
563   std::vector<vtol_face*> *facs;
564   facs=outside_boundary_compute_faces();
565   SUBCHAIN_INF(facs,two_chain,vtol_face,compute_faces);
566 }
567 
568 //: list of blocks
compute_blocks()569 std::vector<vtol_block*> *vtol_two_chain::compute_blocks()
570 {
571   if (is_sub_chain())
572   {
573     auto*result=new std::vector<vtol_block*>;
574     std::list<vtol_chain*>::iterator tci;
575     for (tci=chain_superiors_.begin();tci!=chain_superiors_.end();++tci)
576     {
577       std::vector<vtol_block*> *sublist=(*tci)->cast_to_two_chain()->compute_blocks();
578       std::vector<vtol_block*>::iterator si;
579       for (si=sublist->begin();si!=sublist->end();++si)
580         result->push_back(*si);
581       delete sublist;
582     }
583     return tagged_union(result);
584   }
585   else
586   {
587     SEL_SUP(vtol_block,compute_blocks);
588   }
589 }
590 
591 //: list of two chains
592 
compute_two_chains()593 std::vector<vtol_two_chain*> *vtol_two_chain::compute_two_chains()
594 {
595   std::vector<vtol_two_chain*> *result=outside_boundary_compute_two_chains();
596 
597   chain_list::iterator hi;
598   for (hi=chain_inferiors_.begin();hi!=chain_inferiors_.end();++hi )
599     result->push_back((*hi)->cast_to_two_chain());
600   return result;
601 }
602 
inferior_two_chains()603 two_chain_list *vtol_two_chain::inferior_two_chains()
604 {
605   auto *result=new two_chain_list;
606   chain_list::iterator hi;
607   for (hi=chain_inferiors_.begin();hi!=chain_inferiors_.end();++hi)
608     result->push_back((*hi)->cast_to_two_chain());
609   return result;
610 }
611 
612 
superior_two_chains()613 two_chain_list *vtol_two_chain::superior_two_chains()
614 {
615   auto *result=new two_chain_list;
616   std::list<vtol_chain*>::iterator hi;
617   for (hi=chain_superiors_.begin();hi!=chain_superiors_.end();++hi)
618     result->push_back((*hi)->cast_to_two_chain());
619   return result;
620 }
621 
outside_boundary_two_chains()622 two_chain_list *vtol_two_chain::outside_boundary_two_chains()
623 {
624   std::vector<vtol_two_chain*>* ptr_list= outside_boundary_compute_two_chains();
625   auto *ref_list= new two_chain_list;
626 
627   std::vector<vtol_two_chain*>::iterator i;
628   for (i=ptr_list->begin();i!=ptr_list->end();++i)
629     ref_list->push_back(*i);
630 
631   delete ptr_list;
632   return ref_list;
633 }
634 
outside_boundary_compute_two_chains()635 std::vector<vtol_two_chain*>  *vtol_two_chain::outside_boundary_compute_two_chains()
636 {
637   LIST_SELF(vtol_two_chain);
638 }
639 
640 //***************************************************************************
641 //     Operator Functions
642 //***************************************************************************
643 
644 //: equality operator
645 
operator ==(vtol_two_chain const & other) const646 bool vtol_two_chain::operator==(vtol_two_chain const& other) const
647 {
648   if (this==&other)
649     return true;
650 
651   if (numinf()!=other.numinf())
652     return false;
653 
654   topology_list::const_iterator ti1,ti2;
655   for (ti1=other.inferiors()->begin(),ti2=inferiors()->begin();
656        ti2!=inferiors()->end(); ++ti1,++ti2)
657   {
658     vtol_face *f1=(*ti2)->cast_to_face();
659     vtol_face *f2=(*ti1)->cast_to_face();
660     if (!(*f1==*f2))
661       return false;
662   }
663 
664   // check out the directions
665 
666   const std::vector<signed char> *dir1=this->directions();
667   const std::vector<signed char> *dir2=other.directions();
668 
669   std::vector<signed char>::const_iterator d1;
670   std::vector<signed char>::const_iterator d2;
671   for (d1=dir1->begin(), d2=dir2->begin(); d1 != dir1->end(); ++d1, ++d2)
672     if (!(*d1 == *d2))
673       return false;
674 
675   const chain_list &righth=chain_inferiors_;
676   const chain_list &lefth=other.chain_inferiors_;
677   if (righth.size()!=lefth.size())
678     return false;
679 
680   chain_list::const_iterator hi1,hi2;
681 
682   for (hi1=righth.begin(),hi2=lefth.begin();
683        hi1!=righth.end()&&hi2!=lefth.end();
684        ++hi1,++hi2)
685     if ( !(*(*hi1) == *(*hi2)))
686       return false;
687 
688   return true;
689 }
690 
691 //: spatial object equality
692 
operator ==(vsol_spatial_object_2d const & obj) const693 bool vtol_two_chain::operator==(vsol_spatial_object_2d const& obj) const
694 {
695   return
696    obj.cast_to_topology_object() &&
697    obj.cast_to_topology_object()->cast_to_two_chain() &&
698    *this == *obj.cast_to_topology_object()->cast_to_two_chain();
699 }
700 
701 //***************************************************************************
702 //    Utility Functions
703 //***************************************************************************
704 
705 //: correct the chain directions
correct_chain_directions()706 void vtol_two_chain::correct_chain_directions()
707 {
708   std::cerr << "vtol_two_chain::correct_chain_directions() not yet implemented\n";
709 }
710 
711 //***************************************************************************
712 //    Print Functions
713 //***************************************************************************
714 
print(std::ostream & strm) const715 void vtol_two_chain::print(std::ostream &strm) const
716 {
717   strm << "<vtol_two_chain with " << inferiors()->size() << " faces>\n";
718 }
719 
describe_directions(std::ostream & strm,int blanking) const720 void vtol_two_chain::describe_directions(std::ostream &strm,
721                                          int blanking) const
722 {
723   for (int j=0; j<blanking; ++j) { strm << ' '; }
724   strm << "<Dirs [" << directions_.size() << "]:";
725 
726   std::vector<signed char>::const_iterator di;
727   for (di=directions_.begin();di!=directions_.end();++di)
728   {
729     strm << ' ' << (int)(*di);
730   }
731   strm << ">\n";
732 }
733 
describe(std::ostream & strm,int blanking) const734 void vtol_two_chain::describe(std::ostream &strm,
735                               int blanking) const
736 {
737   for (int j=0; j<blanking; ++j) strm << ' ';
738   print(strm);
739   describe_inferiors(strm,blanking);
740   describe_directions(strm,blanking);
741   describe_superiors(strm,blanking);
742 }
743 
direction(vtol_face const & f) const744 signed char vtol_two_chain::direction(vtol_face const& f) const
745 {
746   // return the direction of the face
747 
748   std::vector<signed char>::const_iterator dit;
749   topology_list::const_iterator toit;
750 
751   dit=directions_.begin();
752   for (toit=inferiors()->begin();toit!=inferiors()->end();++toit)
753   {
754     vtol_face *cf=(*toit)->cast_to_face();
755     if (cf==&f)
756       return *dit;
757     ++dit;
758   }
759   return (signed char)1;
760 }
761