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