1 // This is gel/vsol/vsol_polygon_2d.cxx
2 #include <iostream>
3 #include <cmath>
4 #include "vsol_polygon_2d.h"
5 //:
6 // \file
7 #include "vsl/vsl_vector_io.h"
8 #include <cassert>
9 #ifdef _MSC_VER
10 #  include "vcl_msvc_warnings.h"
11 #endif
12 #include <vsol/vsol_point_2d.h>
13 #include "vgl/vgl_vector_2d.h"
14 
15 //***************************************************************************
16 // Initialization
17 //***************************************************************************
18 
19 //---------------------------------------------------------------------------
20 //: Constructor from a std::vector (not a geometric vector but a list of points)
21 // Require: new_vertices.size()>=3
22 //---------------------------------------------------------------------------
vsol_polygon_2d(const std::vector<vsol_point_2d_sptr> & new_vertices)23 vsol_polygon_2d::vsol_polygon_2d(const std::vector<vsol_point_2d_sptr> &new_vertices)
24   : vsol_region_2d()
25 {
26   // require
27   assert(new_vertices.size()>=3);
28 
29   storage_=new std::vector<vsol_point_2d_sptr>(new_vertices);
30 }
31 
32 //---------------------------------------------------------------------------
33 // Copy constructor
34 //---------------------------------------------------------------------------
vsol_polygon_2d(const vsol_polygon_2d & other)35 vsol_polygon_2d::vsol_polygon_2d(const vsol_polygon_2d &other)
36   : vsol_region_2d(other)
37 {
38   //vsol_point_2d_sptr p;
39   storage_=new std::vector<vsol_point_2d_sptr>(*other.storage_);
40   for (unsigned int i=0;i<storage_->size();++i)
41     (*storage_)[i]=new vsol_point_2d(*((*other.storage_)[i]));
42 }
43 
44 //---------------------------------------------------------------------------
45 // Destructor
46 //---------------------------------------------------------------------------
~vsol_polygon_2d()47 vsol_polygon_2d::~vsol_polygon_2d()
48 {
49   for (auto & i : *storage_)
50    i = nullptr;
51   delete storage_;
52 }
53 
54 //---------------------------------------------------------------------------
55 //: Clone `this': creation of a new object and initialization
56 // See Prototype pattern
57 //---------------------------------------------------------------------------
clone() const58 vsol_spatial_object_2d *vsol_polygon_2d::clone() const {
59   return new vsol_polygon_2d(*this);
60 }
61 
62 //***************************************************************************
63 // Safe casting
64 //***************************************************************************
65 
cast_to_polygon()66 vsol_polygon_2d *vsol_polygon_2d::cast_to_polygon() {
67   if (!cast_to_triangle()||!cast_to_rectangle())
68     return this;
69   else
70     return nullptr;
71 }
72 
cast_to_polygon() const73 const vsol_polygon_2d *vsol_polygon_2d::cast_to_polygon() const {
74   if (!cast_to_triangle()||!cast_to_rectangle())
75     return this;
76   else
77     return nullptr;
78 }
79 
cast_to_triangle()80 vsol_triangle_2d *vsol_polygon_2d::cast_to_triangle() { return nullptr; }
cast_to_triangle() const81 const vsol_triangle_2d *vsol_polygon_2d::cast_to_triangle() const {
82   return nullptr;
83 }
84 
cast_to_rectangle()85 vsol_rectangle_2d *vsol_polygon_2d::cast_to_rectangle() { return nullptr; }
cast_to_rectangle() const86 const vsol_rectangle_2d *vsol_polygon_2d::cast_to_rectangle() const {
87   return nullptr;
88 }
89 
90 //***************************************************************************
91 // Access
92 //***************************************************************************
93 
94 //---------------------------------------------------------------------------
95 //: Return vertex `i'
96 // Require: valid_index(i)
97 //---------------------------------------------------------------------------
vertex(const int i) const98 vsol_point_2d_sptr vsol_polygon_2d::vertex(const int i) const
99 {
100   // require
101   assert(valid_index(i));
102 
103   return (*storage_)[i];
104 }
105 
106 //***************************************************************************
107 // Comparison
108 //***************************************************************************
109 
110 //---------------------------------------------------------------------------
111 //: Has `this' the same points than `other' in the same order ?
112 //---------------------------------------------------------------------------
operator ==(const vsol_polygon_2d & other) const113 bool vsol_polygon_2d::operator==(const vsol_polygon_2d &other) const
114 {
115   bool result = (this==&other);
116 
117   if (!result)
118   {
119     result = (storage_->size()==other.storage_->size());
120     if (result)
121     {
122       vsol_point_2d_sptr p=(*storage_)[0];
123 
124       unsigned int i=0;
125       for (result=false;i<storage_->size()&&!result;++i)
126         result = (*p==*(*other.storage_)[i]);
127       if (result)
128       {
129         for (unsigned int j=1;j<size()&&result;++i,++j)
130         {
131           if (i>=storage_->size()) i=0;
132           result = ((*storage_)[i]==(*storage_)[j]);
133         }
134       }
135     }
136   }
137   return result;
138 }
139 
140 //: spatial object equality
141 
operator ==(const vsol_spatial_object_2d & obj) const142 bool vsol_polygon_2d::operator==(const vsol_spatial_object_2d& obj) const
143 {
144   return
145     obj.cast_to_region() && obj.cast_to_region()->cast_to_polygon() &&
146     *this == *obj.cast_to_region()->cast_to_polygon();
147 }
148 
149 
150 //---------------------------------------------------------------------------
151 //: Compute the bounding box of `this'
152 //---------------------------------------------------------------------------
compute_bounding_box() const153 void vsol_polygon_2d::compute_bounding_box() const {
154   set_bounding_box((*storage_)[0]->x(), (*storage_)[0]->y());
155   for (unsigned int i=1;i<storage_->size();++i)
156     add_to_bounding_box((*storage_)[i]->x(), (*storage_)[i]->y());
157 }
158 
159 //---------------------------------------------------------------------------
160 //: Return the area of `this'
161 //---------------------------------------------------------------------------
area() const162 double vsol_polygon_2d::area() const {
163   double area = 0.0;
164   unsigned int last = storage_->size()-1;
165 
166   for (unsigned int i=0; i<last; ++i)
167     area += ((*storage_)[i]->x() * (*storage_)[i+1]->y())
168           - ((*storage_)[i+1]->x() * (*storage_)[i]->y());
169 
170   area += ((*storage_)[last]->x() * (*storage_)[0]->y())
171         - ((*storage_)[0]->x() * (*storage_)[last]->y());
172 
173   return std::abs(area / 2.0);
174 }
175 
176 //---------------------------------------------------------------------------
177 //: Return the centroid of `this'
178 //---------------------------------------------------------------------------
179 // The centroid is computed by using Green's theorem to compute the
180 // area-weighted 1st moments of the polygon.
181 //  Green's theorem relates the surface integral to the line integral around
182 //  the boundary as:
183 //     Int(surface) x dxdy = 0.5 * Int(boundary) x*x dy
184 //     Int(surface) y dxdy = 0.5 * Int(boundary) y*y dx
185 //  The centroid is given by
186 //     xc = Int(surface) x dxdy / Int(surface) dxdy  = Int(surface) x dxdy/area
187 //     yc = Int(surface) y dxdy / Int(surface) dxdy  = Int(surface) y dxdy/area
188 //
189 //  For a polygon: with vertices x[i], y[i]
190 //   0.5 * Int(boundary) x*x dy =
191 //   1/6 * Sum(i)( x[i+1] + x[i] ) * ( x[i] * y[i+1] - x[i+1] * y[i] )
192 //
193 //   0.5 * Int(boundary) y*y dx =
194 //   1/6 * Sum(i)( y[i+1] + y[i] ) * ( x[i] * y[i+1] - x[i+1] * y[i] )
195 //
196 //  In the case of degenerate polygons, where area == 0, return the average of
197 //  the vertex locations.
198 //
centroid() const199 vsol_point_2d_sptr vsol_polygon_2d::centroid() const {
200   unsigned int nverts = storage_->size();
201   assert(nverts>0);
202   double sx = 0, sy = 0;
203   double area = 0;
204    //fill in edge from last point to first point
205   vsol_point_2d_sptr pi = (*storage_)[nverts-1];
206   vsol_point_2d_sptr pi1 = (*storage_)[0];
207   double xi = pi->x(), yi = pi->y();
208   double xi1 = pi1->x(), yi1 = pi1->y();
209 
210   //for degenerate polygons
211   double xsum = xi, ysum = yi;
212 
213   double temp = xi*yi1 - xi1*yi;
214   area += temp;
215   sx += temp*(xi1 + xi);
216   sy += temp*(yi1 + yi);
217   for (unsigned int i=0; i<nverts-1; ++i)
218     {
219       pi = (*storage_)[i];
220       pi1 = (*storage_)[i+1];
221       xi = pi->x(), yi = pi->y();
222       xi1 = pi1->x(), yi1 = pi1->y();
223       temp = xi*yi1 - xi1*yi;
224       area += temp;
225       sx += temp*(xi1 + xi);
226       sy += temp*(yi1 + yi);
227       xsum += xi; ysum += yi;
228     }
229   area /= 2.0;
230   if(std::fabs(area)!=0.0)
231     {
232       double xc = sx/(6.0*area), yc = sy/(6.0*area);
233       return new vsol_point_2d(xc, yc);
234     }
235   return new vsol_point_2d(xsum/nverts, ysum/nverts);
236 }
237 
238 //---------------------------------------------------------------------------
239 //: Is `this' convex ?
240 // A polygon is convex if the direction of "turning" at every vertex is
241 // the same.  This is checked by calculating the cross product of two
242 // consecutive edges and verifying that these all have the same sign.
243 //---------------------------------------------------------------------------
is_convex() const244 bool vsol_polygon_2d::is_convex() const {
245   if (storage_->size() == 3)
246     return true; // A triangle is always convex
247 
248   // First find a non-zero cross product.  This is certainly present,
249   // unless the polygon collapses to a line segment.
250   // Note that cross-product=0 means that two edges are parallel, which
251   // is perfectly valid, but the other "turnings" should still all be in
252   // the same direction.  An earlier implementation allowed for turning
253   // in the other direction after a cross-product=0.
254 
255   double n = 0.0;
256   for (unsigned int i = 0; i < storage_->size(); ++i) {
257     int j = (i > 1) ? i - 2 : i - 2 + storage_->size();
258     int k = (i > 0) ? i - 1 : i - 1 + storage_->size();
259     vsol_point_2d_sptr p0 = (*storage_)[k];
260     vsol_point_2d_sptr p1 = (*storage_)[j];
261     vsol_point_2d_sptr p2 = (*storage_)[i];
262     vgl_vector_2d<double> v1 = p0->to_vector(*p1);
263     vgl_vector_2d<double> v2 = p1->to_vector(*p2);
264     n = cross_product(v1, v2);
265     if (n != 0.0)
266       break;
267   }
268   if (n == 0.0)
269     return true;
270 
271   for (unsigned int i = 0; i < storage_->size(); ++i) {
272     int j = (i > 1) ? i - 2 : i - 2 + storage_->size();
273     int k = (i > 0) ? i - 1 : i - 1 + storage_->size();
274     vsol_point_2d_sptr p0 = (*storage_)[k];
275     vsol_point_2d_sptr p1 = (*storage_)[j];
276     vsol_point_2d_sptr p2 = (*storage_)[i];
277     vgl_vector_2d<double> v1 = p0->to_vector(*p1);
278     vgl_vector_2d<double> v2 = p1->to_vector(*p2);
279     double n2 = cross_product(v1, v2);
280     if (n2 * n < 0)
281       return false; // turns in the other direction
282   }
283   return true;
284 }
285 
286 //----------------------------------------------------------------
287 // ================   Binary I/O Methods ========================
288 //----------------------------------------------------------------
289 
290 //: Binary save self to stream.
b_write(vsl_b_ostream & os) const291 void vsol_polygon_2d::b_write(vsl_b_ostream &os) const
292 {
293   vsl_b_write(os, version());
294   vsol_spatial_object_2d::b_write(os);
295   if (!storage_)
296     vsl_b_write(os, false); // Indicate null pointer stored
297   else
298   {
299     vsl_b_write(os, true); // Indicate non-null pointer stored
300     vsl_b_write(os, *storage_);
301   }
302 }
303 
304 //: Binary load self from stream (not typically used)
b_read(vsl_b_istream & is)305 void vsol_polygon_2d::b_read(vsl_b_istream &is)
306 {
307   short ver;
308   vsl_b_read(is, ver);
309   switch (ver)
310   {
311    case 1:
312     vsol_spatial_object_2d::b_read(is);
313 
314     delete storage_;
315     storage_ = new std::vector<vsol_point_2d_sptr>();
316     bool null_ptr;
317     vsl_b_read(is, null_ptr);
318     if (!null_ptr)
319       return;
320     vsl_b_read(is, *storage_);
321     break;
322    default:
323     std::cerr << "vsol_polygon_2d: unknown I/O version " << ver << '\n';
324   }
325 }
326 
327 //: Return IO version number;
version() const328 short vsol_polygon_2d::version() const
329 {
330   return 1;
331 }
332 
333 //: Print an ascii summary to the stream
print_summary(std::ostream & os) const334 void vsol_polygon_2d::print_summary(std::ostream &os) const
335 {
336   os << *this;
337 }
338 
339 //***************************************************************************
340 // Implementation
341 //***************************************************************************
342 
343 //---------------------------------------------------------------------------
344 //: Default constructor.
345 //---------------------------------------------------------------------------
vsol_polygon_2d()346 vsol_polygon_2d::vsol_polygon_2d() {
347   storage_=new std::vector<vsol_point_2d_sptr>();
348 }
349 
valid_vertices(const std::vector<vsol_point_2d_sptr>) const350 bool vsol_polygon_2d::valid_vertices(const std::vector<vsol_point_2d_sptr> ) const
351 {
352   return true;
353 }
354 
355 
356 //: Binary save vsol_polygon_2d to stream.
357 void
vsl_b_write(vsl_b_ostream & os,const vsol_polygon_2d * p)358 vsl_b_write(vsl_b_ostream &os, const vsol_polygon_2d* p)
359 {
360   if (p==nullptr) {
361     vsl_b_write(os, false); // Indicate null pointer stored
362   }
363   else{
364     vsl_b_write(os,true); // Indicate non-null pointer stored
365     p->b_write(os);
366   }
367 }
368 
369 
370 //: Binary load vsol_polygon_2d from stream.
371 void
vsl_b_read(vsl_b_istream & is,vsol_polygon_2d * & p)372 vsl_b_read(vsl_b_istream &is, vsol_polygon_2d* &p)
373 {
374   delete p;
375   bool not_null_ptr;
376   vsl_b_read(is, not_null_ptr);
377   if (not_null_ptr) {
378     p = new vsol_polygon_2d();
379     p->b_read(is);
380   }
381   else
382     p = nullptr;
383 }
384 
385 
describe(std::ostream & strm,int blanking) const386 inline void vsol_polygon_2d::describe(std::ostream &strm, int blanking) const
387 {
388   if (blanking < 0) blanking = 0; while (blanking--) strm << ' ';
389   if (size() == 0)
390     strm << "[null]";
391   else {
392     strm << "[Nverts=" << size()
393          << " Area=" << area();
394     for (unsigned int i=0; i<size(); ++i)
395       strm << " p" << i << ':' << *(vertex(i));
396     strm << ']';
397   }
398   strm << std::endl;
399 }
400