Polygon.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5  *
6  * ArmarX is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * ArmarX is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * @package
19  * @author
20  * @date
21  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22  * GNU General Public License
23  */
24 #include "Polygon.h"
25 
27 
29 {
30 
31  //******************************************************************************************************************
32  // Basic tools
33  //******************************************************************************************************************
34 
35  // Sorts the points in the array inout by their X-coordinate (descending)
36  void
37  SortByX(Vec3d* inout, int arraylength)
38  {
39  Vec3d temp;
40  //bool newmax;
41  int i, j;
42 
43  for (i = 0; i < arraylength; i++)
44  {
45  for (j = i + 1; j < arraylength;
46  j++) // evtl schneller: erst max-index suchen, nur am ende tauschen
47  {
48  // oder: j von oben nach unten laufen lassen
49  if (inout[j].x > inout[i].x)
50  {
51  temp = inout[j];
52  inout[j] = inout[i];
53  inout[i] = temp;
54  }
55  }
56  }
57  }
58 
59  // Sorts the points in the array inout by their Y-coordinate (descending)
60  void
61  SortByY(Vec3d* inout, int arraylength)
62  {
63  Vec3d temp;
64  //bool newmax;
65  int i, j;
66 
67  for (i = 0; i < arraylength; i++)
68  {
69  for (j = i + 1; j < arraylength; j++)
70  {
71  if (inout[j].y > inout[i].y)
72  {
73  temp = inout[j];
74  inout[j] = inout[i];
75  inout[i] = temp;
76  }
77  }
78  }
79  }
80 
81  // returns true if line sequence definded by three points makes a turn to the left
82  bool
83  LeftTurn(Vec3d p1, Vec3d p2, Vec3d p3)
84  {
85  return (p2.x - p1.x) * (p3.y - p2.y) - (p3.x - p2.x) * (p2.y - p1.y) >= 0;
86  }
87 
88  // returns true if line sequence definded by three points makes a turn to the right
89  bool
90  RightTurn(Vec3d p1, Vec3d p2, Vec3d p3)
91  {
92  return (p2.x - p1.x) * (p3.y - p2.y) - (p3.x - p2.x) * (p2.y - p1.y) <= 0;
93  }
94 
95  // returns true if Point lies on the right side of the line defined by linePoint1 and linePoint2 (2D)
96  bool
98  {
99  return (Point.y - linePoint1.y) * (linePoint2.x - linePoint1.x) -
100  (Point.x - linePoint1.x) * (linePoint2.y - linePoint1.y) <
101  0;
102  }
103 
104  // Returns true if it is possible that the two polygons intersect
105  bool
107  {
108  return ((pol1->maxX > pol2->minX) && (pol2->maxX > pol1->minX) &&
109  (pol1->maxY > pol2->minY) && (pol2->maxY > pol1->minY));
110  }
111 
112  //******************************************************************************************************************
113  // Calculate the convex hull of polygons
114  //******************************************************************************************************************
115 
116  // Analog zu Sanders-VL Algorithmentechnik, Folien 16 vom 12.02.2008, S.28-32.
117  // Calculates the convex hull of the points in "in", the left part of the hull is stored in hull_left,
118  // the right part in hull_right. Both start with the lowest point, then the highest point, then the
119  // points of the respective hull descending by y until the lowest point (again).
120  // hull_left, hull_right, temp1 and temp2 have to be of size (max number of corners of a polygon) + 1
121  void
123  int num_all_points,
124  Vec3d* hull_left,
125  int* num_hull_points_left,
126  Vec3d* hull_right,
127  int* num_hull_points_right,
128  Vec3d* temp1,
129  Vec3d* temp2)
130  {
131  int left_points_counter, right_points_counter;
132 
133  for (int i = 0; i < num_all_points; i++)
134  {
135  temp1[i] = in[i];
136  }
137 
138  SortByY(temp1, num_all_points);
139 
140  hull_left[0] = temp1[num_all_points - 1];
141  hull_left[1] = temp1[0];
142  hull_right[0] = temp1[num_all_points - 1];
143  hull_right[1] = temp1[0];
144  float divided_x_dif =
145  (temp1[0].x - temp1[num_all_points - 1].x) / (temp1[0].y - temp1[num_all_points - 1].y);
146 
147 
148  // Divide into points on the left and on the right of the line from highest to lowest point.
149  // Left part is in the first part of the array, in descending order of y-values, right part
150  // is in the upper part of the array in (from the end) descending order of y-values
151  left_points_counter = 0;
152  right_points_counter = 0;
153  for (int i = 1; i < num_all_points - 1; i++)
154  {
155  if (temp1[i].x < temp1[0].x + (temp1[i].y - temp1[0].y) * divided_x_dif)
156  {
157  temp2[left_points_counter] = temp1[i];
158  left_points_counter++;
159  }
160  else
161  {
162  temp2[num_all_points - 1 - right_points_counter] = temp1[i];
163  right_points_counter++;
164  }
165  }
166  // add lowest point
167  temp2[left_points_counter] = temp1[num_all_points - 1];
168  left_points_counter++;
169  temp2[num_all_points - 1 - right_points_counter] = temp1[num_all_points - 1];
170  right_points_counter++;
171 
172 
173  // left part
174  int hull_ind_l = 2;
175  hull_left[2] = temp2[0];
176  for (int i = 1; i < left_points_counter; i++)
177  {
178  while (RightTurn(hull_left[hull_ind_l - 1], hull_left[hull_ind_l], temp2[i]))
179  {
180  hull_ind_l--;
181  }
182  hull_ind_l++;
183  hull_left[hull_ind_l] = temp2[i];
184  }
185  *num_hull_points_left = hull_ind_l + 1;
186 
187 
188  //right part
189  int hull_ind_r = 2;
190  hull_right[2] = temp2[num_all_points - 1];
191  for (int i = 2; i <= right_points_counter; i++)
192  {
193  while (LeftTurn(
194  hull_right[hull_ind_r - 1], hull_right[hull_ind_r], temp2[num_all_points - i]))
195  {
196  hull_ind_r--;
197  }
198  hull_ind_r++;
199  hull_right[hull_ind_r] = temp2[num_all_points - i];
200  }
201  *num_hull_points_right = hull_ind_r + 1;
202  }
203 
204  void
206  int num_all_points,
207  Vec3d* hull_left,
208  int* num_hull_points_left,
209  Vec3d* hull_right,
210  int* num_hull_points_right)
211  {
212  Vec3d* temp1 = new Vec3d[num_all_points + 1];
213  Vec3d* temp2 = new Vec3d[num_all_points + 1];
214  CalcConvexHull(in,
215  num_all_points,
216  hull_left,
217  num_hull_points_left,
218  hull_right,
219  num_hull_points_right,
220  temp1,
221  temp2);
222  }
223 
224  // interface to create the convex polygon pol from the points in the array in
225  void
226  CalcConvexHull(Vec3d* in, int num_all_points, Polygon* pol, Vec3d* temp1, Vec3d* temp2)
227  {
228  int i, j;
229 
230  CalcConvexHull(in,
231  num_all_points,
232  (Vec3d*)&pol->hullLeft,
233  &pol->nCornersLeft,
234  (Vec3d*)&pol->hullRight,
235  &pol->nCornersRight,
236  temp1,
237  temp2);
238 
239  // merge left and right part of the hull with corners ordered by y descending
240  pol->hull[0] = pol->hullLeft[1]; // first elem = highest point
241  pol->hull[0].z = 3;
242  int ind_l = 2;
243  int ind_r = 2;
244  int ind_h = 1;
245  while (ind_l < pol->nCornersLeft - 1 && ind_r < pol->nCornersRight - 1)
246  {
247  if (pol->hullLeft[ind_l].y > pol->hullRight[ind_r].y)
248  {
249  pol->hull[ind_h] = pol->hullLeft[ind_l];
250  pol->hull[ind_h].z = 1;
251  ind_l++;
252  }
253  else
254  {
255  pol->hull[ind_h] = pol->hullRight[ind_r];
256  pol->hull[ind_h].z = 2;
257  ind_r++;
258  }
259  ind_h++;
260  }
261  // now get the elements which rest in the left or the right part
262  while (ind_l < pol->nCornersLeft - 1)
263  {
264  pol->hull[ind_h] = pol->hullLeft[ind_l];
265  pol->hull[ind_h].z = 1;
266  ind_l++;
267  ind_h++;
268  }
269  while (ind_r < pol->nCornersRight - 1)
270  {
271  pol->hull[ind_h] = pol->hullRight[ind_r];
272  pol->hull[ind_h].z = 2;
273  ind_r++;
274  ind_h++;
275  }
276 
277  pol->nCorners = pol->nCornersRight + pol->nCornersLeft - 4;
278  pol->hull[pol->nCorners - 1] = pol->hullLeft[0]; // last elem = lowest point
279  pol->hull[pol->nCorners - 1].z = 3;
280 
281 
282  // calculate the hull with the corners ordered in clockwise sense
283  i = 0;
284  for (j = 1; j < pol->nCornersRight - 1; j++, i++)
285  {
286  pol->hullCircle[i] = pol->hullRight[j];
287  }
288  pol->hullCircle[i] = pol->hullRight[0];
289  i++;
290  for (j = pol->nCornersLeft - 2; j > 1; j--, i++)
291  {
292  pol->hullCircle[i] = pol->hullLeft[j];
293  }
294  pol->hullCircle[i] = pol->hullRight[1];
295 
296 
297  // calculate the coordinates for the enveloping rectangle
298  pol->minY = pol->hull[pol->nCorners - 1].y;
299  pol->maxY = pol->hull[0].y;
300  pol->minX = pol->hull[0].x;
301  for (i = 2; i <= pol->nCornersLeft; i++)
302  if (pol->hullLeft[i].x < pol->minX)
303  {
304  pol->minX = pol->hullLeft[i].x;
305  }
306  pol->maxX = pol->hull[0].x;
307  for (i = 2; i <= pol->nCornersRight; i++)
308  if (pol->hullRight[i].x > pol->maxX)
309  {
310  pol->maxX = pol->hullRight[i].x;
311  }
312  }
313 
314  void
315  CalcConvexHull(Vec3d* in, int num_all_points, Polygon* pol)
316  {
317  Vec3d* temp1 = new Vec3d[num_all_points + 1];
318  Vec3d* temp2 = new Vec3d[num_all_points + 1];
319  CalcConvexHull(in, num_all_points, pol, temp1, temp2);
320  }
321 
322  // interface to create the convex polygon pol from the points already in pol->hull
323  void
324  CalcConvexHull(Polygon* pol, Vec3d* temp1, Vec3d* temp2)
325  {
326  CalcConvexHull((Vec3d*)&pol->hull, pol->nCorners, pol, temp1, temp2);
327  }
328 
329  void
331  {
332  Vec3d* temp1 = new Vec3d[pol->nCorners + 1];
333  Vec3d* temp2 = new Vec3d[pol->nCorners + 1];
334  CalcConvexHull(pol, temp1, temp2);
335  }
336 
337  // creates a convex polygon from the points in hullpoints, assuming that they all belong to the
338  // convex hull
339  void
340  CreateConvexPolygonFromHullPoints(Vec3d* hullpoints, int nPoints, Polygon* pol)
341  {
342  int left_points_counter, right_points_counter;
343 
344  SortByY(hullpoints, nPoints);
345 
346  pol->hullLeft[0] = hullpoints[nPoints - 1];
347  pol->hullLeft[1] = hullpoints[0];
348  pol->hullRight[0] = hullpoints[nPoints - 1];
349  pol->hullRight[1] = hullpoints[0];
350  float divided_x_dif = (hullpoints[0].x - hullpoints[nPoints - 1].x) /
351  (hullpoints[0].y - hullpoints[nPoints - 1].y);
352 
353  pol->hull[0].x = hullpoints[0].x;
354  pol->hull[0].y = hullpoints[0].y;
355  pol->hull[0].z = 3;
356  pol->hull[nPoints - 1].x = hullpoints[nPoints - 1].x;
357  pol->hull[nPoints - 1].y = hullpoints[nPoints - 1].y;
358  pol->hull[nPoints - 1].z = 3;
359 
360  left_points_counter = 2;
361  right_points_counter = 2;
362  for (int i = 1; i < nPoints - 1; i++)
363  {
364  pol->hull[i].x = hullpoints[i].x;
365  pol->hull[i].y = hullpoints[i].y;
366  if (hullpoints[i].x <
367  hullpoints[0].x + (hullpoints[i].y - hullpoints[0].y) * divided_x_dif)
368  {
369  pol->hullLeft[left_points_counter] = hullpoints[i];
370  pol->hull[i].z = 1;
371  left_points_counter++;
372  }
373  else
374  {
375  pol->hullRight[right_points_counter] = hullpoints[i];
376  pol->hull[i].z = 2;
377  right_points_counter++;
378  }
379  }
380 
381  pol->hullLeft[left_points_counter] = hullpoints[nPoints - 1];
382  pol->hullRight[right_points_counter] = hullpoints[nPoints - 1];
383 
384  pol->nCorners = nPoints;
385  pol->nCornersLeft = left_points_counter + 1;
386  pol->nCornersRight = right_points_counter + 1;
387 
388  // calculate the hull with the corners ordered in clockwise sense
389  int i = 0;
390  for (int j = 1; j < pol->nCornersRight - 1; j++, i++)
391  {
392  pol->hullCircle[i] = pol->hullRight[j];
393  }
394  pol->hullCircle[i] = pol->hullRight[0];
395  i++;
396  for (int j = pol->nCornersLeft - 2; j > 1; j--, i++)
397  {
398  pol->hullCircle[i] = pol->hullLeft[j];
399  }
400  pol->hullCircle[i] = pol->hullRight[1];
401 
402 
403  // calculate the coordinates for the enveloping rectangle
404  pol->minY = pol->hull[pol->nCorners - 1].y;
405  pol->maxY = pol->hull[0].y;
406  pol->minX = pol->hull[0].x;
407  for (int i = 2; i <= pol->nCornersLeft; i++)
408  if (pol->hullLeft[i].x < pol->minX)
409  {
410  pol->minX = pol->hullLeft[i].x;
411  }
412  pol->maxX = pol->hull[0].x;
413  for (int i = 2; i <= pol->nCornersRight; i++)
414  if (pol->hullRight[i].x > pol->maxX)
415  {
416  pol->maxX = pol->hullRight[i].x;
417  }
418  }
419 
420  //******************************************************************************************************************
421  // Calculate the intersection polygon of two convex polygons
422  //******************************************************************************************************************
423 
424  // returns the convex polygon that is the intersection polygon of p1 and p2. pointAccu and boolTable have to
425  // be of size 2*(maximal number of points in a normal polygon), clockwiseHullPoly1/2 of size (maximal number
426  // of points in a normal polygon)+1
427  void
429  Polygon* p2,
430  Polygon* pInter,
431  Vec3d* pointAccu,
432  bool* boolTable,
433  Vec3d* clockwiseHullPoly1,
434  Vec3d* clockwiseHullPoly2)
435  {
436  int pointcount = 0;
437  int i, j;
438 
439  //*******************************************************************
440  // Get corners of polygon 1 that lie inside polygon 2
441  //
442  // The line segments are traversed in clockwise order. A point lies
443  // inside the convex polygon iff it is on the right side of every
444  // line segment.
445  //*******************************************************************
446 
447  // boolTable contains booleans which indicate if point i is inside the polygon
448  for (j = 0; j < p1->nCorners; j++)
449  {
450  boolTable[j] = true;
451  }
452 
453  for (i = 0; i < p2->nCorners; i++)
454  for (j = 0; j < p1->nCorners; j++)
455  {
456  boolTable[j] &= PointIsOnTheRightSideOfTheLine(
457  p1->hull[j], p2->hullCircle[i], p2->hullCircle[i + 1]);
458  }
459 
460 
461  for (j = 0; j < p1->nCorners; j++)
462  if (boolTable[j] == true)
463  {
464  pointAccu[pointcount] = p1->hull[j];
465  pointcount++;
466  }
467 
468 
469  //*******************************************************************
470  // Get corners of polygon 2 that lie inside polygon 1
471  //*******************************************************************
472 
473  for (j = 0; j < p2->nCorners; j++)
474  {
475  boolTable[j] = true;
476  }
477 
478  for (i = 0; i < p1->nCorners; i++)
479  for (j = 0; j < p2->nCorners; j++)
480  {
481  boolTable[j] &= PointIsOnTheRightSideOfTheLine(
482  p2->hull[j], p1->hullCircle[i], p1->hullCircle[i + 1]);
483  }
484 
485 
486  for (j = 0; j < p2->nCorners; j++)
487  if (boolTable[j] == true)
488  {
489  pointAccu[pointcount] = p2->hull[j];
490  pointcount++;
491  }
492 
493 
494  // optim: hier abbruchkriterium, wenn pointcount=0 und zentren nicht sehr nah beieinander
495 
496 
497  //*******************************************************************
498  // Calculate intersections
499  //
500  // A line is defined as p1 + c*(p2-p1). Solving the two equations
501  // resulting from setting line1 = line2 gives the value of c for
502  // which the above term gives the intersection point. If c is
503  // in [0,1], the intersection lies on the line segment (p1,p2).
504  // An analogue criterion exists for the other line segment.
505  //*******************************************************************
506 
507  float x1, y1, x2, y2, x3, y3, x4, y4, c1, c2, denominator;
508 
509 
510  for (i = 0; i < p1->nCorners; i++)
511  {
512  x1 = p1->hullCircle[i].x;
513  y1 = p1->hullCircle[i].y;
514  x2 = p1->hullCircle[i + 1].x;
515  y2 = p1->hullCircle[i + 1].y;
516  for (j = 0; j < p2->nCorners; j++)
517  {
518  x3 = p2->hullCircle[j].x;
519  y3 = p2->hullCircle[j].y;
520  x4 = p2->hullCircle[j + 1].x;
521  y4 = p2->hullCircle[j + 1].y;
522  denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
523  c1 = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator;
524  c2 = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator;
525  if (0 <= c1 && 1 >= c1 && 0 <= c2 && 1 >= c2)
526  {
527  pointAccu[pointcount].x = x1 + c1 * (x2 - x1);
528  pointAccu[pointcount].y = y1 + c1 * (y2 - y1);
529  pointcount++;
530  }
531  }
532  }
533 
534  if (pointcount >= 3)
535  {
536  CreateConvexPolygonFromHullPoints(pointAccu, pointcount, pInter);
537  }
538  else
539  {
540  pInter->nCorners = 0;
541  }
542  }
543 
544  void
546  {
547  Vec3d pointAccu[2 * DSHT_MAX_POLYGON_CORNERS];
548  bool boolTable[2 * DSHT_MAX_POLYGON_CORNERS];
549  Vec3d clockwiseHullPoly1[DSHT_MAX_POLYGON_CORNERS + 1];
550  Vec3d clockwiseHullPoly2[DSHT_MAX_POLYGON_CORNERS + 1];
552  p1, p2, pInter, pointAccu, boolTable, clockwiseHullPoly1, clockwiseHullPoly2);
553  }
554 
555 } // namespace visionx::ConvexPolygonCalculations
DSHT_MAX_POLYGON_CORNERS
#define DSHT_MAX_POLYGON_CORNERS
Definition: HandLocalisationConstants.h:46
GfxTL::Vec3d
VectorXD< 3, double > Vec3d
Definition: VectorXD.h:737
visionx::ConvexPolygonCalculations::Polygon::hullLeft
Vec3d hullLeft[2 *DSHT_MAX_POLYGON_CORNERS+1]
Definition: Polygon.h:49
visionx::ConvexPolygonCalculations::LeftTurn
bool LeftTurn(Vec3d p1, Vec3d p2, Vec3d p3)
Definition: Polygon.cpp:83
visionx::ConvexPolygonCalculations::RightTurn
bool RightTurn(Vec3d p1, Vec3d p2, Vec3d p3)
Definition: Polygon.cpp:90
visionx::ConvexPolygonCalculations::GetPolygonIntersection
void GetPolygonIntersection(Polygon *p1, Polygon *p2, Polygon *pInter, Vec3d *pointAccu, bool *boolTable, Vec3d *clockwiseHullPoly1, Vec3d *clockwiseHullPoly2)
Definition: Polygon.cpp:428
visionx::ConvexPolygonCalculations::Polygon::hull
Vec3d hull[2 *DSHT_MAX_POLYGON_CORNERS]
Definition: Polygon.h:37
visionx::ConvexPolygonCalculations::Polygon::maxY
float maxY
Definition: Polygon.h:56
visionx::ConvexPolygonCalculations::Polygon::nCorners
int nCorners
Definition: Polygon.h:34
visionx::ConvexPolygonCalculations::SortByY
void SortByY(Vec3d *inout, int arraylength)
Definition: Polygon.cpp:61
visionx::ConvexPolygonCalculations::Polygon
Definition: Polygon.h:32
visionx::ConvexPolygonCalculations::CreateConvexPolygonFromHullPoints
void CreateConvexPolygonFromHullPoints(Vec3d *hullpoints, int nPoints, Polygon *pol)
Definition: Polygon.cpp:340
visionx::ConvexPolygonCalculations::Polygon::hullRight
Vec3d hullRight[2 *DSHT_MAX_POLYGON_CORNERS+1]
Definition: Polygon.h:52
Polygon.h
visionx::ConvexPolygonCalculations
Definition: Polygon.cpp:28
visionx::ConvexPolygonCalculations::PolygonsMightIntersect
bool PolygonsMightIntersect(Polygon *pol1, Polygon *pol2)
Definition: Polygon.cpp:106
visionx::ConvexPolygonCalculations::Polygon::nCornersLeft
int nCornersLeft
Definition: Polygon.h:48
visionx::ConvexPolygonCalculations::Polygon::maxX
float maxX
Definition: Polygon.h:56
Point
Definition: PointCloud.h:21
visionx::ConvexPolygonCalculations::SortByX
void SortByX(Vec3d *inout, int arraylength)
Definition: Polygon.cpp:37
visionx::ConvexPolygonCalculations::Polygon::minY
float minY
Definition: Polygon.h:56
visionx::ConvexPolygonCalculations::Polygon::nCornersRight
int nCornersRight
Definition: Polygon.h:51
visionx::ConvexPolygonCalculations::Polygon::hullCircle
Vec3d hullCircle[2 *DSHT_MAX_POLYGON_CORNERS+1]
Definition: Polygon.h:41
visionx::ConvexPolygonCalculations::Polygon::minX
float minX
Definition: Polygon.h:56
Logging.h
visionx::ConvexPolygonCalculations::CalcConvexHull
void CalcConvexHull(Vec3d *in, int num_all_points, Vec3d *hull_left, int *num_hull_points_left, Vec3d *hull_right, int *num_hull_points_right, Vec3d *temp1, Vec3d *temp2)
Definition: Polygon.cpp:122
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
visionx::ConvexPolygonCalculations::PointIsOnTheRightSideOfTheLine
bool PointIsOnTheRightSideOfTheLine(Vec3d Point, Vec3d linePoint1, Vec3d linePoint2)
Definition: Polygon.cpp:97