1 // This is gel/vtol/vtol_face.cxx
2 #include "vtol_face.h"
3 //:
4 // \file
5 
6 #include <cassert>
7 #ifdef _MSC_VER
8 #  include "vcl_msvc_warnings.h"
9 #endif
10 #include <vtol/vtol_macros.h>
11 #include <vtol/vtol_two_chain.h>
12 #include <vtol/vtol_vertex.h>
13 #include <vtol/vtol_edge.h>
14 #include <vtol/vtol_one_chain.h>
15 #include <vtol/vtol_list_functions.h>
16 
link_inferior(const vtol_one_chain_sptr & inf)17 void vtol_face::link_inferior(const vtol_one_chain_sptr& inf)
18 {
19   vtol_topology_object::link_inferior(inf->cast_to_topology_object());
20 }
21 
unlink_inferior(const vtol_one_chain_sptr & inf)22 void vtol_face::unlink_inferior(const vtol_one_chain_sptr& inf)
23 {
24   vtol_topology_object::unlink_inferior(inf->cast_to_topology_object());
25 }
26 
27 //---------------------------------------------------------------------------
28 // Destructor
29 //---------------------------------------------------------------------------
~vtol_face()30 vtol_face::~vtol_face()
31 {
32   unlink_all_inferiors();
33 }
34 
35 //:
36 // Returns an ordered list of vertices of the outside boundary of the
37 // face.  All vertices on any holes of the face are \e not included.
38 // This vertex list is ordered such that a positive normal is
39 // computing using the Right Hand rule in the direction of the vertex
40 // list.
41 
outside_boundary_vertices()42 vertex_list *vtol_face::outside_boundary_vertices() {
43   auto *new_ref_list = new vertex_list;
44   std::vector<vtol_vertex*>* ptr_list = this->outside_boundary_compute_vertices();
45 
46   // copy the lists
47   for (std::vector<vtol_vertex*>::const_iterator ti = ptr_list->begin();
48        ti != ptr_list->end(); ++ti)
49     new_ref_list->push_back(*ti);
50 
51   delete ptr_list;
52   return new_ref_list;
53 }
54 
outside_boundary_compute_vertices()55 std::vector<vtol_vertex *> *vtol_face::outside_boundary_compute_vertices() {
56   OUTSIDE_BOUNDARY(vtol_vertex,one_chain,compute_vertices);
57 }
58 
59 //:
60 // Returns a vtol_vertex list of all the vertices on the face.
61 // If the face does not have any holes, this vertex list is ordered
62 // in the direction of a positive normal using the Right Hand rule.
63 
compute_vertices()64 std::vector<vtol_vertex *> *vtol_face::compute_vertices() {
65   SEL_INF(vtol_vertex,compute_vertices);
66 }
67 
68 //:
69 // Returns a list of the zero_chains on the outside boundary of the face.
70 // All zero_chains on any hole boundaries of the face are \e not included.
71 
72 std::vector<vtol_zero_chain *> *
outside_boundary_compute_zero_chains()73 vtol_face::outside_boundary_compute_zero_chains() {
74   OUTSIDE_BOUNDARY(vtol_zero_chain,one_chain,compute_zero_chains);
75 }
76 
77 //:
78 // Returns a list of the zero_chains on the outside boundary of the face.
79 // All zero_chains on any hole boundaries of the face are \e not included.
80 
outside_boundary_zero_chains()81 zero_chain_list *vtol_face::outside_boundary_zero_chains() {
82   auto *new_ref_list = new zero_chain_list;
83   std::vector<vtol_zero_chain*>* ptr_list = this->outside_boundary_compute_zero_chains();
84 
85   // copy the lists
86   for (std::vector<vtol_zero_chain*>::const_iterator ti = ptr_list->begin();
87        ti != ptr_list->end(); ++ti)
88     new_ref_list->push_back(*ti);
89 
90   delete ptr_list;
91   return new_ref_list;
92 }
93 
94 //: Returns a list of zero_chains of the face.
95 
compute_zero_chains()96 std::vector<vtol_zero_chain *> *vtol_face::compute_zero_chains() {
97   SEL_INF(vtol_zero_chain,compute_zero_chains);
98 }
99 
100 //:
101 // Returns a list of edges that make up the outside boundary of the
102 // face. All edges on any hole boundaries are \e not included.
103 
outside_boundary_compute_edges()104 std::vector<vtol_edge *> *vtol_face::outside_boundary_compute_edges() {
105   OUTSIDE_BOUNDARY(vtol_edge,one_chain,compute_edges);
106 }
107 
108 //---------------------------------------------------------------------------
109 //: Get the outside boundary edges
110 //---------------------------------------------------------------------------
outside_boundary_edges()111 edge_list *vtol_face::outside_boundary_edges() {
112   auto *new_ref_list = new edge_list;
113   std::vector<vtol_edge*>* ptr_list = this->outside_boundary_compute_edges();
114 
115   // copy the lists
116   for (std::vector<vtol_edge*>::const_iterator ti = ptr_list->begin();
117        ti != ptr_list->end(); ++ti)
118     new_ref_list->push_back(*ti);
119 
120   delete ptr_list;
121   return new_ref_list;
122 }
123 
124 //: Returns a list of edges on the face.
compute_edges()125 std::vector<vtol_edge *> *vtol_face::compute_edges() {
126   SEL_INF(vtol_edge,compute_edges);
127 }
128 
129 //: Returns a list of one_chains that make up the outside boundary of the face.
130 
outside_boundary_one_chains()131 one_chain_list *vtol_face::outside_boundary_one_chains() {
132   std::vector<vtol_one_chain*>* ptr_list= outside_boundary_compute_one_chains();
133   auto *ref_list= new one_chain_list;
134 
135   for (std::vector<vtol_one_chain*>::const_iterator i=ptr_list->begin();
136        i!=ptr_list->end(); ++i)
137     ref_list->push_back(*i);
138 
139   delete ptr_list;
140   return ref_list;
141 }
142 
143 std::vector<vtol_one_chain *> *
outside_boundary_compute_one_chains()144 vtol_face::outside_boundary_compute_one_chains() {
145   COPY_INF(one_chain);
146 }
147 
148 //: Returns a list of all Onechains of the face.
149 
compute_one_chains()150 std::vector<vtol_one_chain *> *vtol_face::compute_one_chains() {
151   SEL_INF(vtol_one_chain,compute_one_chains);
152 }
153 
154 //:
155 // Returns a list of that has itself as the only element.  This method
156 // is needed for traversing the model hierarchy consistently.
157 
compute_faces()158 std::vector<vtol_face *> *vtol_face::compute_faces() { LIST_SELF(vtol_face); }
159 
160 //: Returns a list of all the two_chains which contain the vtol_face.
compute_two_chains()161 std::vector<vtol_two_chain *> *vtol_face::compute_two_chains() {
162   SEL_SUP(vtol_two_chain,compute_two_chains);
163 }
164 
165 //: Returns a list of all the blocks that contain the vtol_face.
166 
compute_blocks()167 std::vector<vtol_block *> *vtol_face::compute_blocks() {
168   SEL_SUP(vtol_block,compute_blocks);
169 }
170 
171 //---------------------------------------------------------------------------
172 //: Does `this' share an edge with `f' ?
173 //  Comparison of edge pointers, not geometric values
174 //---------------------------------------------------------------------------
shares_edge_with(vtol_face_sptr const & f)175 bool vtol_face::shares_edge_with(vtol_face_sptr const& f)
176 {
177   edge_list thised; this->edges(thised);
178   edge_list fedges; f->edges(fedges);
179   for (edge_list::const_iterator ei1=thised.begin(); ei1!=thised.end(); ++ei1)
180     for (edge_list::const_iterator ei2=fedges.begin(); ei2!=fedges.end(); ++ei2)
181       if ((*ei1)==(*ei2)) return true;
182   return false;
183 }
184 
185 //:
186 // Links new_vtol_one_chain as an inferior of the vtol_face and returns True if
187 // successful. This method will be replacing all calls to add_edge_loop().
188 
add_one_chain(vtol_one_chain_sptr const & new_vtol_one_chain)189 void vtol_face::add_one_chain(vtol_one_chain_sptr const& new_vtol_one_chain)
190 {
191   // require
192   assert(new_vtol_one_chain->contains_sub_chains());
193 
194   link_inferior(new_vtol_one_chain);
195 }
196 
197 #if 1 // deprecated
add_one_chain(vtol_one_chain & new_vtol_one_chain)198 void vtol_face::add_one_chain(vtol_one_chain &new_vtol_one_chain)
199 {
200   std::cerr << "Warning: deprecated form of vtol_face::add_one_chain()\n";
201   assert(new_vtol_one_chain.contains_sub_chains());
202 
203   link_inferior(&new_vtol_one_chain);
204 }
205 #endif
206 
207 //: deep equality check on faces.  uses fuzzy equal on vertices.
208 //
209 
operator ==(const vtol_face & other) const210 bool vtol_face::operator==(const vtol_face &other) const
211 {
212   if (this==&other) return true;
213 
214   if (numinf()!=other.numinf())
215     return false;
216 
217   if (!compare_geometry(other))
218     return false;
219 
220   topology_list::const_iterator ti1;
221   topology_list::const_iterator ti2;
222 
223   for (ti1=inferiors()->begin(),ti2=other.inferiors()->begin(); ti1!=inferiors()->end(); ++ti1,++ti2)
224       if (!(*(*ti1)== *(*ti2)))
225         return false;
226 
227   return true;
228 }
229 
230 //---------------------------------------------------------------------------
231 //: Spatial object equality
232 //---------------------------------------------------------------------------
operator ==(const vsol_spatial_object_2d & obj) const233 bool vtol_face::operator==(const vsol_spatial_object_2d& obj) const
234 {
235   return
236    obj.cast_to_topology_object() &&
237    obj.cast_to_topology_object()->cast_to_face() &&
238    *this == *obj.cast_to_topology_object()->cast_to_face();
239 }
240 
241 //: Returns the ith inferior vtol_one_chain of the vtol_face.
242 
get_one_chain(int which)243 vtol_one_chain_sptr vtol_face::get_one_chain(int which)
244 {
245   assert((unsigned int)which < inferiors()->size());
246   if ((unsigned int)which < inferiors()->size())
247     return (inferiors_[which])->cast_to_one_chain();
248   else
249   {
250     std::cerr << "Tried to get bad edge_loop from face\n";
251     return nullptr;
252   }
253 }
254 
255 //: Returns the first inferior vtol_one_chain of the vtol_face (the boundary onechain).
256 
get_boundary_cycle()257 vtol_one_chain_sptr vtol_face::get_boundary_cycle() {
258   // The outside boundary vtol_one_chain will *always*
259   // be the first one chain in the inferiors
260   // list.
261   return get_one_chain(0);
262 }
263 
264 //---------------------------------------------------------------------------
265 //: Adds a new hole to the face
266 //---------------------------------------------------------------------------
add_hole_cycle(vtol_one_chain_sptr new_hole)267 bool vtol_face::add_hole_cycle(vtol_one_chain_sptr new_hole)
268 {
269   vtol_one_chain_sptr onech=get_boundary_cycle();
270 
271   if (onech)
272   {
273     onech->link_chain_inferior(new_hole);
274     return true;
275   }
276   else
277     return false;
278 }
279 
280 // Returns a list of the one_chains that make up the holes of the vtol_face.
281 
get_hole_cycles()282 one_chain_list *vtol_face::get_hole_cycles() {
283   auto * result=new one_chain_list;
284 
285   topology_list::const_iterator ii;
286   for (ii=inferiors()->begin();ii!=inferiors()->end();++ii)
287   {
288     one_chain_list* templist=(*ii)->cast_to_one_chain()->inferior_one_chains();
289 
290     for (one_chain_list::const_iterator oi=templist->begin();oi!=templist->end();++oi)
291       result->push_back(*oi);
292     delete templist;
293   }
294 
295   return result;
296 }
297 
298 //: Returns the number of edges on the vtol_face.
299 //
300 
get_num_edges() const301 int vtol_face::get_num_edges() const {
302   int result=0;
303   topology_list::const_iterator ii;
304   for (ii=inferiors()->begin();ii!=inferiors()->end();++ii)
305     result+=((*ii)->cast_to_one_chain())->numinf();
306   return result;
307 }
308 
309 //---------------------------------------------------------------------------
310 //: Reverse the direction of the face
311 //---------------------------------------------------------------------------
reverse_normal()312 void vtol_face::reverse_normal() {
313   topology_list::const_iterator ti;
314   for (ti=inferiors()->begin();ti!=inferiors()->end();++ti)
315     (*ti)->cast_to_one_chain()->reverse_directions();
316   // compute_normal();
317 }
318 
319 //:
320 //  This method describes the data members of the vtol_face including the
321 // Inferiors.  The blanking argument is used to indent the output in
322 // a clear fashion.
323 
describe(std::ostream & strm,int blanking) const324 void vtol_face::describe(std::ostream &strm,
325                          int blanking) const
326 {
327   for (int j=0; j<blanking; ++j) strm << ' ';
328   print();
329   for (unsigned int i=0;i<inferiors()->size();++i)
330   {
331     if ((inferiors_[i])->cast_to_one_chain()!=nullptr)
332       (inferiors_[i])->cast_to_one_chain()->describe(strm,blanking);
333     else
334       std::cout << "*** Odd inferior for a face\n";
335   }
336 }
337 
338 //:
339 // This method prints out a simple text representation for the vtol_face which
340 // includes its address in memory.
print(std::ostream & strm) const341 void vtol_face::print(std::ostream &strm) const
342 {
343   strm << "<vtol_face ";
344 
345   topology_list::const_iterator ii;
346   for (ii=inferiors()->begin();ii!= inferiors()->end();++ii)
347   {
348     strm << ' ' << (*ii)->inferiors()->size();
349   }
350   strm << "   " << (void const *) this << ">\n";
351 }
352 
353 //-------------------------------------------------------------
354 //: Update the bounding box, a member of vsol_spatial_object_2d.
355 //  The algorithm uses the bounding boxes of the vtol_edge(s) forming
356 //  the boundary of the face.
compute_bounding_box() const357 void vtol_face::compute_bounding_box() const
358 {
359   this->empty_bounding_box();
360   edge_list edges; this->edges(edges);
361   for (auto & edge : edges)
362     this->add_to_bounding_box(edge->get_bounding_box());
363 }
364 
365 //: This method determines if a vtol_face is a hole of another vtol_face.
IsHoleP() const366 bool vtol_face::IsHoleP() const
367 {
368   edge_list* edges = const_cast<vtol_face*>(this)->outside_boundary_edges();
369   if (edges->empty()) {
370     delete edges;
371     return false;
372   }
373   vtol_edge_sptr e = edges->front();
374   delete edges;
375   std::list<vtol_topology_object*> const* chains = e->superiors_list();
376   for (auto chain : *chains)
377     if (chain->cast_to_one_chain()->numsup() > 0)
378       return true;
379   return false;
380 }
381