1 // This is gel/vtol/vtol_face_2d.cxx
2 #include "vtol_face_2d.h"
3 //:
4 // \file
5 
6 #include <cassert>
7 #ifdef _MSC_VER
8 #  include "vcl_msvc_warnings.h"
9 #endif
10 #include <vtol/vtol_topology_object.h>
11 #include <vtol/vtol_edge_2d.h>
12 #include <vtol/vtol_one_chain.h>
13 #include <vsol/vsol_region_2d.h>
14 #include <vsol/vsol_rectangle_2d.h>
15 #include <vsol/vsol_point_2d.h>
16 
17 //---------------------------------------------------------------------------
18 //: Pseudo copy constructor.  Deep copy.
19 //---------------------------------------------------------------------------
vtol_face_2d(vtol_face_2d_sptr const & other)20 vtol_face_2d::vtol_face_2d(vtol_face_2d_sptr const& other)
21   : surface_(nullptr)
22 {
23   edge_list edgs;    other->edges(edgs);
24   vertex_list verts; other->vertices(verts);
25 
26   topology_list newedges(edgs.size());
27   topology_list newverts(verts.size());
28 
29   int i=0;
30   for (auto vi=verts.begin();vi!=verts.end();++vi,++i)
31   {
32     vtol_vertex_sptr v=(*vi);
33     newverts[i]=v->clone()->cast_to_topology_object();
34     v->set_id(i);
35   }
36   int j=0;
37   for (auto ei=edgs.begin();ei!= edgs.end();++ei,++j)
38   {
39     vtol_edge_sptr e=(*ei);
40 
41     vtol_topology_object_sptr V1 = newverts[e->v1()->get_id()];
42     vtol_topology_object_sptr V2 = newverts[e->v2()->get_id()];
43     if (!V1 || !V2)
44     {
45       std::cerr << "Inconsistent topology in vtol_face_2d pseudo copy constructor\n";
46       link_inferior(new vtol_one_chain);
47       return;
48      }
49     // make the topology and geometry match
50     vtol_edge_sptr newedge=new vtol_edge_2d(V1->cast_to_vertex(),
51                                             V2->cast_to_vertex());
52 
53     newedges[j]=newedge->cast_to_topology_object();
54     e->set_id(j);
55   }
56 
57   // This is a deep copy of the vtol_face_2d.
58   topology_list::const_iterator ii;
59   for (ii=other->inferiors()->begin();ii!= other->inferiors()->end();++ii)
60     link_inferior((*ii)->cast_to_one_chain()->copy_with_arrays(newverts,newedges));
61   set_surface(nullptr);
62   if (other->surface_)
63     set_surface(other->surface_->clone()->cast_to_region());
64 }
65 
66 //---------------------------------------------------------------------------
67 //: Clone `this': creation of a new object and initialization.
68 // See Prototype pattern
69 //---------------------------------------------------------------------------
clone() const70 vsol_spatial_object_2d* vtol_face_2d::clone() const
71 {
72   return new vtol_face_2d(vtol_face_2d_sptr(const_cast<vtol_face_2d*>(this)));
73 }
74 
surface() const75 vsol_region_2d_sptr vtol_face_2d::surface() const
76 {
77   return surface_;
78 }
79 
80 //: copy with an array
81 
82 vtol_face *
copy_with_arrays(topology_list & verts,topology_list & edges) const83 vtol_face_2d::copy_with_arrays(topology_list &verts,
84                                topology_list &edges) const
85 {
86   auto *newface=new vtol_face_2d();
87   topology_list::const_iterator i;
88   for (i=newface->inferiors()->begin();i!= newface->inferiors()->end();++i )
89     newface->unlink_inferior((*i)->cast_to_one_chain());
90   newface->inferiors()->clear();
91   for (i=inferiors()->begin();i!=inferiors()->end();++i)
92   {
93     vtol_one_chain *onech=(*i)->cast_to_one_chain()->copy_with_arrays(verts,edges);
94     assert(*onech == *(*i));
95     newface->link_inferior(onech);
96   }
97   if (surface_)
98     newface->set_surface(surface_->clone()->cast_to_region());
99   return newface;
100 }
101 
102 //---------------------------------------------------------------------------
103 //: Copy with no links. Only copy the surface if it exists
104 //---------------------------------------------------------------------------
shallow_copy_with_no_links() const105 vtol_face *vtol_face_2d::shallow_copy_with_no_links() const
106 {
107   vtol_face_2d *result;
108   result=new vtol_face_2d;
109   result->set_surface(nullptr);
110   if (surface_)
111     result->set_surface(surface_->clone()->cast_to_region());
112   return result;
113 }
114 
115 //: Constructor for a planar vtol_face_2d from an ordered list of vertices.
116 // Edges are constructed by connecting vtol_vertex_2d[i] to vtol_vertex_2d[(i+1)mod L].
117 // L is the length of the vertex list, verts, and i goes from 0 to L.
118 // Require: verts.size()>2
119 
vtol_face_2d(vertex_list const & verts)120 vtol_face_2d::vtol_face_2d(vertex_list const& verts)
121   :surface_(nullptr)
122 {
123   // require
124   assert(verts.size()>2);
125 
126   double xmin=0;
127   double ymin=0;
128   double xmax=1;
129   double ymax=1;
130 
131   set_surface(new vsol_rectangle_2d(new vsol_point_2d(xmin,ymin),
132                                     new vsol_point_2d(xmax,ymin),
133                                     new vsol_point_2d(xmax,ymax),
134                                     new vsol_point_2d(xmin,ymax)));
135 
136   //generate a list of edges for edge loop
137   bool done=false;
138   auto vi=verts.begin();
139   vtol_vertex_sptr v01=(*vi);
140   edge_list elist;
141   std::vector<signed char> directions;
142 
143   while (!done)
144   {
145     // if no next vertex, then use the first vertex by calling
146     // verts->end() again to wrap around  This will close the loop
147     ++vi;
148 
149     if (vi==verts.end())
150     {
151       vi=verts.begin();
152       done=true;
153     }
154 
155     vtol_vertex_sptr v02=(*vi); // get the next vertex (may be first)
156 
157     vtol_edge_sptr newedge=v01->new_edge(v02);
158     elist.push_back(newedge);
159 
160     if (*v02 == *(newedge->v2()))
161       directions.push_back((signed char)1);
162     else
163       directions.push_back((signed char)(-1));
164     v01=v02; // in the next go around v1 is v2 of the last
165   }
166 
167   link_inferior(new vtol_one_chain(elist,directions,true));
168 }
169 
170 //: Constructor for a planar face from a list of one_chains.
171 // This method assumes that the first vtol_one_chain on the list is the outside
172 // boundary vtol_one_chain.  The remaining one_chains are holes boundaries
173 // on the face.
174 
vtol_face_2d(one_chain_list const & onechs)175 vtol_face_2d::vtol_face_2d(one_chain_list const& onechs)
176   :surface_(nullptr)
177 {
178   // 1)  Add one chains to the inferiors list.
179   //     Assume that the first vtol_one_chain on the
180   //     list is the outside boundary...the
181   //     remaining one_chains are holes.
182 
183   if (!onechs.empty())
184     link_inferior(onechs[0]);
185 
186   vtol_one_chain_sptr onech=get_boundary_cycle();
187 
188   // 2) This constructor will assume that the
189   // surface is an ImplicitPlane().
190 
191   double xmin=0;
192   double ymin=0;
193   double xmax=1;
194   double ymax=1;
195 
196   set_surface(new vsol_rectangle_2d(new vsol_point_2d(xmin,ymin),
197                                     new vsol_point_2d(xmax,ymin),
198                                     new vsol_point_2d(xmax,ymax),
199                                     new vsol_point_2d(xmin,ymax)));
200 
201   if (onech)
202     for (unsigned int i = 1; i < onechs.size(); ++i)
203       onech->link_chain_inferior(onechs[i]);
204 }
205 
206 //: Constructor of a Planar face from a vtol_one_chain.
207 //  This method uses the vtol_one_chain, edgeloop, as the outside boundary of the face.
208 
vtol_face_2d(vtol_one_chain_sptr const & edgeloop)209 vtol_face_2d::vtol_face_2d(vtol_one_chain_sptr const& edgeloop)
210   : surface_(nullptr)
211 {
212   link_inferior(edgeloop);
213 
214   // TODO - surface is set to bounding box rectangle, which is often too large
215   set_surface(new vsol_rectangle_2d(new vsol_point_2d(get_min_x(),get_min_y()),
216                                     new vsol_point_2d(get_max_x(),get_min_y()),
217                                     new vsol_point_2d(get_max_x(),get_max_y()),
218                                     new vsol_point_2d(get_min_x(),get_max_y())));
219 }
220 
221 //: Constructor requiring only the underlying geometric surface
vtol_face_2d(vsol_region_2d & facesurf)222 vtol_face_2d::vtol_face_2d (vsol_region_2d &facesurf)
223   : surface_(nullptr)
224 {
225   set_surface(&facesurf);
226 
227   // not much, but at least it's a start...
228 }
229 
230 //: Set the underlying geometric surface.
set_surface(vsol_region_2d_sptr const & newsurf)231 void vtol_face_2d::set_surface(vsol_region_2d_sptr const& newsurf)
232 {
233   surface_=newsurf;
234   touch();
235 }
236 
operator ==(const vtol_face_2d & other) const237 bool vtol_face_2d::operator==(const vtol_face_2d &other) const
238 {
239   if (this==&other) return true;
240 
241   if (numinf()!=other.numinf())
242     return false;
243 
244   if ( (surface_ && ! other.surface_) ||
245        (other.surface_ && ! surface_))
246     return false;
247 
248   if (surface_ && *surface_!=*(other.surface_))
249     return false;
250 
251   topology_list::const_iterator ti1;
252   topology_list::const_iterator ti2;
253 
254   for (ti1=inferiors()->begin(),ti2=other.inferiors()->begin();
255        ti1!=inferiors()->end(); ++ti1,++ti2)
256     if (!(*(*ti1)== *(*ti2)))
257       return false;
258 
259   return true;
260 }
261 
operator ==(const vtol_face & other) const262 bool vtol_face_2d::operator==(const vtol_face &other) const
263 {
264   if (! other.cast_to_face_2d() )
265     return false;
266   else
267     return *this == (vtol_face_2d const&) other;
268 }
269 
270 //: spatial object equality
271 
operator ==(const vsol_spatial_object_2d & obj) const272 bool vtol_face_2d::operator==(const vsol_spatial_object_2d& obj) const
273 {
274   return
275    obj.cast_to_topology_object() &&
276    obj.cast_to_topology_object()->cast_to_face() &&
277    obj.cast_to_topology_object()->cast_to_face()->cast_to_face_2d() &&
278    *this == *obj.cast_to_topology_object()->cast_to_face()->cast_to_face_2d();
279 }
280 
281 //:
282 //  This method describes the data members of the vtol_face_2d including the
283 // Inferiors.  The blanking argument is used to indent the output in
284 // a clear fashion.
285 
describe(std::ostream & strm,int blanking) const286 void vtol_face_2d::describe(std::ostream &strm,
287                             int blanking) const
288 {
289   for (int j=0; j<blanking; ++j) strm << ' ';
290   print(strm);
291   for (unsigned int i=0;i<inferiors()->size();++i)
292   {
293     if ((inferiors_[i])->cast_to_one_chain()!=nullptr)
294       inferiors_[i]->cast_to_one_chain()->describe(strm,blanking);
295     else
296       strm << "*** Odd inferior for a face\n";
297   }
298 }
299 
300 //:
301 // This method prints out a simple text representation for the vtol_face_2d which
302 // includes its address in memory.
print(std::ostream & strm) const303 void vtol_face_2d::print(std::ostream &strm) const
304 {
305   strm << "<vtol_face_2d ";
306 
307   topology_list::const_iterator ii;
308   for (ii=inferiors()->begin();ii!= inferiors()->end();++ii)
309   {
310     strm << ' ' << (*ii)->inferiors()->size();
311   }
312   strm << "   " << (void const *) this << ">\n";
313 }
314 
315 //: copy the geometry
316 
copy_geometry(const vtol_face & other)317 void vtol_face_2d::copy_geometry(const vtol_face &other)
318 {
319   if (other.cast_to_face_2d())
320     surface_ = other.cast_to_face_2d()->surface();
321 }
322 
323 //: provide a mechanism to compare geometry
324 
compare_geometry(const vtol_face & other) const325 bool vtol_face_2d::compare_geometry(const vtol_face &other) const
326 {
327   if (other.cast_to_face_2d())
328     return (*surface_)== *(other.cast_to_face_2d()->surface());
329   else
330     return false;
331 }
332