LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
Polygon2D.cxx
Go to the documentation of this file.
1 #include "Polygon2D.h"
2 
3 #include <iostream>
4 #include <math.h>
5 
6 //------------------------------------------------
7 float FindSlope(const std::pair<float, float>& p1, const std::pair<float, float>& p2)
8 {
9  float slope = (p2.second - p1.second) / (p2.first - p1.first);
10  return slope;
11 }
12 
13 //-------------------------------------------------------------------------
14 bool Clockwise(double Ax, double Ay, double Bx, double By, double Cx, double Cy)
15 {
16  return (Cy - Ay) * (Bx - Ax) > (By - Ay) * (Cx - Ax);
17 }
18 
19 //------------------------------------------------------------
20 bool SegmentOverlap(double Ax,
21  double Ay,
22  double Bx,
23  double By,
24  double Cx,
25  double Cy,
26  double Dx,
27  double Dy)
28 {
29 
30  bool overlap = ((Clockwise(Ax, Ay, Cx, Cy, Dx, Dy) != Clockwise(Bx, By, Cx, Cy, Dx, Dy)) and
31  (Clockwise(Ax, Ay, Bx, By, Cx, Cy) != Clockwise(Ax, Ay, Bx, By, Dx, Dy)));
32  return overlap;
33 }
34 
35 //---------------------------------------------------------------------------------
36 std::pair<float, float> GetIntersection(double Ax,
37  double Ay,
38  double Bx,
39  double By,
40  double Cx,
41  double Cy,
42  double Dx,
43  double Dy)
44 {
45 
46  //get equations for two lines
47  // [Ax,Ay]<--->[Bx,By] : y = s1*x+c1
48  // [Cx,Cy]<--->[Dx,Dy] : y = s2*x+c2
49  double s1 = (By - Ay) / (Bx - Ax);
50  double s2 = (Dy - Cy) / (Dx - Cx);
51  double c1 = By - s1 * Bx;
52  double c2 = Dy - s2 * Dx;
53 
54  double Xintersection = (c2 - c1) / (s2 - s1);
55  double Yintersection = s1 * Xintersection + c1;
56  std::pair<float, float> intersection;
57  intersection = std::make_pair(Xintersection, Yintersection);
58 
59  return intersection;
60 }
61 
62 //------------------------------------------------------------------
63 Polygon2D::Polygon2D(const Polygon2D& poly1, const Polygon2D& poly2)
64 {
65 
66  //figure out if the two polygons overlap at all
67  if (!(poly1.PolyOverlap(poly2))) {
68  std::vector<std::pair<float, float>> nullpoint;
69  vertices = nullpoint;
70  return;
71  }
72 
73  //The overlap polygon is made up by:
74  //1) all points of poly1 in poly2
75  //2) all points of poly2 in poly1
76  //3) all intersection points between segments
77 
78  //make a new set of points and add points
79  //as listed above, if found.
80  std::vector<std::pair<float, float>> IntersectionPoints;
81  //1)
82  for (unsigned int p1 = 0; p1 < poly1.Size(); p1++) {
83  if (poly2.PointInside(poly1.Point(p1))) { IntersectionPoints.push_back(poly1.Point(p1)); }
84  }
85  //2)
86  for (unsigned int p2 = 0; p2 < poly2.Size(); p2++) {
87  if (poly1.PointInside(poly2.Point(p2))) { IntersectionPoints.push_back(poly2.Point(p2)); }
88  }
89  //3)
90  //FIND SEGMENT INTERSECTIONS
91  for (unsigned int i = 0; i < poly1.Size(); i++) {
92  for (unsigned int j = 0; j < poly2.Size(); j++) {
93  if (SegmentOverlap(poly1.Point(i).first,
94  poly1.Point(i).second,
95  poly1.Point(i + 1).first,
96  poly1.Point(i + 1).second,
97  poly2.Point(j).first,
98  poly2.Point(j).second,
99  poly2.Point(j + 1).first,
100  poly2.Point(j + 1).second))
101  //segments overlap...add intersection to list
102  IntersectionPoints.push_back(GetIntersection(poly1.Point(i).first,
103  poly1.Point(i).second,
104  poly1.Point(i + 1).first,
105  poly1.Point(i + 1).second,
106  poly2.Point(j).first,
107  poly2.Point(j).second,
108  poly2.Point(j + 1).first,
109  poly2.Point(j + 1).second));
110  } //for all segments in poly2
111  } //for all segments in poly1
112 
113  vertices = IntersectionPoints;
114  return;
115 }
116 
117 //---------------------------
118 float Polygon2D::Area() const
119 {
120  //how? here:
121  //http://www.mathsisfun.com/geometry/area-irregular-polygons.html
122  float area = 0;
123  for (unsigned int i = 0; i < vertices.size(); i++) {
124  if (i < (vertices.size() - 1))
125  area += (((vertices.at(i)).second) + ((vertices.at(i + 1)).second)) *
126  (((vertices.at(i)).first) - ((vertices.at(i + 1)).first)) * 0.5;
127  if (i == (vertices.size() - 1))
128  area += (((vertices.at(i)).second) + ((vertices.at(0)).second)) *
129  (((vertices.at(i)).first) - ((vertices.at(0)).first)) * 0.5;
130  }
131  if (area < 0.0) area = -area;
132  return area;
133 }
134 
135 //--------------------------------
136 float Polygon2D::Perimeter() const
137 {
138 
139  float perimeter = 0.;
140 
141  for (unsigned int i = 0; i < vertices.size(); i++) {
142  if (i < (vertices.size() - 1))
143  perimeter += ((vertices.at(i).second - vertices.at(i + 1).second) *
144  (vertices.at(i).second - vertices.at(i + 1).second) +
145  (vertices.at(i).first - vertices.at(i + 1).first) *
146  (vertices.at(i).first - vertices.at(i + 1).first));
147  if (i == (vertices.size() - 1))
148  perimeter += ((vertices.at(i).second - vertices.at(0).second) *
149  (vertices.at(i).second - vertices.at(0).second) +
150  (vertices.at(i).first - vertices.at(0).first) *
151  (vertices.at(i).first - vertices.at(0).first));
152  }
153 
154  return sqrt(perimeter);
155 }
156 
157 //------------------------------------------------------------------
158 const std::pair<float, float>& Polygon2D::Point(unsigned int p) const
159 {
160  //This function returns the vertex under consideration
161  //as a std::pair<float,float> Returns vertex for argument
162  //from 0 to N-1. For input N = number of sides then
163  //the first vertex is returned
164  if (p < vertices.size())
165  return vertices.at(p);
166  else if (p == vertices.size())
167  return vertices.at(0);
168  else {
169  std::cout << "Out of bounds of Polygon!" << std::endl;
170  return vertices.at(0);
171  }
172 }
173 
174 //------------------------------------------------------------------------
175 std::pair<float, float> Polygon2D::Project(const std::pair<float, float>& p, float theta) const
176 {
177 
178  std::pair<float, float> range(10000, 0);
179  std::pair<float, float> ptmp;
180 
181  for (unsigned int i = 0; i < vertices.size(); i++) {
182  //Translation
183  //translating each vertex so that origin is on first vertex on polygon's edge being considered
184  ptmp = std::make_pair((vertices.at(i)).first - p.first, (vertices.at(i)).second - p.second);
185  //Rotation
186  //instead of rotating each (x,y) edge (slow) just find nex x-position which gives us information
187  //on the projection of that vertex on the line we are considering
188  // +x direction is from vertex in consideration (vertex 'i' in loop) to next vertex
189  //now find the x-coordinate of that vertex after it is rotated such that edge is now + x axis
190  float xnew = (ptmp.first) * cos(theta) + (ptmp.second) * sin(theta);
191  //finally calculate range of projection on x-axis: look at every x position and compare it to range
192  if (xnew < range.first) range.first = xnew;
193  if (xnew > range.second) range.second = xnew;
194  }
195  return range;
196 }
197 
198 //---------------------------------------------------------------
199 bool Polygon2D::Overlap(float slope,
200  const Polygon2D& poly2,
201  const std::pair<float, float>& origin) const
202 {
203  //translate and rotate both polygons
204  float theta = tan(slope);
205  //here we translate origin, rotate and find x-coordinates and find range of projection on edge line
206  std::pair<float, float> range1 = this->Project(origin, theta);
207  std::pair<float, float> range2 = poly2.Project(origin, theta);
208  //std::cout << "range 1: " << range1.first << " " << range1.second << std::endl;
209  //std::cout << "range 2: " << range2.first << " " << range2.second << std::endl;
210  //if the two projections don't overlap --> no overlap!
211  if ((((range1.first <= range2.second) and (range1.first >= range2.first)) or
212  ((range1.second <= range2.second) and (range1.second >= range2.first))) or
213  (((range2.first <= range1.second) and (range2.first >= range1.first)) or
214  ((range2.second <= range1.second) and (range2.second >= range1.first))))
215  return true; //yes...they overlap
216  else
217  return false; //no....they do not overlap
218 }
219 
220 //-------------------------------------------------------
221 bool Polygon2D::PolyOverlap(const Polygon2D& poly2) const
222 {
223 
224  //start from first pair in vector then check all edges.
225  //edges are (0,1), (1,2), ..., (N,N-1) each pair a pair
226  //of vertexes
227  for (unsigned int i = 0; i < this->Size(); i++) { //loop over first polygon's vertices
228  //find projection line's slope
229  //line: y=ax+b --- slope is a variable
230  float slope;
231  slope = FindSlope(this->Point(i), this->Point(i + 1));
232  //if there is even one no-overlap
233  //need to exit and return no overlap!
234  if (!(this->Overlap(slope, poly2, this->Point(i)))) return false;
235  } //loop over first polygon vertices
236 
237  //do the exact same thing but reversing polygon role
238  for (unsigned int i = 0; i < poly2.Size(); i++) { //loop over first polygon
239  float slope;
240  slope = FindSlope(poly2.Point(i), poly2.Point(i + 1));
241  if (!(poly2.Overlap(slope, *this, poly2.Point(i)))) return false;
242  } //loop over second polygon vertices
243  return true;
244 }
245 
246 //---------------------------------------------------------------
248 {
249  //if contained in one another then they also overlap:
250  if ((this->Contained(poly2)) or (poly2.Contained(*this))) { return true; }
251  //loop over the two polygons checking wehther
252  //two segments ever intersect
253  for (unsigned int i = 0; i < this->Size(); i++) {
254  for (unsigned int j = 0; j < poly2.Size(); j++) {
255  if (SegmentOverlap(this->Point(i).first,
256  this->Point(i).second,
257  this->Point(i + 1).first,
258  this->Point(i + 1).second,
259  poly2.Point(j).first,
260  poly2.Point(j).second,
261  poly2.Point(j + 1).first,
262  poly2.Point(j + 1).second)) {
263  return true;
264  }
265  }
266  }
267  return false;
268 }
269 
270 //--------------------------------------------------------------------
271 bool Polygon2D::PointInside(const std::pair<float, float>& point) const
272 {
273 
274  //any ray originating at point will cross polygon
275  //even number of times if point outside
276  //odd number of times if point inside
277  int intersections = 0;
278  for (unsigned int i = 0; i < this->Size(); i++) {
279  if (SegmentOverlap(this->Point(i).first,
280  this->Point(i).second,
281  this->Point(i + 1).first,
282  this->Point(i + 1).second,
283  10000.0,
284  10000.0,
285  point.first,
286  point.second))
287  intersections += 1;
288  }
289  if ((intersections % 2) == 0)
290  return false;
291  else
292  return true;
293 }
294 
295 //-----------------------------------------------------
296 bool Polygon2D::Contained(const Polygon2D& poly2) const
297 {
298 
299  //loop over poly2 checking wehther
300  //points of poly2 all inside poly1
301  for (unsigned int i = 0; i < poly2.Size(); i++) {
302  if (!(this->PointInside(poly2.Point(i)))) return false;
303  }
304 
305  return true;
306 }
307 
308 //-------------------------------
310 {
311 
312  //loop over edges
313  for (unsigned int i = 0; i < vertices.size() - 1; i++) {
314  double Ax = vertices.at(i).first;
315  double Ay = vertices.at(i).second;
316  double Bx = vertices.at(i + 1).first;
317  double By = vertices.at(i + 1).second;
318  //loop over edges that have not been checked yet
319  for (unsigned int j = i + 2; j < vertices.size() - 1; j++) {
320  //avoid consecutive segments
321  if (vertices.at(i) == vertices.at(j + 1))
322  continue;
323  else {
324  double Cx = vertices.at(j).first;
325  double Cy = vertices.at(j).second;
326  double Dx = vertices.at(j + 1).first;
327  double Dy = vertices.at(j + 1).second;
328 
329  if (SegmentOverlap(Ax, Ay, Bx, By, Cx, Cy, Dx, Dy)) {
330  std::pair<float, float> tmp = vertices.at(i + 1);
331  vertices.at(i + 1) = vertices.at(j);
332  vertices.at(j) = tmp;
333  //swapped polygon, now do recursion to make sure
334  this->UntanglePolygon();
335  } //if crossing
336  }
337  } //second loop
338  } //first loop
339 }
float Area() const
Definition: Polygon2D.cxx:118
2D polygon object
std::pair< float, float > Project(const std::pair< float, float > &, float) const
Definition: Polygon2D.cxx:175
bool Contained(const Polygon2D &poly2) const
Definition: Polygon2D.cxx:296
const std::pair< float, float > & Point(unsigned int p) const
Definition: Polygon2D.cxx:158
Polygon2D()
Definition: Polygon2D.h:38
Float_t tmp
Definition: plot.C:35
unsigned int Size() const
Create Intersection Polygon.
Definition: Polygon2D.h:41
std::vector< std::pair< float, float > > vertices
Definition: Polygon2D.h:35
bool Clockwise(double Ax, double Ay, double Bx, double By, double Cx, double Cy)
Definition: Polygon2D.cxx:14
float Perimeter() const
Definition: Polygon2D.cxx:136
std::pair< float, float > GetIntersection(double Ax, double Ay, double Bx, double By, double Cx, double Cy, double Dx, double Dy)
Definition: Polygon2D.cxx:36
bool PolyOverlapSegments(const Polygon2D &poly2) const
Definition: Polygon2D.cxx:247
TCanvas * c1
Definition: plotHisto.C:7
TCanvas * c2
Definition: plot_hist.C:75
bool SegmentOverlap(double Ax, double Ay, double Bx, double By, double Cx, double Cy, double Dx, double Dy)
Definition: Polygon2D.cxx:20
bool Overlap(float slope, const Polygon2D &poly2, const std::pair< float, float > &origin) const
Definition: Polygon2D.cxx:199
float FindSlope(const std::pair< float, float > &p1, const std::pair< float, float > &p2)
Definition: Polygon2D.cxx:7
bool PointInside(const std::pair< float, float > &point) const
Definition: Polygon2D.cxx:271
second_as<> second
Type of time stored in seconds, in double precision.
Definition: spacetime.h:82
bool PolyOverlap(const Polygon2D &poly2) const
Definition: Polygon2D.cxx:221
void UntanglePolygon()
check if poly2 is inside poly1
Definition: Polygon2D.cxx:309
constexpr Point origin()
Returns a origin position with a point of the specified type.
Definition: geo_vectors.h:229