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