xmsgrid  1.0
geoms.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
7 //------------------------------------------------------------------------------
8 
9 // 1. Precompiled header
10 
11 // 2. My own header
12 #include <xmsgrid/geometry/geoms.h>
13 
14 // 3. Standard library headers
15 #include <cfloat>
16 #include <algorithm>
17 
18 // 4. External library headers
19 
20 // 5. Shared code headers
21 #include <xmscore/math/math.h> // GT_TOL, LT_TOL
22 #include <xmscore/misc/XmError.h>
23 #include <xmscore/points/pt.h> // Pt3d
24 #include <xmscore/stl/vector.h>
26 #include <xmscore/misc/xmstype.h> // XM_ZERO_TOL
28 #include <xmscore/misc/XmConst.h>
29 
30 // 6. Non-shared code headers
31 
32 //----- Namespace declaration --------------------------------------------------
33 
34 namespace xms
35 {
36 //----- Constants / Enumerations -----------------------------------------------
37 
38 //----- Forward declarations ---------------------------------------------------
39 
40 //----- External globals -------------------------------------------------------
41 
42 //----- Internal function prototypes -------------------------------------------
43 
44 namespace
45 {
46 //------------------------------------------------------------------------------
48 //------------------------------------------------------------------------------
49 bool isRightTurn(Turn_enum turn, bool includeCollinear)
50 {
51  if (includeCollinear)
52  return turn == TURN_RIGHT || turn == TURN_COLINEAR_180;
53  else
54  return turn == TURN_RIGHT;
55 } // isRightTurn
56 }
57 
58 //------------------------------------------------------------------------------
64 //------------------------------------------------------------------------------
65 bool gmPointInOrOnBox2d(const Pt3d& a_bMin, const Pt3d& a_bMax, const Pt3d& a_pt)
66 {
67  if (a_pt.x < a_bMin.x || a_pt.y < a_bMin.y || a_pt.x > a_bMax.x || a_pt.y > a_bMax.y)
68  return false;
69  return true;
70 } // gmBoxesOverlap2d
71 //------------------------------------------------------------------------------
78 //------------------------------------------------------------------------------
79 bool gmBoxesOverlap2d(const Pt3d& a_b1Min,
80  const Pt3d& a_b1Max,
81  const Pt3d& a_b2Min,
82  const Pt3d& a_b2Max)
83 {
84  if (a_b1Max.x < a_b2Min.x)
85  return false;
86  if (a_b1Min.x > a_b2Max.x)
87  return false;
88  if (a_b1Max.y < a_b2Min.y)
89  return false;
90  if (a_b1Min.y > a_b2Max.y)
91  return false;
92  return true;
93 } // gmBoxesOverlap2d
94 //------------------------------------------------------------------------------
104 //------------------------------------------------------------------------------
106  const Pt3d& p2,
107  const Pt3d& p3,
108  double* a,
109  double* b,
110  double* c,
111  double* d)
112 {
113  // call the other version
114  gmCalculateNormalizedPlaneCoefficients(&p1, &p2, &p3, a, b, c, d);
115 } // gmCalculateNormalizedPlaneCoefficients
116 //------------------------------------------------------------------------------
126 //------------------------------------------------------------------------------
128  const Pt3d* p2,
129  const Pt3d* p3,
130  double* a,
131  double* b,
132  double* c,
133  double* d)
134 {
135  double x1(p1->x), y1(p1->y), z1(p1->z);
136  double x2(p2->x), y2(p2->y), z2(p2->z);
137  double x3(p3->x), y3(p3->y), z3(p3->z);
138  *a = (y1 * (z2 - z3) + y2 * (z3 - z1) + y3 * (z1 - z2));
139  *b = (z1 * (x2 - x3) + z2 * (x3 - x1) + z3 * (x1 - x2));
140  *c = (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2));
141  double mag(sqrt((*a) * (*a) + (*b) * (*b) + (*c) * (*c)));
142  *a /= mag;
143  *b /= mag;
144  *c /= mag;
145  *d = -(*a) * x1 - (*b) * y1 - (*c) * z1;
146 } // gmCalculateNormalizedPlaneCoefficients
147 //------------------------------------------------------------------------------
152 //------------------------------------------------------------------------------
153 double gmMiddleZ(const VecPt3d& a_points)
154 {
155  // Get an average z value
156  double zmin = XM_DBL_HIGHEST;
157  double zmax = XM_DBL_LOWEST;
158  for (size_t i = 0; i < a_points.size(); ++i)
159  {
160  double z = a_points[i].z;
161  zmin = std::min(zmin, z);
162  zmax = std::max(zmax, z);
163  }
164  return (zmin + zmax) / 2.0;
165 } // gmMiddleZ
166 //------------------------------------------------------------------------------
171 //------------------------------------------------------------------------------
172 PtInOutOrOn_enum gmPtInCircumcircle(const Pt3d& pt, Pt3d circumcirclePts[3])
173 {
174  double xc, yc, r2;
175 
176  if (!gmCircumcircleWithTol(&circumcirclePts[0], &circumcirclePts[1], &circumcirclePts[2], &xc,
177  &yc, &r2, gmXyTol()))
178  {
179  return PT_ERROR;
180  }
181  /* compute distance from (xc,yc) to pt squared */
182  double delta = sqrt(r2) - sqrt(sqr(pt.x - xc) + sqr(pt.y - yc));
183  if (fabs(delta) > gmXyTol())
184  {
185  if (delta > gmXyTol())
186  {
187  return PT_IN;
188  }
189  else
190  {
191  return PT_OUT;
192  }
193  }
194  return PT_ON;
195 } // gmPtInCircumcircle
196 //------------------------------------------------------------------------------
201 //------------------------------------------------------------------------------
202 double gmXyDistanceSquared(const Pt3d& pt1, const Pt3d& pt2)
203 {
204  return (sqr(pt1.x - pt2.x) + sqr(pt1.y - pt2.y));
205 } // gmXyDistanceSqared
206 //------------------------------------------------------------------------------
217 //------------------------------------------------------------------------------
218 bool gmCircumcircleWithTol(const Pt3d* pt1,
219  const Pt3d* pt2,
220  const Pt3d* pt3,
221  double* xc,
222  double* yc,
223  double* r2,
224  double tol)
225 {
226  bool ok = true;
227  double det11, det12, det13, det21, det22, det23;
228  double determinate;
229  /* compute these */
230  det11 = pt1->x - pt2->x;
231  det12 = pt1->y - pt2->y;
232  det13 = det11 * (pt1->x + pt2->x) / 2.0 + det12 * (pt1->y + pt2->y) / 2.0;
233 
234  det21 = pt3->x - pt2->x;
235  det22 = pt3->y - pt2->y;
236  det23 = det21 * (pt3->x + pt2->x) / 2.0 + det22 * (pt3->y + pt2->y) / 2.0;
237  /* compute determinant */
238  determinate = det11 * det22 - det12 * det21;
239  /* zero determinate indicates collinear pts */
240  if (fabs(determinate) < tol)
241  {
242  ok = false;
243  determinate = tol;
244  /* the old subtri perturbed a vertex to
245  * give a non zero determinant as follows:
246 i = 0;
247 while (determinate == 0.0) {
248 i++;
249 Nx = ((double)i/1000.0)*(vtx1->y - vtx0->y);
250 Ny = ((double)i/1000.0)*(vtx0->x - vtx1->x);
251 x1new = vtx1->x + Nx;
252 y1new = vtx1->y + Ny;
253 det11 = x1new - vtx0->x;
254 det12 = y1new - vtx0->y;
255 det13 = det11*(x1new + vtx0->x)/2.0 + det12*(y1new + vtx0->y)/2.0;
256 determinate = det11 * det22 - det12 * det21;
257 }
258  * END OF COMMENTED CODE */
259  }
260  *xc = (det13 * det22 - det23 * det12) / determinate;
261  *yc = (det11 * det23 - det21 * det13) / determinate;
262  *r2 = sqr(pt1->x - *xc) + sqr(pt1->y - *yc);
263  return ok;
264 } // gmCircumcircleWithTol
265 //------------------------------------------------------------------------------
274 //------------------------------------------------------------------------------
275 int gmCartToBary(const Pt3d* cart, const Pt3d* orig, double coef[6], int dir, Pt3d* bary)
276 {
277  double x, y, z;
278  x = cart->x - orig->x;
279  y = cart->y - orig->y;
280  z = cart->z - orig->z;
281  /* get magnitudes of the plane normal */
282  switch (dir)
283  {
284  case (0):
285  bary->x = coef[0] * y + coef[1] * z + coef[2];
286  bary->y = coef[3] * y + coef[4] * z + coef[5];
287  bary->z = 1.0 - bary->x - bary->y;
288  break;
289  case (1):
290  bary->x = coef[0] * z + coef[1] * x + coef[2];
291  bary->y = coef[3] * z + coef[4] * x + coef[5];
292  bary->z = 1.0 - bary->x - bary->y;
293  break;
294  case (2):
295  bary->x = coef[0] * x + coef[1] * y + coef[2];
296  bary->y = coef[3] * x + coef[4] * y + coef[5];
297  bary->z = 1.0 - bary->x - bary->y;
298  break;
299  }
300  return (XM_SUCCESS);
301 } // gmCartToBary
302 //------------------------------------------------------------------------------
314 //------------------------------------------------------------------------------
315 int gmBaryPrepare(const Pt3d* p1,
316  const Pt3d* p2,
317  const Pt3d* p3,
318  const Pt3d* norm,
319  Pt3d* orig,
320  double coef[6],
321  int* dir,
322  bool flag)
323 {
324  double x1, x2, x3, y1, y2, y3, z1, z2, z3, sizeinv;
325  /* compute the direction */
326  x1 = fabs(norm->x);
327  y1 = fabs(norm->y);
328  z1 = fabs(norm->z);
329  if (x1 > y1 && x1 > z1)
330  *dir = 0;
331  else if (y1 > z1)
332  *dir = 1;
333  else
334  *dir = 2;
335  /* get the origin */
336  if (flag)
337  {
338  orig->x = Mmin(p1->x, Mmin(p2->x, p3->x));
339  orig->y = Mmin(p1->y, Mmin(p2->y, p3->y));
340  orig->z = Mmin(p1->z, Mmin(p2->z, p3->z));
341  }
342  /* compute the coefficients */
343  x1 = p1->x - orig->x;
344  y1 = p1->y - orig->y;
345  z1 = p1->z - orig->z;
346  x2 = p2->x - orig->x;
347  y2 = p2->y - orig->y;
348  z2 = p2->z - orig->z;
349  x3 = p3->x - orig->x;
350  y3 = p3->y - orig->y;
351  z3 = p3->z - orig->z;
352  switch (*dir)
353  {
354  case (0):
355  sizeinv = 1.0 / ((y2 - y3) * (z1 - z3) - (z2 - z3) * (y1 - y3));
356  coef[0] = (z3 - z2) * sizeinv;
357  coef[1] = (y2 - y3) * sizeinv;
358  coef[2] = (y3 * z2 - z3 * y2) * sizeinv;
359  coef[3] = (z1 - z3) * sizeinv;
360  coef[4] = (y3 - y1) * sizeinv;
361  coef[5] = (y1 * z3 - z1 * y3) * sizeinv;
362  break;
363  case (1):
364  sizeinv = 1.0 / ((z2 - z3) * (x1 - x3) - (x2 - x3) * (z1 - z3));
365  coef[0] = (x3 - x2) * sizeinv;
366  coef[1] = (z2 - z3) * sizeinv;
367  coef[2] = (z3 * x2 - x3 * z2) * sizeinv;
368  coef[3] = (x1 - x3) * sizeinv;
369  coef[4] = (z3 - z1) * sizeinv;
370  coef[5] = (z1 * x3 - x1 * z3) * sizeinv;
371  break;
372  case (2):
373  sizeinv = 1.0 / ((x2 - x3) * (y1 - y3) - (y2 - y3) * (x1 - x3));
374  coef[0] = (y3 - y2) * sizeinv;
375  coef[1] = (x2 - x3) * sizeinv;
376  coef[2] = (x3 * y2 - y3 * x2) * sizeinv;
377  coef[3] = (y1 - y3) * sizeinv;
378  coef[4] = (x3 - x1) * sizeinv;
379  coef[5] = (x1 * y3 - y1 * x3) * sizeinv;
380  break;
381  }
382  return (XM_SUCCESS);
383 } // gmBaryPrepare
384 //------------------------------------------------------------------------------
392 //------------------------------------------------------------------------------
393 bool gmColinearWithTol(const Pt3d& p1, const Pt3d& p2, const Pt3d& p3, const double tol)
394 {
395  if (gmOnLineWithTol(p1, p2, p3.x, p3.y, tol))
396  return true;
397  else if (gmOnLineWithTol(p2, p3, p1.x, p1.y, tol))
398  return true;
399  else if (gmOnLineWithTol(p3, p1, p2.x, p2.y, tol))
400  return true;
401  else
402  return false;
403 } // gmColinearWithTol
404 //------------------------------------------------------------------------------
419 //------------------------------------------------------------------------------
421  const Pt3d& one2,
422  const Pt3d& two1,
423  const Pt3d& two2,
424  double* xi /*=NULL*/,
425  double* yi /*=NULL*/,
426  double* zi1 /*=NULL*/,
427  double* zi2 /*=NULL*/,
428  double tol /*=0.0*/)
429 {
430  double minx1, minx2, miny1, miny2, maxx1, maxx2, maxy1, maxy2;
431  double dx1, dy1, dz1, dx2, dy2, dz2, lambda, mu, cross;
432  // do a trivial rejection
433  // RDJ - 4/20/2004 Do tests one at a time so if we fail on one we stop
434  minx1 = std::min(one1.x, one2.x);
435  maxx2 = std::max(two1.x, two2.x);
436  if (GT_TOL(minx1, maxx2, tol))
437  {
438  return false;
439  }
440  maxx1 = std::max(one1.x, one2.x);
441  minx2 = std::min(two1.x, two2.x);
442  if (LT_TOL(maxx1, minx2, tol))
443  {
444  return false;
445  }
446  miny1 = std::min(one1.y, one2.y);
447  maxy2 = std::max(two1.y, two2.y);
448  if (GT_TOL(miny1, maxy2, tol))
449  {
450  return false;
451  }
452  maxy1 = std::max(one1.y, one2.y);
453  miny2 = std::min(two1.y, two2.y);
454  if (LT_TOL(maxy1, miny2, tol))
455  {
456  return false;
457  }
458  // define the vectors
459  dx1 = one2.x - one1.x;
460  dy1 = one2.y - one1.y;
461  dz1 = one2.z - one1.z;
462  dx2 = two2.x - two1.x;
463  dy2 = two2.y - two1.y;
464  dz2 = two2.z - two1.z;
465  /* see if lines are parallel */
466  cross = (dx1 * dy2) -
467  (dy1 * dx2); // dy1/dx1 = dy2/dx2 lines have same slope
468  // This checks the line slopes. If equal then the lines are parallel or
469  // the same line. We assume they are parallel and exit.
470  // But really theta should be computed using vector magnitudes
471  if (EQ_TOL(cross, 0.0, tol))
472  return false;
473  // compute the value of lambda
474  lambda = (dy2 * (two1.x - one1.x) + dx2 * (one1.y - two1.y)) / cross;
475 
476  // There is some question as to what effect the tolerance should have on this
477  // function. It was decided that in the case where the segments do not
478  // intersect, but the minimum distance between the two segments is within
479  // tolerance, then the location of the minimum will be returned as the
480  // point of intersection.
481  // If the point of intersection is off the end of the first segment, then
482  // set it to be at the end and set the checkDistance flag.
483  bool checkDistance(false);
484  if (lambda < 0.0)
485  {
486  lambda = 0.0;
487  checkDistance = true;
488  }
489  else if (lambda > 1.0)
490  {
491  lambda = 1.0;
492  checkDistance = true;
493  }
494  // The intersection is inside of segment 1, so we need to check segment 2
495  // Compute mu from lambda and the two parametric segment equations
496  // two1 + mu (two2 - two1) = one1 + lambda ( one2 - one1)
497  // so
498  // mu = (one1 + lambda (one2-one1) - two1)/(two2-two1)
499  if (fabs(dx2) > fabs(dy2))
500  mu = (one1.x + lambda * dx1 - two1.x) / dx2;
501  else
502  mu = (one1.y + lambda * dy1 - two1.y) / dy2;
503 
504  // If the point of intersection is off the end of the second segment, then
505  // set it to be at the end and set the checkDistance flag.
506  if (mu < 0.0)
507  {
508  mu = 0.0;
509  checkDistance = true;
510  }
511  else if (mu > 1.0)
512  {
513  mu = 1.0;
514  checkDistance = true;
515  }
516  // if checkDistance flag is true check distance between mu/lambda
517  // positions (nearest points). If it is not within tolerance, return false.
518  Pt3d lambdapos = one1 + Pt3d(lambda * dx1, lambda * dy1, lambda * dz1);
519  Pt3d mupos = two1 + Pt3d(mu * dx2, mu * dy2, mu * dz2);
520  if (checkDistance)
521  {
522  if (!gmEqualPointsXY(lambdapos, mupos, tol))
523  {
524  return false;
525  }
526  }
527 
528  if (gmColinearWithTol(one1, one2, lambdapos, tol / 2) &&
529  gmColinearWithTol(two1, two2, lambdapos, tol / 2))
530  {
531  if (xi)
532  {
533  *xi = lambdapos.x;
534  }
535  if (yi)
536  {
537  *yi = lambdapos.y;
538  }
539  }
540  else
541  {
542  if (xi)
543  {
544  *xi = mupos.x;
545  }
546  if (yi)
547  {
548  *yi = mupos.y;
549  }
550  }
551  if (zi2)
552  *zi2 = mupos.z;
553  if (zi1)
554  *zi1 = lambdapos.z;
555  return true;
556 } // gmIntersectLineSegmentsWithTol
557 //------------------------------------------------------------------------------
563 //------------------------------------------------------------------------------
564 bool gmCounterClockwiseTri(const Pt3d& vtx0, const Pt3d& vtx1, const Pt3d& vtx2)
565 {
566  double triarea1 = trArea(vtx0, vtx1, vtx2);
567  return (triarea1 > 0.0);
568 } // gmCounterClockwiseTri
569 //------------------------------------------------------------------------------
578 //------------------------------------------------------------------------------
579 double gmCross2D(const double& dx1, const double& dy1, const double& dx2, const double& dy2)
580 {
581  return (dx1 * dy2) - (dx2 * dy1);
582 } // gmCross2D
583 //------------------------------------------------------------------------------
589 //------------------------------------------------------------------------------
590 double gmCross2D(const Pt3d& a_origin, const Pt3d& a_A, const Pt3d& a_B)
591 {
592  return (a_A.x - a_origin.x) * (a_B.y - a_origin.y) - (a_A.y - a_origin.y) * (a_B.x - a_origin.x);
593 } // gmCross2D
594 //------------------------------------------------------------------------------
602 //------------------------------------------------------------------------------
603 double gmAngleBetween2DVectors(double dxp, double dyp, double dxn, double dyn)
604 {
605  double magn, magp;
606 
607  magn = sqrt(sqr(dxn) + sqr(dyn));
608  magp = sqrt(sqr(dxp) + sqr(dyp));
609  return gmAngleBetween2DVectors(dxp, dyp, dxn, dyn, magn, magp);
610 } // gmAngleBetween2DVectors
611 //----- OVERLOAD ---------------------------------------------------------------
621 //----- OVERLOAD ---------------------------------------------------------------
622 double gmAngleBetween2DVectors(double dxp,
623  double dyp,
624  double dxn,
625  double dyn,
626  double a_magn,
627  double a_magp)
628 {
629  double theangle, cosign;
630 
631  if (a_magn == 0.0 || a_magp == 0.0)
632  return (0.0);
633  cosign = (dxn * dxp + dyn * dyp) / (a_magn * a_magp);
634  if (cosign > 1.0)
635  cosign = 1.0;
636  if (cosign < -1.0)
637  cosign = -1.0;
638  theangle = acos(cosign);
639  if (theangle == 0.0)
640  {
641  if ((dxn * dxp) + (dyn * dyp) < 0.0)
642  theangle = XM_PI;
643  }
644  else if (gmCross2D(dxp, dyp, dxn, dyn) < 0.0)
645  theangle = 2 * XM_PI - theangle;
646  return theangle;
647 } // gmAngleBetween2DVectors
648 //------------------------------------------------------------------------------
654 //------------------------------------------------------------------------------
655 double gmAngleBetweenEdges(const Pt3d& p1, const Pt3d& p2, const Pt3d& p3)
656 {
657  double dxp, dyp, dxn, dyn;
658  /* compute the vectors */
659  dxp = p1.x - p2.x;
660  dyp = p1.y - p2.y;
661  dxn = p3.x - p2.x;
662  dyn = p3.y - p2.y;
663  return gmAngleBetween2DVectors(dxp, dyp, dxn, dyn);
664 } // gmAngleBetweenEdges
665 //------------------------------------------------------------------------------
671 //------------------------------------------------------------------------------
672 double gmAngleBetweenEdges(const Pt2d& p1, const Pt2d& p2, const Pt2d& p3)
673 {
674  double dxp, dyp, dxn, dyn;
675  /* compute the vectors */
676  dxp = p1.x - p2.x;
677  dyp = p1.y - p2.y;
678  dxn = p3.x - p2.x;
679  dyn = p3.y - p2.y;
680  return gmAngleBetween2DVectors(dxp, dyp, dxn, dyn);
681 } // gmAngleBetweenEdges
682 //------------------------------------------------------------------------------
696 //------------------------------------------------------------------------------
697 double gmComputeDeviationInDirection(const Pt3d& a_p0, const Pt3d& a_p1, const Pt3d& a_p2)
698 {
699  double x1, y1, x2, y2, m, cosine_dev;
700  x1 = a_p1.x - a_p0.x;
701  y1 = a_p1.y - a_p0.y;
702  x2 = a_p2.x - a_p1.x;
703  y2 = a_p2.y - a_p1.y;
704  m = sqrt(x1 * x1 + y1 * y1) * sqrt(x2 * x2 + y2 * y2);
705  if (m > 0.0)
706  {
707  cosine_dev = Mmin((x1 * x2 + y1 * y2) / (m), 1.0);
708  cosine_dev = Mmax(cosine_dev, -1.0);
709  return acos(cosine_dev);
710  }
711  else
712  {
713  return XM_PI;
714  }
715 } // gmComputeDeviationInDirection
716 //------------------------------------------------------------------------------
731 //------------------------------------------------------------------------------
732 bool gmOnLineWithTol(const Pt3d& p1,
733  const Pt3d& p2,
734  const double x,
735  const double y,
736  const double tol)
737 {
738  // compute vector components
739  double dx = p2.x - p1.x;
740  double dy = p2.y - p1.y;
741  double mag = sqrt(sqr(dx) + sqr(dy));
742  // check for extremely small segment
743  if (mag <= tol)
744  return gmEqualPointsXY(p1.x, p1.y, x, y);
745  else
746  {
747  double a = -dy / mag;
748  double b = dx / mag;
749  double c = -a * p2.x - b * p2.y;
750  // compute distance from line to (x,y)
751  double d = a * x + b * y + c;
752  return fabs(d) <= tol;
753  }
754 } // gmOnLineWithTol
755 //------------------------------------------------------------------------------
766 //------------------------------------------------------------------------------
768  const Pt3d& a_pt2,
769  const double a_x,
770  const double a_y,
771  double a_tol)
772 {
773  if ((Mmin(a_pt1.x, a_pt2.x) - a_tol <= a_x && Mmax(a_pt1.x, a_pt2.x) + a_tol >= a_x) &&
774  (Mmin(a_pt1.y, a_pt2.y) - a_tol <= a_y && Mmax(a_pt1.y, a_pt2.y) + a_tol >= a_y))
775  return gmOnLineWithTol(a_pt1, a_pt2, a_x, a_y, a_tol) == true;
776  else
777  return false;
778 } // gmOnLineAndBetweenEndpointsWithTol
779 //------------------------------------------------------------------------------
786 //------------------------------------------------------------------------------
787 void gmAddToExtents(const Pt3d& a_pt, Pt3d& a_min, Pt3d& a_max)
788 {
789  a_min.x = std::min(a_pt.x, a_min.x);
790  a_min.y = std::min(a_pt.y, a_min.y);
791  a_min.z = std::min(a_pt.z, a_min.z);
792  a_max.x = std::max(a_pt.x, a_max.x);
793  a_max.y = std::max(a_pt.y, a_max.y);
794  a_max.z = std::max(a_pt.z, a_max.z);
795 } // gmAddToExtents
796 //------------------------------------------------------------------------------
801 //------------------------------------------------------------------------------
802 void gmAddToExtents(const Pt3d& a_pt, Pt2d& a_min, Pt2d& a_max)
803 {
804  a_min.x = std::min(a_pt.x, a_min.x);
805  a_min.y = std::min(a_pt.y, a_min.y);
806  a_max.x = std::max(a_pt.x, a_max.x);
807  a_max.y = std::max(a_pt.y, a_max.y);
808 } // gmAddToExtents
809 //------------------------------------------------------------------------------
814 //------------------------------------------------------------------------------
815 void gmAddToExtents(const Pt2d& a_pt, Pt3d& a_min, Pt3d& a_max)
816 {
817  a_min.x = std::min(a_pt.x, a_min.x);
818  a_min.y = std::min(a_pt.y, a_min.y);
819  a_max.x = std::max(a_pt.x, a_max.x);
820  a_max.y = std::max(a_pt.y, a_max.y);
821 } // gmAddToExtents
822 //------------------------------------------------------------------------------
831 //------------------------------------------------------------------------------
832 double gmXyDistance(double x1, double y1, double x2, double y2)
833 {
834  return sqrt(sqr(x1 - x2) + sqr(y1 - y2));
835 } // gmXyDistance
836 //------------------------------------------------------------------------------
841 //------------------------------------------------------------------------------
842 double gmXyDistance(const Pt3d& pt1, const Pt3d& pt2)
843 {
844  return sqrt(sqr(pt1.x - pt2.x) + sqr(pt1.y - pt2.y));
845 } // gmXyDistance
846 //------------------------------------------------------------------------------
862 //------------------------------------------------------------------------------
863 Turn_enum gmTurn(const Pt3d& a_v1, const Pt3d& a_v2, const Pt3d& a_v3, double a_angtol)
864 {
865  // compute sin T = (v3-v2)x(v1-v2)/(d12*d32)
866  double dx32 = a_v3.x - a_v2.x;
867  double dy32 = a_v3.y - a_v2.y;
868  double dx12 = a_v1.x - a_v2.x;
869  double dy12 = a_v1.y - a_v2.y;
870  double d32 = sqrt(dx32 * dx32 + dy32 * dy32);
871  double d12 = sqrt(dx12 * dx12 + dy12 * dy12);
872  double mag = d12 * d32;
873  double sint = (dx32 * dy12 - dx12 * dy32) / mag;
874 
875  // for 99.999 > T > 0.1 deg - sin T > 0.0017
876  if (sint > a_angtol)
877  return TURN_LEFT;
878  else if (sint < -a_angtol)
879  return TURN_RIGHT;
880 
881  // compute cos T = (v3-v2)DOT(v1-v2)/(d12*d32)
882  // Near colinear case, Cosine should be near 1 or -1,
883  // -1 indicates 180 deg
884  double cost = (dx12 * dx32 + dy12 * dy32) / mag;
885  if (cost < 0.0)
886  return TURN_COLINEAR_180;
887  return TURN_COLINEAR_0;
888 } // gmTurn
889 //------------------------------------------------------------------------------
894 //------------------------------------------------------------------------------
896 {
897  Pt3d centroid;
898  size_t size = a_points.size();
899  for (size_t i = 0; i < size; ++i)
900  centroid += a_points[i];
901  return (centroid / (double)size);
902 } // gmComputeCentroid
903 //------------------------------------------------------------------------------
907 //------------------------------------------------------------------------------
909 {
910  Pt3d centroid;
911  if (pts.empty())
912  return centroid;
913  // get offset to use in calculation below to fix precision issues
914  double xMax = XM_DBL_LOWEST, yMax = XM_DBL_LOWEST, xMin = XM_DBL_HIGHEST, yMin = XM_DBL_HIGHEST;
915  size_t i = 0;
916  for (i = 0; i < pts.size(); ++i)
917  {
918  double x = pts[i].x;
919  double y = pts[i].y;
920  xMax = (x > xMax) ? x : xMax;
921  yMax = (y > yMax) ? y : yMax;
922  xMin = (x < xMin) ? x : xMin;
923  yMin = (y < yMin) ? y : yMin;
924  }
925  double xOffset = (xMax + xMin) / 2.0;
926  double yOffset = (yMax + yMin) / 2.0;
927  // For all vertices except last
928  double signedArea = 0.0;
929  for (i = 0; i < pts.size() - 1; ++i)
930  {
931  double x0 = pts[i].x - xOffset;
932  double y0 = pts[i].y - yOffset;
933  double x1 = pts[i + 1].x - xOffset;
934  double y1 = pts[i + 1].y - yOffset;
935  double a = x0 * y1 - x1 * y0;
936  signedArea += a;
937  centroid.x += (x0 + x1) * a;
938  centroid.y += (y0 + y1) * a;
939  }
940  // Do last vertex
941  double x0 = pts[i].x - xOffset;
942  double y0 = pts[i].y - yOffset;
943  double x1 = pts[0].x - xOffset;
944  double y1 = pts[0].y - yOffset;
945  double a = x0 * y1 - x1 * y0;
946  signedArea += a;
947  centroid.x += (x0 + x1) * a;
948  centroid.y += (y0 + y1) * a;
949  signedArea *= 0.5;
950  centroid.x /= (6.0 * signedArea);
951  centroid.y /= (6.0 * signedArea);
952  centroid.x += xOffset;
953  centroid.y += yOffset;
954  return centroid;
955 } // gmComputePolygonCentroid
956 //------------------------------------------------------------------------------
965 //------------------------------------------------------------------------------
966 bool gmLinesIntersect(const Pt3d& one1, const Pt3d& one2, const Pt3d& two1, const Pt3d& two2)
967 {
968  // do a trivial rejection
969  double min = std::min(one1.x, one2.x);
970  double max = std::max(two1.x, two2.x);
971  const double tol(XM_ZERO_TOL);
972  if (GT_TOL(min, max, tol))
973  return false;
974  max = std::max(one1.x, one2.x);
975  min = std::min(two1.x, two2.x);
976  if (LT_TOL(max, min, tol))
977  return false;
978  min = std::min(one1.y, one2.y);
979  max = std::max(two1.y, two2.y);
980  if (GT_TOL(min, max, tol))
981  return false;
982  max = std::max(one1.y, one2.y);
983  min = std::min(two1.y, two2.y);
984  if (LT_TOL(max, min, tol))
985  return false;
986  // define the vectors
987  Pt2d d1(one2 - one1), d2(two2 - two1);
988  // see if lines are parallel
989  // SMS bug fix: replaced tolerance check with a non-zero check.
990  // Sometimes we have very small tolerances
991  double cross = (d2.x * d1.y) - (d2.y * d1.x);
992  if (cross == 0.0)
993  return false;
994  // if the lines intersect s should be between 0.0 and 1.0
995  double s = ((d1.x * (two1.y - one1.y)) + (d1.y * (one1.x - two1.x))) / cross;
996  if (LT_TOL(s, 0.0, tol) || GT_TOL(s, 1.0, tol))
997  return false;
998  // if the lines intersect t should be between -1.0 and 0.0
999  double t = ((d2.x * (one1.y - two1.y)) + (d2.y * (two1.x - one1.x))) / cross;
1000  if (LT_TOL(t, -1.0, tol) || GT_TOL(t, 0.0, tol))
1001  return false;
1002  return true;
1003 } // gmLinesIntersect
1004 //------------------------------------------------------------------------------
1012 //------------------------------------------------------------------------------
1013 bool gmLinesCross(const Pt3d& a_segment1Point1,
1014  const Pt3d& a_segment1Point2,
1015  const Pt3d& a_segment2Point1,
1016  const Pt3d& a_segment2Point2)
1017 {
1018  // Boundary case checks
1019  // Any of the points from line segment 1 are the same as any points from line segment 2
1020  if ((a_segment1Point1 == a_segment2Point1 || a_segment1Point1 == a_segment2Point2) &&
1021  (a_segment1Point2 == a_segment2Point1 || a_segment1Point2 == a_segment2Point2))
1022  return true;
1023 
1024  // The segments AB and CD intersect if and only if both of the following are true:
1025  //
1026  // A and B lie on different sides of the line through C and D
1027  // C and D lie on different sides of the line through A and B
1028  // These two conditions can be tested for using the notion of a scalar cross product(formulas
1029  // below).
1030 
1031  // is true if and only if the scalar cross products CA->=CD-> and CB->=CD-> have opposite signs.
1032  // is true if and only if the scalar cross products AC->=AB-> and AD->=AB-> have opposite signs.
1033 
1034  // Conclusion: the line segments intersect if and only if both are negative
1035  double result1 = gmCross2D(a_segment2Point1, a_segment1Point1, a_segment2Point2);
1036  double result2 = gmCross2D(a_segment2Point1, a_segment1Point2, a_segment2Point2);
1037  double result3 = gmCross2D(a_segment1Point1, a_segment2Point1, a_segment1Point2);
1038  double result4 = gmCross2D(a_segment2Point1, a_segment2Point2, a_segment1Point2);
1039 
1040  return (result1 * result2 < 0 && result3 * result4 < 0);
1041 } // gmLinesCross
1042 //------------------------------------------------------------------------------
1055 //------------------------------------------------------------------------------
1056 template <typename T>
1057 int gmPointInPolygon2D(const T* a_verts,
1058  const size_t a_num,
1059  const double a_x,
1060  const double a_y,
1061  const double a_tol)
1062 {
1063  if (a_verts && a_num)
1064  {
1065  int nmleft = 0, nmrght = 0;
1066  double dy2 = fabs(a_verts[0].y - a_y);
1067  double diff;
1068  for (size_t i = 0; i < a_num; i++)
1069  {
1070  size_t i2 = 0;
1071  if (i != a_num - 1)
1072  i2 = i + 1;
1073  double dy1 = dy2;
1074  dy2 = fabs(a_verts[i2].y - a_y);
1075  if (dy1 <= a_tol)
1076  {
1077  if (dy2 <= a_tol)
1078  {
1079  // Case #1 - edge is on the same y value as the point
1080  // - see if the point is on the edge
1081  if (((a_verts[i].x >= a_x) && (a_verts[i2].x <= a_x)) ||
1082  ((a_verts[i].x <= a_x) && (a_verts[i2].x >= a_x)))
1083  return (0);
1084  }
1085  else
1086  {
1087  // Case #2 - first vertex has same y value as point
1088  // - see if the point actually coincides with
1089  // the ith vertex
1090  diff = a_verts[i].x - a_x;
1091  if (fabs(diff) <= a_tol)
1092  return (0);
1093  else if (a_verts[i].y < a_verts[i2].y)
1094  {
1095  // edge ascends, classify as right or left
1096  if (diff > 0)
1097  ++nmrght;
1098  else
1099  ++nmleft;
1100  }
1101  }
1102  }
1103  else if (dy2 <= a_tol)
1104  {
1105  // Case #3 - 2nd vertex of edge lies on dividing plane
1106  // - see if the point actually coincides with
1107  // the i2-th vertex
1108  diff = a_verts[i2].x - a_x;
1109  if (fabs(diff) <= a_tol)
1110  return (0);
1111  else if (a_verts[i2].y < a_verts[i].y)
1112  {
1113  // if edge descends classify as right or left
1114  if (diff > 0)
1115  ++nmrght;
1116  else
1117  ++nmleft;
1118  }
1119  }
1120  else if (((a_verts[i].y < a_y) && (a_verts[i2].y > a_y)) ||
1121  ((a_verts[i].y > a_y) && (a_verts[i2].y < a_y)))
1122  {
1123  // Case #4 - edge cleanly intersects dividing plane
1124  // - flag edge as left, right or on edge
1125  double val = a_verts[i].x + (a_verts[i2].x - a_verts[i].x) * (a_y - a_verts[i].y) /
1126  (a_verts[i2].y - a_verts[i].y);
1127  diff = val - a_x;
1128  if (fabs(diff) <= a_tol)
1129  return (0);
1130  else if (diff > 0)
1131  ++nmrght;
1132  else
1133  ++nmleft;
1134  }
1135  }
1136  nmleft = nmleft % 2;
1137  nmrght = nmrght % 2;
1138  if (nmleft != nmrght)
1139  return (-1); // this should never happen actually
1140  else if (nmleft == 1)
1141  return (1);
1142  else
1143  return (-1);
1144  }
1145  return (-1);
1146 } // gmPointInPolygon2D
1147 //------------------------------------------------------------------------------
1154 //------------------------------------------------------------------------------
1155 int gmPointInPolygon2D(const Pt3d* a_verts, size_t a_num, double a_x, double a_y)
1156 {
1157  return gmPointInPolygon2D(a_verts, a_num, a_x, a_y, gmXyTol());
1158 } // gmPointInPolygon2D
1159 //------------------------------------------------------------------------------
1165 //------------------------------------------------------------------------------
1166 int gmPointInPolygon2D(const Pt3d* a_verts, size_t a_num, Pt3d a_pt)
1167 {
1168  return gmPointInPolygon2D(a_verts, a_num, a_pt.x, a_pt.y, gmXyTol());
1169 } // gmPointInPolygon2D
1170 //------------------------------------------------------------------------------
1176 //------------------------------------------------------------------------------
1177 int gmPointInPolygon2D(const Pt2i* a_verts, size_t a_num, Pt2d a_pt)
1178 {
1179  return gmPointInPolygon2D(a_verts, a_num, a_pt.x, a_pt.y, gmXyTol());
1180 } // gmPointInPolygon2D
1181 //------------------------------------------------------------------------------
1187 //------------------------------------------------------------------------------
1188 int gmPointInPolygon2D(const Pt2i* a_verts, size_t a_num, Pt3d a_pt)
1189 {
1190  return gmPointInPolygon2D(a_verts, a_num, a_pt.x, a_pt.y, gmXyTol());
1191 } // gmPointInPolygon2D
1192 //------------------------------------------------------------------------------
1198 //------------------------------------------------------------------------------
1199 int gmPointInPolygon2D(const Pt2i* a_verts, size_t a_num, Pt2i a_pt)
1200 {
1201  return gmPointInPolygon2D(a_verts, a_num, a_pt.x, a_pt.y, gmXyTol());
1202 } // gmPointInPolygon2D
1203 //------------------------------------------------------------------------------
1208 //------------------------------------------------------------------------------
1209 int gmPointInPolygon2D(const VecPt3d& a_verts, const Pt3d& a_pt)
1210 {
1211  return gmPointInPolygon2D(&a_verts[0], a_verts.size(), a_pt.x, a_pt.y, gmXyTol());
1212 } // gmPointInPolygon2D
1213 //------------------------------------------------------------------------------
1221 //------------------------------------------------------------------------------
1222 template int gmPointInPolygon2D<Pt3d>(const Pt3d* a_verts,
1223  const size_t a_num,
1224  const double a_x,
1225  const double a_y,
1226  const double a_tol);
1227 //------------------------------------------------------------------------------
1235 //------------------------------------------------------------------------------
1236 template int gmPointInPolygon2D<Pt2d>(const Pt2d* a_verts,
1237  const size_t a_num,
1238  const double a_x,
1239  const double a_y,
1240  const double a_tol);
1241 //------------------------------------------------------------------------------
1249 //------------------------------------------------------------------------------
1250 template int gmPointInPolygon2D<Pt2i>(const Pt2i* a_verts,
1251  const size_t a_num,
1252  const double a_x,
1253  const double a_y,
1254  const double a_tol);
1255 //------------------------------------------------------------------------------
1261 //------------------------------------------------------------------------------
1262 double gmComputeXyTol(const Pt3d& a_mn, const Pt3d& a_mx)
1263 {
1264  double d = gmXyDistance(a_mn, a_mx);
1265  double const kFactor = 1e-9;
1266  double xytol = d * kFactor;
1267  if (xytol < kFactor)
1268  {
1269  xytol = kFactor;
1270  }
1271  return xytol;
1272 } // gmComputeXyTol
1273 //------------------------------------------------------------------------------
1278 //------------------------------------------------------------------------------
1279 double gmXyTol(bool a_set /*false*/, double a_value /*1e-9*/)
1280 {
1281  static double xytol = a_value;
1282  if (a_set)
1283  xytol = a_value;
1284  return xytol;
1285 } // gmXyTol
1286 //------------------------------------------------------------------------------
1291 //------------------------------------------------------------------------------
1292 double gmZTol(bool a_set, double a_value)
1293 {
1294  static double ztol = a_value;
1295  if (a_set)
1296  ztol = a_value;
1297  return ztol;
1298 } // gmZTol
1299 //------------------------------------------------------------------------------
1307 //------------------------------------------------------------------------------
1308 bool gmEqualPointsXY(double x1, double y1, double x2, double y2, double tolerance)
1309 {
1310  double dx = fabs(x1 - x2);
1311  double dy = fabs(y1 - y2);
1312  if (dx > tolerance || dy > tolerance)
1313  return false;
1314  else if (sqrt(dx * dx + dy * dy) <= tolerance)
1315  return true;
1316  else
1317  return false;
1318 } // gmEqualPointsXY
1319 //------------------------------------------------------------------------------
1326 //------------------------------------------------------------------------------
1327 bool gmEqualPointsXY(double x1, double y1, double x2, double y2)
1328 {
1329  return gmEqualPointsXY(x1, y1, x2, y2, gmXyTol());
1330 } // gmEqualPointsXY
1331 //------------------------------------------------------------------------------
1337 //------------------------------------------------------------------------------
1338 bool gmEqualPointsXY(const Pt2d& a_pt1, const Pt2d& a_pt2, double tol)
1339 {
1340  return gmEqualPointsXY(a_pt1.x, a_pt1.y, a_pt2.x, a_pt2.y, tol);
1341 } // gmEqualPointsXY
1342 //------------------------------------------------------------------------------
1348 //------------------------------------------------------------------------------
1349 bool gmEqualPointsXY(const Pt3d& a_pt1, const Pt3d& a_pt2, double tol)
1350 {
1351  return gmEqualPointsXY(a_pt1.x, a_pt1.y, a_pt2.x, a_pt2.y, tol);
1352 } // gmEqualPointsXY
1353 //------------------------------------------------------------------------------
1358 //------------------------------------------------------------------------------
1359 bool gmEqualPointsXY(const Pt2i& point1, const Pt2i& point2)
1360 {
1361  if (point1.x == point2.x && point1.y == point2.y)
1362  return true;
1363  return false;
1364 } // gmEqualPointsXY
1365 //------------------------------------------------------------------------------
1375 //------------------------------------------------------------------------------
1376 bool gmEqualPointsXYZ(double x1,
1377  double y1,
1378  double z1,
1379  double x2,
1380  double y2,
1381  double z2,
1382  double tolerance)
1383 {
1384  if ((fabs(x1 - x2) <= tolerance) && (fabs(y1 - y2) <= tolerance) && (fabs(z1 - z2) <= tolerance))
1385  return true;
1386  return false;
1387 } // gmEqualPointsXYZ
1388 //------------------------------------------------------------------------------
1397 //------------------------------------------------------------------------------
1398 bool gmEqualPointsXYZ(double x1, double y1, double z1, double x2, double y2, double z2)
1399 {
1400  return gmEqualPointsXYZ(x1, y1, z1, x2, y2, z2, gmXyTol());
1401 } // gmEqualPointsXYZ
1402 //------------------------------------------------------------------------------
1408 //------------------------------------------------------------------------------
1409 bool gmEqualPointsXYZ(const Pt3d& pt1, const Pt3d& pt2, double tol)
1410 {
1411  return gmEqualPointsXYZ(pt1.x, pt1.y, pt1.z, pt2.x, pt2.y, pt2.z, tol);
1412 } // gmEqualPointsXYZ
1413 //------------------------------------------------------------------------------
1422 //------------------------------------------------------------------------------
1424  const Pt3d* p2,
1425  const Pt3d* p3,
1426  double x,
1427  double y,
1428  double tol)
1429 {
1430  if (gmInsideOrOnLineWithTol(p1, p2, p3, x, y, tol))
1431  if (gmInsideOrOnLineWithTol(p2, p3, p1, x, y, tol))
1432  if (gmInsideOrOnLineWithTol(p3, p1, p2, x, y, tol))
1433  return true;
1434  return false;
1435 } // gmPointInTriangleWithTol
1436 //------------------------------------------------------------------------------
1449 //------------------------------------------------------------------------------
1451  const Pt3d* p2,
1452  const Pt3d* inpoint,
1453  const double x,
1454  const double y,
1455  const double tol,
1456  double* dist /*= NULL */)
1457 {
1458  double dx, dy, a, b, c, mag;
1459  double d1, d2;
1460  /* make sure line is not a point */
1461  dx = p2->x - p1->x;
1462  dy = p2->y - p1->y;
1463  mag = sqrt(sqr(dx) + sqr(dy));
1464  if (mag <= tol)
1465  {
1466  return gmEqualPointsXY(p1->x, p1->y, x, y);
1467  }
1468  else
1469  {
1470  a = -dy / mag;
1471  b = dx / mag;
1472  c = -a * p1->x - b * p1->y;
1473  /* compute distance from line to (x,y) */
1474  d1 = a * x + b * y + c;
1475  /* compute distance from line to opposite p */
1476  d2 = a * inpoint->x + b * inpoint->y + c;
1477  // if inpoint is really on, we can't make a judgment on the point
1478  if (Mfabs(d2) <= tol)
1479  {
1480  // AKZ - Since "inpoint" is usually the other point in a triangle
1481  // this usually indicates a poorly formed triangle.
1482  // You should determine how this triangle was formed.
1483  // XM_ASSERT(0);
1484  return false;
1485  }
1486  /* return true if point on line */
1487  if (Mfabs(d1) <= tol)
1488  {
1489  if (dist)
1490  {
1491  if (d1 * d2 < 0.0)
1492  {
1493  *dist = Mfabs(d1);
1494  }
1495  else
1496  {
1497  *dist = -Mfabs(d1);
1498  }
1499  }
1500  return true;
1501  }
1502  /* return true if d1 and d2 have same sign */
1503  if ((d1 < 0.0) && (d2 < 0.0))
1504  {
1505  if (dist)
1506  {
1507  *dist = -Mfabs(d1);
1508  }
1509  return true;
1510  }
1511  else if ((d1 > 0.0) && (d2 > 0.0))
1512  {
1513  if (dist)
1514  {
1515  *dist = -Mfabs(d1);
1516  }
1517  return true;
1518  }
1519  else
1520  {
1521  if (dist)
1522  {
1523  *dist = Mfabs(d1);
1524  }
1525  return false;
1526  }
1527  }
1528 } // gmInsideOrOnLineWithTol
1529 //------------------------------------------------------------------------------
1536 //------------------------------------------------------------------------------
1537 double gmPolygonArea(const Pt3d* pts, size_t npoints)
1538 {
1539  if (npoints < 3)
1540  return 0.0;
1541  size_t id;
1542  double area = 0.0;
1543 
1544  /* original method with precision errors
1545  for (id = 0; id < npoints; id++)
1546  {
1547  if (id != (npoints - 1))
1548  {
1549  area += (pts[id].x * pts[id + 1].y);
1550  area -= (pts[id].y * pts[id + 1].x);
1551  }
1552  else
1553  {
1554  area += (pts[id].x * pts[0].y);
1555  area -= (pts[id].y * pts[0].x);
1556  }
1557  }
1558  area /= 2.0;
1559  */
1560 
1561  // AKZ 2/15/2018
1562  // I changed the implementation to translate the polygon
1563  // so that the first point is at the origin
1564  // Reduces round off error due to large coordinates
1565  // Reduces the number of computations because the first and last
1566  // computations in the loop would be 0.0
1567  VecDbl x, y;
1568  double x0 = pts[0].x;
1569  double y0 = pts[0].y;
1570  for (id = 1; id < npoints; id++)
1571  {
1572  x.push_back((pts[id].x - x0));
1573  y.push_back((pts[id].y - y0));
1574  }
1575  for (id = 0; id < npoints - 2; id++)
1576  {
1577  area += (x[id] * y[id + 1]);
1578  area -= (y[id] * x[id + 1]);
1579  }
1580  area /= 2.0;
1581 
1582  return (area);
1583 } // gmPolygonArea
1584 //------------------------------------------------------------------------------
1589 //------------------------------------------------------------------------------
1590 VecPt3d gmArrayToVecPt3d(double* a_array, int a_size)
1591 {
1592  VecPt3d v(a_size / 2);
1593  for (int i = 0; i < a_size; i += 2)
1594  {
1595  v[i / 2].x = a_array[i];
1596  v[i / 2].y = a_array[i + 1];
1597  }
1598  return v;
1599 } // gmArrayToVecPt3d
1600 //------------------------------------------------------------------------------
1605 //------------------------------------------------------------------------------
1606 void gmEnvelopeOfPts(const VecPt3d& a_pts, Pt3d& a_min, Pt3d& a_max)
1607 {
1608  a_min = a_max = Pt3d();
1609  XM_ENSURE_TRUE(!a_pts.empty());
1610  a_min = a_max = a_pts.front();
1611  for (size_t i = 0; i < a_pts.size(); ++i)
1612  {
1613  if (a_pts[i].x < a_min.x)
1614  a_min.x = a_pts[i].x;
1615  if (a_pts[i].y < a_min.y)
1616  a_min.y = a_pts[i].y;
1617  if (a_pts[i].z < a_min.z)
1618  a_min.z = a_pts[i].z;
1619  if (a_pts[i].x > a_max.x)
1620  a_max.x = a_pts[i].x;
1621  if (a_pts[i].y > a_max.y)
1622  a_max.y = a_pts[i].y;
1623  if (a_pts[i].z > a_max.z)
1624  a_max.z = a_pts[i].z;
1625  }
1626 } // gmEnvelopeOfPts
1627 //------------------------------------------------------------------------------
1634 //------------------------------------------------------------------------------
1635 void gmOrderPointsCounterclockwise(const VecPt3d& a_pts, VecInt& a_ccwOrder, int a_startindex)
1636 {
1637  int numnodes = (int)a_pts.size();
1638 
1639  // compute centroid of points
1640  Pt2d center;
1641  double sumx = 0.0;
1642  double sumy = 0.0;
1643  for (int i = 0; i < numnodes; i++)
1644  {
1645  sumx += a_pts[i].x;
1646  sumy += a_pts[i].y;
1647  }
1648 
1649  center.x = sumx / numnodes;
1650  center.y = sumy / numnodes;
1651 
1652  // compute polar angle for each node about the centroid of the element
1653  // along with the original point index
1654  std::vector<std::pair<float, int> > angleIndex(numnodes);
1655  for (int i = 0; i < numnodes; i++)
1656  {
1657  float angle = (float)(atan2(a_pts[i].y - center.y, a_pts[i].x - center.x));
1658  angleIndex[i] = std::pair<float, int>(angle, i);
1659  }
1660 
1661  std::stable_sort(angleIndex.begin(), angleIndex.end());
1662 
1663  // find where starting index is in sorted array
1664  auto startIter = angleIndex.begin();
1665  while (startIter != angleIndex.end() && startIter->second != a_startindex)
1666  {
1667  ++startIter;
1668  }
1669  if (startIter == angleIndex.end())
1670  startIter = angleIndex.begin();
1671 
1672  // assign the result preserving the order with a_startindex the first node
1673  a_ccwOrder.resize(numnodes, 0);
1674  size_t j = 0;
1675  for (auto iter = startIter; iter != angleIndex.end(); ++iter)
1676  {
1677  a_ccwOrder[j] = iter->second;
1678  j++;
1679  }
1680  for (auto iter = angleIndex.begin(); iter != startIter; ++iter)
1681  {
1682  a_ccwOrder[j] = iter->second;
1683  j++;
1684  }
1685 } // gmOrderPointsCounterclockwise
1686 //------------------------------------------------------------------------------
1689 //------------------------------------------------------------------------------
1691 {
1692  if (a_pts.empty())
1693  return;
1694 
1695  VecInt ccwOrder;
1696  VecPt3d pts(a_pts);
1697  gmOrderPointsCounterclockwise(pts, ccwOrder);
1698  for (size_t i = 0; i < ccwOrder.size(); ++i)
1699  {
1700  a_pts[i] = pts[ccwOrder[i]];
1701  }
1702 } // gmOrderPointsCounterclockwise
1703 //------------------------------------------------------------------------------
1713 //------------------------------------------------------------------------------
1714 double gmFindClosestPtOnSegment(const Pt3d& a_pt1,
1715  const Pt3d& a_pt2,
1716  const Pt3d& a_pt,
1717  Pt3d& a_newpt,
1718  const double a_tol)
1719 {
1720  double t = gmPtDistanceAlongSegment(a_pt1, a_pt2, a_pt, a_tol);
1721  if (t < 0.0)
1722  {
1723  a_newpt.x = a_pt1.x;
1724  a_newpt.y = a_pt1.y;
1725  }
1726  else if (t > 1.0)
1727  {
1728  a_newpt.x = a_pt2.x;
1729  a_newpt.y = a_pt2.y;
1730  }
1731  else
1732  {
1733  double dx = a_pt2.x - a_pt1.x;
1734  double dy = a_pt2.y - a_pt1.y;
1735  a_newpt.x = a_pt1.x + dx * t;
1736  a_newpt.y = a_pt1.y + dy * t;
1737  }
1738  return t;
1739 } // gmFindClosestPtOnSegment
1740 //------------------------------------------------------------------------------
1748 //------------------------------------------------------------------------------
1749 double gmPtDistanceAlongSegment(const Pt3d& a_pt1,
1750  const Pt3d& a_pt2,
1751  const Pt3d& a_pt,
1752  const double a_tol)
1753 {
1754  double dx, dy, t;
1755 
1756  dx = a_pt2.x - a_pt1.x;
1757  dy = a_pt2.y - a_pt1.y;
1758 
1759  if ((dx == 0.0 && dy == 0.0) || (sqrt(dx * dx + dy * dy) <= a_tol))
1760  {
1761  t = -1.0;
1762  }
1763  else
1764  {
1765  t = ((a_pt.x - a_pt1.x) * dx + (a_pt.y - a_pt1.y) * dy) / (dx * dx + dy * dy);
1766  }
1767 
1768  return t;
1769 } // gmPtDistanceAlongSegment
1770 //------------------------------------------------------------------------------
1781 //------------------------------------------------------------------------------
1782 bool gmInsideOfLineWithTol(const Pt3d& a_vertex1,
1783  const Pt3d& a_vertex2,
1784  const Pt3d& a_oppositevertex,
1785  const double a_x,
1786  const double a_y,
1787  const double a_tol)
1788 {
1789  double dx = a_vertex2.x - a_vertex1.x;
1790  double dy = a_vertex2.y - a_vertex1.y;
1791  double mag = sqrt(sqr(dx) + sqr(dy));
1792  if (mag <= a_tol)
1793  {
1794  return gmEqualPointsXY(a_vertex1.x, a_vertex1.y, a_x, a_y);
1795  }
1796  else
1797  {
1798  double a = -dy / mag;
1799  double b = dx / mag;
1800  double c = -a * a_vertex1.x - b * a_vertex1.y;
1801  /* compute the distance from the line to the Point */
1802  double d1 = a * a_x + b * a_y + c;
1803  /* compute the distance from the line to the opposite vertex */
1804  double d2 = a * a_oppositevertex.x + b * a_oppositevertex.y + c;
1805  if (fabs(d1) <= a_tol)
1806  return false;
1807  else if ((d1 < 0.0) && (d2 < 0.0))
1808  return true;
1809  else if ((d1 > 0.0) && (d2 > 0.0))
1810  return true;
1811  else
1812  return false;
1813  }
1814 } // gmInsideOfLine
1815 //------------------------------------------------------------------------------
1820 //------------------------------------------------------------------------------
1821 void gmExtents2D(const VecPt3d& a_points, Pt2d& a_min, Pt2d& a_max)
1822 {
1823  XM_ENSURE_TRUE_VOID_NO_ASSERT(!a_points.empty());
1824 
1825  a_min.x = a_max.x = a_points.at(0).x;
1826  a_min.y = a_max.y = a_points.at(0).y;
1827  for (int i = 1; i < (int)a_points.size(); i++)
1828  {
1829  gmAddToExtents(a_points[i], a_min, a_max);
1830  }
1831 } // gmExtents2D
1832 //----- OVERLOAD ---------------------------------------------------------------
1837 //----- OVERLOAD ---------------------------------------------------------------
1838 void gmExtents2D(const VecPt3d& a_points, Pt3d& a_min, Pt3d& a_max)
1839 {
1840  XM_ENSURE_TRUE_VOID_NO_ASSERT(!a_points.empty());
1841 
1842  a_min.x = a_max.x = a_points.at(0).x;
1843  a_min.y = a_max.y = a_points.at(0).y;
1844  a_min.z = a_max.z = 0.0;
1845  for (int i = 1; i < (int)a_points.size(); i++)
1846  {
1847  gmAddToExtents((Pt2d)a_points[i], a_min, a_max);
1848  }
1849 } // gmExtents2D
1850 //------------------------------------------------------------------------------
1855 //------------------------------------------------------------------------------
1856 void gmExtents3D(const VecPt3d& a_points, Pt3d& a_min, Pt3d& a_max)
1857 {
1858  XM_ENSURE_TRUE_VOID_NO_ASSERT(!a_points.empty());
1859 
1860  a_min.x = a_max.x = a_points.at(0).x;
1861  a_min.y = a_max.y = a_points.at(0).y;
1862  a_min.z = a_max.z = a_points.at(0).z;
1863  for (int i = 1; i < (int)a_points.size(); i++)
1864  {
1865  gmAddToExtents(a_points[i], a_min, a_max);
1866  }
1867 } // gmExtents3D
1868 //------------------------------------------------------------------------------
1873 //------------------------------------------------------------------------------
1874 double gmPerpendicularAngle(const Pt3d& a_pt1, const Pt3d& a_pt2)
1875 {
1876  double hypot;
1877  double deltax, deltay, arad, theangle;
1878 
1879  deltax = a_pt1.x - a_pt2.x;
1880  deltay = a_pt1.y - a_pt2.y;
1881  hypot = sqrt(sqr(deltax) + sqr(deltay));
1882  arad = deltax / hypot;
1883  if (arad > .9999)
1884  arad = 1.0;
1885  else if (arad < -.9999)
1886  arad = -1.0;
1887  if (deltay >= 0.0)
1888  theangle = acos(arad);
1889  else
1890  theangle = 2 * XM_PI - acos(arad);
1891  return (theangle - (XM_PI / 2));
1892 } // gmPerpendicularAngle
1893 //------------------------------------------------------------------------------
1900 //------------------------------------------------------------------------------
1901 double gmBisectingAngle(const Pt3d& a_p1, const Pt3d& a_p2, const Pt3d& a_p3)
1902 {
1903  double dxn, dyn, dxp, dyp, magn, magp, angletoedge1, theanglebetween;
1904  double cosign;
1905 
1906  dxp = a_p1.x - a_p2.x;
1907  dyp = a_p1.y - a_p2.y;
1908  dxn = a_p3.x - a_p2.x;
1909  dyn = a_p3.y - a_p2.y;
1910  angletoedge1 = atan2(dyp, dxp);
1911  magn = sqrt(sqr(dxn) + sqr(dyn));
1912  magp = sqrt(sqr(dxp) + sqr(dyp));
1913  cosign = (dxn * dxp + dyn * dyp) / (magn * magp);
1914  if (cosign > .99999)
1915  cosign = 1.0;
1916  if (cosign < -.99999)
1917  cosign = -1.0;
1918  theanglebetween = acos(cosign);
1919  if (theanglebetween == 0.0)
1920  {
1921  if ((dxn * dxp) + (dyn * dyp) < 0.0)
1922  theanglebetween = XM_PI;
1923  }
1924  else if (gmCross2D(dxp, dyp, dxn, dyn) < 0.0)
1925  theanglebetween = 2 * XM_PI - theanglebetween;
1926  return angletoedge1 + theanglebetween / 2.0;
1927 } // gmBisectingAngle
1928 //------------------------------------------------------------------------------
1940 //------------------------------------------------------------------------------
1941 void gmComponentMagnitudes(double* a_x, double* a_y, double* a_mag, double* a_dir, bool a_tomagdir)
1942 {
1943  double rads;
1944 
1945  if (a_tomagdir)
1946  { // convert (x,y) to (mag,dir)
1947  if (fabs(*a_x) < XM_ZERO_TOL && fabs(*a_y) < XM_ZERO_TOL)
1948  {
1949  *a_mag = 0.0;
1950  *a_dir = 0.0;
1951  }
1952  else
1953  {
1954  if (*a_x == 0)
1955  *a_x = XM_ZERO_TOL;
1956  *a_mag = sqrt(sqr(*a_x) + sqr(*a_y));
1957  *a_dir = (atan(*a_y / *a_x)) * (180 / XM_PI);
1958  if (*a_x < 0)
1959  (*a_dir) += 180;
1960  if (*a_dir < 0)
1961  (*a_dir) += 360;
1962  }
1963  }
1964  else
1965  { // convert (mag,dir) to (x,y)
1966  rads = *a_dir * (XM_PI / 180);
1967  *a_x = cos(rads) * *a_mag;
1968  *a_y = sin(rads) * *a_mag;
1969  if (fabs(*a_x) < XM_ZERO_TOL)
1970  *a_x = 0;
1971  if (fabs(*a_y) < XM_ZERO_TOL)
1972  *a_y = 0;
1973  }
1974 } // gmComponentMagnitudes
1975 //------------------------------------------------------------------------------
1981 //------------------------------------------------------------------------------
1982 Pt3d gmCreateVector(const Pt3d& a_p1, const Pt3d& a_p2)
1983 {
1984  Pt3d vector;
1985  vector.x = a_p2.x - a_p1.x;
1986  vector.y = a_p2.y - a_p1.y;
1987  vector.z = a_p2.z - a_p1.z;
1988  return vector;
1989 } // gmCreateVector
1990 //------------------------------------------------------------------------------
1996 //------------------------------------------------------------------------------
1997 double gmConvertAngleToBetween0And360(double a_angle, bool a_InDegrees /*= true*/
1998 )
1999 {
2000  double ang = a_angle;
2001 
2002  if (!a_InDegrees)
2003  {
2004  ang *= (180.0 / XM_PI);
2005  }
2006 
2007 #if BOOST_OS_WINDOWS
2008  while (LT_TOL(ang, 0.0, DBL_EPSILON) && _finite(ang))
2009  {
2010 #else
2011  while (LT_TOL(ang, 0.0, DBL_EPSILON) && std::isfinite(ang))
2012  {
2013 #endif
2014  ang += 360.0;
2015  }
2016 #if BOOST_OS_WINDOWS
2017  while (GTEQ_TOL(ang, 360.0, DBL_EPSILON) && _finite(ang))
2018  {
2019 #else
2020  while (GTEQ_TOL(ang, 360.0, DBL_EPSILON) && std::isfinite(ang))
2021  {
2022 #endif
2023  ang -= 360.0;
2024  }
2025 
2026  return ang;
2027 } // gmConvertAngleToBetween0And360
2028 //------------------------------------------------------------------------------
2033 //------------------------------------------------------------------------------
2034 void gmCross3D(const Pt3d& a_vec1, const Pt3d& a_vec2, Pt3d* a_vec3)
2035 {
2036  a_vec3->x = a_vec1.y * a_vec2.z - a_vec1.z * a_vec2.y;
2037  a_vec3->y = a_vec1.z * a_vec2.x - a_vec1.x * a_vec2.z;
2038  a_vec3->z = a_vec1.x * a_vec2.y - a_vec1.y * a_vec2.x;
2039 } // gmCross3D
2040 //------------------------------------------------------------------------------
2047 //------------------------------------------------------------------------------
2048 inline double gmDot3D(const Pt3d& a_vec1, const Pt3d& a_vec2)
2049 {
2050  return (a_vec1.x * a_vec2.x + a_vec1.y * a_vec2.y + a_vec1.z * a_vec2.z);
2051 } // gmDot3D
2052 //------------------------------------------------------------------------------
2066 //
2067 // Copyright 2001, softSurfer (www.softsurfer.com)
2068 // This code may be freely used and modified for any purpose providing that
2069 // this copyright notice is included with it. SoftSurfer makes no warranty
2070 // for this code, and cannot be held liable for any real or imagined damage
2071 // resulting from its use. Users of this code must verify correctness for
2072 // their application.
2073 // http://geometryalgorithms.com/Archive/algorithm_0105/algorithm_0105.htm
2074 //------------------------------------------------------------------------------
2076  const Pt3d& a_pt2,
2077  const Pt3d& a_t0,
2078  const Pt3d& a_t1,
2079  const Pt3d& a_t2,
2080  Pt3d& a_IntersectPt)
2081 {
2082  double a, b, r;
2083  Pt3d dir, n, NullVector(0.0, 0.0, 0.0), u, v, w, w0;
2084 
2085  // get the triangle edge vectors and plane normal
2086  u = a_t1 - a_t0;
2087  v = a_t2 - a_t0;
2088  gmCross3D(u, v, &n);
2089 
2090  // check if the triangle is degenerate
2091  if (n == NullVector)
2092  {
2093  return -1;
2094  }
2095 
2096  // get the ray direction vector
2097  dir = a_pt2 - a_pt1;
2098  w0 = a_pt1 - a_t0;
2099  a = -gmDot3D(n, w0);
2100  b = gmDot3D(n, dir);
2101 
2102  // see if ray is parallel to the triangle
2103  if (fabs(b) < XM_ZERO_TOL)
2104  {
2105  // see if ray lies in triangle plane
2106  if (a == 0)
2107  {
2108  return 2;
2109  }
2110  // else ray is disjoint from the triangle plane
2111  else
2112  {
2113  return 0;
2114  }
2115  }
2116 
2117  // get the intersection point or ray with triangle plane
2118  r = a / b;
2119 
2120  // see if there is an intersection
2121  // if (r < 0.0 || r > 1.0) {
2122  if (r < -FLT_EPSILON || r > 1.0 + FLT_EPSILON)
2123  {
2124  return 0;
2125  }
2126 
2127  // intersect point of ray and plane
2128  a_IntersectPt = a_pt1 + dir * r;
2129 
2130  // see if the intersection is inside of the triangle
2131  double D, uu, uv, vv, wu, wv;
2132 
2133  uu = gmDot3D(u, u);
2134  uv = gmDot3D(u, v);
2135  vv = gmDot3D(v, v);
2136  w = a_IntersectPt - a_t0;
2137  wu = gmDot3D(w, u);
2138  wv = gmDot3D(w, v);
2139  D = uv * uv - uu * vv;
2140 
2141  // get the test parametric coords
2142  double s, t;
2143 
2144  s = (uv * wv - vv * wu) / D;
2145  if (s < 0.0 || s > 1.0)
2146  {
2147  // the intersect point is outside the triangle
2148  return 0;
2149  }
2150  t = (uv * wu - uu * wv) / D;
2151  if (t < 0.0 || (s + t) > 1.0)
2152  {
2153  // the intersect point is outside the triangle
2154  return 0;
2155  }
2156 
2157  // the intersect point is inside the triangle
2158  return 1;
2159 } // gmIntersectTriangleAndLineSegment
2160 /***********************************************************************
2161 * FUNCTION gm2DDistanceToLineWithTol
2162 * PURPOSE return the xy distance from (x,y) to line through (pt1, pt2)
2163 * NOTES this doesn't return fabs of the dist!! Differs from
2164 gm2DDistanceToLineSegmentWithTol in that the line is not
2165 treated like a line segment and the point on the line closest
2166 to xy may be outside the 2 points defining the line.
2167 ***********************************************************************/
2168 //------------------------------------------------------------------------------
2176 //------------------------------------------------------------------------------
2177 double gm2DDistanceToLineWithTol(const Pt3d* a_pt1,
2178  const Pt3d* a_pt2,
2179  double a_x,
2180  double a_y,
2181  double a_tol)
2182 {
2183  double a1, b1, c, mag;
2184  double dist;
2185  // see if the (x,y) is on infinite line
2186  a1 = a_pt2->x - a_pt1->x;
2187  b1 = a_pt2->y - a_pt1->y;
2188  mag = sqrt(a1 * a1 + b1 * b1);
2189  // handle case of line segment with length < tol distance to either point (pt1)
2190  if (mag <= a_tol)
2191  {
2192  return sqrt(sqr(a_pt1->x - a_x) + sqr(a_pt1->y - a_y));
2193  }
2194 
2195  // compute line equation
2196  double a, b;
2197  a = -b1 / mag;
2198  b = a1 / mag;
2199  c = -a * a_pt1->x - b * a_pt1->y;
2200  // compute distance from the line to (x,y)
2201  dist = a * a_x + b * a_y + c;
2202 
2203  return dist;
2204 } // gm2DDistanceToLineWithTol
2205 //------------------------------------------------------------------------------
2210 //------------------------------------------------------------------------------
2211 void gmGetConvexHull(const VecPt3d& a_pts, VecPt3d& a_hull, bool a_includeOn /*=false*/)
2212 {
2213  a_hull.clear();
2214 
2215  // copy points with only x/y values
2216  VecPt3d points(a_pts);
2217  for (size_t i = 0; i < points.size(); ++i)
2218  points[i].z = 0.0;
2219 
2220  // sort and remove duplicates
2221  std::sort(points.begin(), points.end());
2222  auto end = std::unique(points.begin(), points.end());
2223  size_t size = end - points.begin();
2224  points.resize(size);
2225 
2226  if (size < 3)
2227  {
2228  a_hull = points;
2229  return;
2230  }
2231 
2232  // build lower hull
2233  VecPt3d lower;
2234  for (auto p = points.begin(); p != points.end(); ++p)
2235  {
2236  size_t lsize = lower.size();
2237  while (lsize > 1 && isRightTurn(gmTurn(lower[lsize - 2], lower[lsize - 1], *p), !a_includeOn))
2238  {
2239  lower.pop_back();
2240  lsize = lower.size();
2241  }
2242  lower.push_back(*p);
2243  }
2244  lower.pop_back();
2245 
2246  // build upper hull
2247  VecPt3d upper;
2248  for (auto p = points.rbegin(); p != points.rend(); ++p)
2249  {
2250  size_t usize = upper.size();
2251  while (usize > 1 && isRightTurn(gmTurn(upper[usize - 2], upper[usize - 1], *p), !a_includeOn))
2252  {
2253  upper.pop_back();
2254  usize = upper.size();
2255  }
2256  upper.push_back(*p);
2257  }
2258  upper.pop_back();
2259 
2260  a_hull = lower;
2261  a_hull.insert(a_hull.end(), upper.begin(), upper.end());
2262 } // gmGetConvexHull
2263 
2264 } // namespace xms
2265 
2266 //----- Tests ------------------------------------------------------------------
2267 
2268 #ifdef CXX_TEST
2269 
2270 //#include <RunTest.h>
2271 
2272 #include <boost/timer/timer.hpp>
2273 
2274 #include <xmscore/testing/TestTools.h>
2276 #include <xmsgrid/geometry/geoms.t.h>
2277 #include <xmscore/misc/XmLog.h>
2278 
2279 //----- Namespace declaration --------------------------------------------------
2280 
2281 // namespace xms {
2282 
2289 //------------------------------------------------------------------------------
2291 //------------------------------------------------------------------------------
2293 : m_outPoly()
2294 , m_inPoly()
2295 , m_timer()
2296 , m_count(0)
2297 , m_status(XM_NODATA)
2298 {
2299 } // GmPointInPolyUnitTests::GmPointInPolyUnitTests
2300 //------------------------------------------------------------------------------
2302 //------------------------------------------------------------------------------
2304 {
2305  Setup();
2306  CheckPoints();
2307  GetResults();
2308 } // GmPointInPolyUnitTests::DoTest
2309 //------------------------------------------------------------------------------
2311 //------------------------------------------------------------------------------
2313 {
2315 } // GmPointInPolyUnitTests::Setup
2316 //------------------------------------------------------------------------------
2318 //------------------------------------------------------------------------------
2320 {
2321  xms::Pt3d pt;
2322  const double xStart = -5;
2323  const double xEnd = 55;
2324  const double yStart = 35;
2325  const double yEnd = -5;
2326  const double kIncrement = 1e-1;
2327  m_timer.start();
2328  for (double y = yStart; y >= yEnd; y -= kIncrement)
2329  {
2330  for (double x = xStart; x <= xEnd; x += kIncrement)
2331  {
2332  pt.Set(x, y, 0);
2333  CheckPoint(pt);
2334  ++m_count;
2335  }
2336  }
2337 } // GmPointInPolyUnitTests::CheckPoints
2338 //--------------------------------------------------------------------------
2340 //--------------------------------------------------------------------------
2342 {
2343  // Using elapsed user + system time, not wall clock time, so this should be
2344  // similar on other computers. "For a production process, the wall clock
2345  // time may be what is most important. To study the efficiency of code,
2346  // total CPU time (user + system) is often a much better measure."
2347  // http://www.boost.org/doc/libs/1_59_0/libs/timer/doc/cpu_timers.html
2348 
2349  // Get elapsed user + system time, not wall clock time
2350  boost::timer::cpu_times const elapsed_times(m_timer.elapsed());
2351  boost::timer::nanosecond_type time = elapsed_times.system + elapsed_times.user;
2352 
2353  // convert nanoseconds to seconds
2354  const double NANO_PER_SEC = 1e9;
2355  double seconds = time / NANO_PER_SEC;
2356 
2357  // Make sure we checked a bunch of points
2358  int const kCountTotal = 240000;
2359  TS_ASSERT_EQUALS(m_count, kCountTotal);
2360 
2361  // For speed tests we don't check correctness of every point. We just
2362  // make sure m_status has changed.
2363  TS_ASSERT(m_status != XM_NODATA);
2364 
2365  // Check that the time is below a max time and write the time to the log
2366  // so we can check this in release.
2367  TS_ASSERT(seconds < MaxTime());
2368  XM_LOG(xmlog::debug, std::to_string((long long)seconds));
2369 } // GmPointInPolyUnitTests::GetResults
2370 
2374 {
2375 public:
2376  //----------------------------------------------------------------------------
2378  //----------------------------------------------------------------------------
2381  {
2382  }
2383 
2384 private:
2385  //----------------------------------------------------------------------------
2388  //----------------------------------------------------------------------------
2389  virtual void CheckPoint(const xms::Pt3d& a_pt) override
2390  {
2393  int outer = xms::gmPointInPolygon2D(&m_outPoly[0], m_outPoly.size(), a_pt);
2394  int inner = xms::gmPointInPolygon2D(&m_inPoly[0], m_inPoly.size(), a_pt);
2395  if (outer == 1 && inner == -1)
2396  {
2397  m_status = 1; // in
2398  }
2399  else if (outer == -1 || inner == 1)
2400  {
2401  m_status = 0; // completely out or in the hole
2402  }
2403  else if (outer == 0 || inner == 0)
2404  {
2405  m_status = 2; // on the outer poly or the inner poly
2406  }
2407  } // CheckPoint
2408  //----------------------------------------------------------------------------
2411  //----------------------------------------------------------------------------
2412  virtual double MaxTime() override
2413  {
2414  // It takes .09 - .17 seconds on my machine in release.
2415  return 0.5;
2416  // Hopefully big enough for the tests to pass on all machines but give us
2417  // an error if it starts going a lot slower for some reason.
2418  } // MaxTime
2419 
2420 private:
2423 }; // GmPointInPolyTester_gmPointInPolygon2D
2424 
2429 //------------------------------------------------------------------------------
2432 //------------------------------------------------------------------------------
2433 // virtual
2434 // const CxxTest::TestGroup& GeomsXmsngUnitTests::group ()
2435 //{
2436 // return *CxxTest::TestGroup::GetGroup(CxxTest::TG_INTERMEDIATE);
2437 //} // GeomsXmsngUnitTests::group
2438 //------------------------------------------------------------------------------
2441 // 10 *------*
2442 // | |
2443 // | *
2444 // | |
2445 // 0 *------*
2446 // 0 10
2448 //------------------------------------------------------------------------------
2450 {
2451  using xms::Pt3d;
2452 
2453  // 10 *------*
2454  // | |
2455  // | *
2456  // | |
2457  // 0 *------*
2458  // 0 10
2459 
2460  std::vector<Pt3d> points{{0, 0, 0}, {10, 0, 0}, {10, 5, 0}, {10, 10, 0}, {0, 10, 0}};
2461  const double kDelta = 1e-5;
2462  TS_ASSERT_DELTA_PT3D(xms::gmComputeCentroid(points), Pt3d(6, 5, 0), kDelta);
2463  // Notice the 6 above means it's not the centroid, but the average
2464 } // GeomsXmsngUnitTests::test_gmComputeCentroid
2465 //------------------------------------------------------------------------------
2468 // 10 *------*
2469 // | |
2470 // | *
2471 // | |
2472 // 0 *------*
2473 // 0 10
2475 //------------------------------------------------------------------------------
2477 {
2478  using xms::Pt3d;
2479 
2480  std::vector<Pt3d> points{{0, 0, 0}, {10, 0, 0}, {10, 5, 0}, {10, 10, 0}, {0, 10, 0}};
2481  const double kDelta = 1e-5;
2482  TS_ASSERT_DELTA_PT3D(xms::gmComputePolygonCentroid(points), Pt3d(5, 5, 0), kDelta);
2483 } // GeomsXmsngUnitTests::test_gmComputePolygonCentroid
2484 //------------------------------------------------------------------------------
2488 // 30 - 45--44 41--40 37--36 33--32 29------28
2489 // | | | | | | | | | | |
2490 // 25 - 46 43--42 39--38 35--34 31--30 26--27
2491 // | | |
2492 // 20 - 47---48 2---3---4---5---6---7---8 25--24
2493 // | | | | |
2494 // 15 - 50---49 1 18---17 14---13 10---9 22--23
2495 // | | | | | | | | |
2496 // 10 - 51 0---19 16---15 12---11 21--20
2497 // | | |
2498 // 5 - 52 2---3 6---7 10--11 14--15 18--19
2499 // | | | | | | | | | | |
2500 // 0 - 0---1 4---5 8---9 12--13 16--17
2501 //
2502 // |---|---|---|---|---|---|---|---|---|---|
2503 // 0 5 10 15 20 25 30 35 40 45 50 55
2505 //------------------------------------------------------------------------------
2507 {
2508 #ifndef _DEBUG
2510  tester.DoTest();
2511 #endif
2512 } // GeomsXmsngUnitTests::test_gmPointInPolygon2D_Speed
2513 //------------------------------------------------------------------------------
2515 //------------------------------------------------------------------------------
2517 {
2518  using namespace xms;
2519  VecPt3d inputPoints;
2520  VecPt3d expectedHull;
2521  VecPt3d hull;
2522  // Pyramid
2523  expectedHull = {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 1.0, 0.0}, {0.0, 1.0, 0.0}};
2524  for (int i = 0; i < 2; ++i)
2525  {
2526  for (int j = 0; j < 2; ++j)
2527  {
2528  inputPoints.push_back(Pt3d(i, j));
2529  }
2530  }
2531  inputPoints.push_back(Pt3d(.5, .5));
2532  gmGetConvexHull(inputPoints, hull);
2533  TS_ASSERT_EQUALS(expectedHull, hull);
2534 
2535  // bounds test
2536  expectedHull.clear();
2537  inputPoints.clear();
2538  gmGetConvexHull(inputPoints, hull);
2539  TS_ASSERT_EQUALS(expectedHull, hull);
2540 } // GeomsXmsngUnitTests::TestConvexHull
2541 //------------------------------------------------------------------------------
2543 //------------------------------------------------------------------------------
2545 {
2546  using namespace xms;
2547  // Test 1 Segments do not intersect
2548  {
2549  Pt3d point1(1, 2);
2550  Pt3d point2(1, 4);
2551  Pt3d point3(2, 1);
2552  Pt3d point4(4, 1);
2553  bool expected = false;
2554  TS_ASSERT_EQUALS(expected, gmLinesCross(point1, point2, point3, point4));
2555  }
2556  // Test 2 Segments that do intersect (generic)
2557  {
2558  Pt3d point1(2, 2);
2559  Pt3d point2(4, 4);
2560  Pt3d point3(2, 4);
2561  Pt3d point4(4, 2);
2562  bool expected = true;
2563  TS_ASSERT_EQUALS(expected, gmLinesCross(point1, point2, point3, point4));
2564  }
2565  // Test 3 Colinear
2566  {
2567  Pt3d point1(1, 5);
2568  Pt3d point2(1, 8);
2569  Pt3d point3(1, 5);
2570  Pt3d point4(1, 8);
2571  bool expected = true;
2572  TS_ASSERT_EQUALS(expected, gmLinesCross(point1, point2, point3, point4));
2573  }
2574  // Test 4 T intersection (false because it does not cross)
2575  {
2576  Pt3d point1(6, 2);
2577  Pt3d point2(6, 4);
2578  Pt3d point3(5, 4);
2579  Pt3d point4(7, 4);
2580  bool expected = false;
2581  TS_ASSERT_EQUALS(expected, gmLinesCross(point1, point2, point3, point4));
2582  }
2583  // Test 5 L intersection (which is allowed for valid shapes, so return false)
2584  {
2585  Pt3d point1(2, 5);
2586  Pt3d point2(2, 8);
2587  Pt3d point3(2, 8);
2588  Pt3d point4(4, 8);
2589  bool expected = false;
2590  TS_ASSERT_EQUALS(expected, gmLinesCross(point1, point2, point3, point4));
2591  }
2592  // Test 6 Near miss
2593  {
2594  Pt3d point1(5, 5);
2595  Pt3d point2(7, 5);
2596  Pt3d point3(5, 6);
2597  Pt3d point4(5, 8);
2598  bool expected = false;
2599  TS_ASSERT_EQUALS(expected, gmLinesCross(point1, point2, point3, point4));
2600  }
2601 } // GeomsXmsngUnitTests::testDoLineSegmentsCross
2602 
2607 //------------------------------------------------------------------------------
2610 // 15 - 0 1 2 3 4
2611 // |
2612 // 10 - 5 6---7---8 9
2613 // | | |
2614 // 5 - 10 11 12 13 14
2615 // | | |
2616 // 0 - 15 16--17--18 19
2617 // |
2618 // -15- 20 21 22 23 24
2619 //
2620 // |---|---|---|---|
2621 // -5 0 5 10 15
2623 //------------------------------------------------------------------------------
2625 {
2626  using xms::Pt3d;
2628 
2629  // CCW, first point not repeated. We also test it CW below.
2630  xms::VecPt3d poly{{0, 0, 0}, {5, 0, 0}, {10, 0, 0}, {10, 5, 0}, {10, 10, 0}, {0, 10, 0}};
2631  for (size_t i = 0; i < 2; ++i)
2632  {
2633  if (i == 1)
2634  {
2635  // Make it CW and recheck
2636  std::reverse(poly.begin(), poly.end());
2637  }
2638  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(-5, 15, 0)), -1); // 0
2639  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(0, 15, 0)), -1); // 1
2640  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(5, 15, 0)), -1); // 2
2641  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(10, 15, 0)), -1); // 3
2642  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(15, 15, 0)), -1); // 4
2643  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(-5, 10, 0)), -1); // 5
2644  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(0, 10, 0)), 0); // 6
2645  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(5, 10, 0)), 0); // 7
2646  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(10, 10, 0)), 0); // 8
2647  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(15, 10, 0)), -1); // 9
2648  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(-5, 5, 0)), -1); // 10
2649  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(0, 5, 0)), 0); // 11
2650  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(5, 5, 0)), 1); // 12
2651  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(10, 5, 0)), 0); // 13
2652  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(15, 5, 0)), -1); // 14
2653  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(-5, 0, 0)), -1); // 15
2654  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(0, 0, 0)), 0); // 16
2655  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(5, 0, 0)), 0); // 17
2656  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(10, 0, 0)), 0); // 18
2657  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(15, 0, 0)), -1); // 19
2658  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(-5, -5, 0)), -1); // 20
2659  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(0, -5, 0)), -1); // 21
2660  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(5, -5, 0)), -1); // 22
2661  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(10, -5, 0)), -1); // 23
2662  TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(), Pt3d(15, -5, 0)), -1); // 24
2663  }
2664 } // GeomsXmsngIntermediateTests::test_gmPointInPolygon2D
2665 
2666 #endif
virtual void Setup()
Setup the polygons.
Definition: geoms.cpp:2312
void testConvexHull()
Test building a convex hull.
Definition: geoms.cpp:2516
double gmMiddleZ(const VecPt3d &a_points)
Returns the z value halfway between the max and min z. Different from the average z (where many point...
Definition: geoms.cpp:153
For testing point in polygon speed.
Definition: geoms.cpp:2373
bool gmOnLineWithTol(const Pt3d &p1, const Pt3d &p2, const double x, const double y, const double tol)
Determines if a point (x,y) is on the line defined by p1 and p2. Assumes p1 and p2 aren&#39;t the same...
Definition: geoms.cpp:732
double gmZTol(bool a_set, double a_value)
Get or set (set first time) global z tolerance for float operations.
Definition: geoms.cpp:1292
bool gmInsideOfLineWithTol(const Pt3d &a_vertex1, const Pt3d &a_vertex2, const Pt3d &a_oppositevertex, const double a_x, const double a_y, const double a_tol)
Returns TRUE if the Point on the same side of the line (defined by vertex1 and vertex2) as oppositeve...
Definition: geoms.cpp:1782
#define TS_ASSERT_DELTA_PT3D(a, b, delta)
#define XM_LOG(A, B)
double gmBisectingAngle(const Pt3d &a_p1, const Pt3d &a_p2, const Pt3d &a_p3)
Returns the angle (0-2pi) which bisects the edges p2-p1 and p2-p3 based on a ccw rotation from edge 1...
Definition: geoms.cpp:1901
std::vector< int > VecInt
template int gmPointInPolygon2D< Pt2d >(const Pt2d *a_verts, const size_t a_num, const double a_x, const double a_y, const double a_tol)
void gmOrderPointsCounterclockwise(const VecPt3d &a_pts, VecInt &a_ccwOrder, int a_startindex)
Orders array of points counter clockwise. Given non-empty array of points. array of point indices ord...
Definition: geoms.cpp:1635
virtual void GetResults()
Get the timer results and do some assertions.
Definition: geoms.cpp:2341
double gmXyDistance(double x1, double y1, double x2, double y2)
Compute the 2d distance between 2 points.
Definition: geoms.cpp:832
bool gmOnLineAndBetweenEndpointsWithTol(const Pt3d &a_pt1, const Pt3d &a_pt2, const double a_x, const double a_y, double a_tol)
determines if (x,y) is on the line passing through p1 & p2 and between p1 & p2.
Definition: geoms.cpp:767
Functions dealing with triangles.
virtual double MaxTime()=0
std::vector< double > VecDbl
virtual double MaxTime() override
Maximum time test should take.
Definition: geoms.cpp:2412
bool gmPointInTriangleWithTol(const Pt3d *p1, const Pt3d *p2, const Pt3d *p3, double x, double y, double tol)
Returns true if (x,y) is in the tri formed by p1, p2, p3.
Definition: geoms.cpp:1423
PtInOutOrOn_enum gmPtInCircumcircle(const Pt3d &pt, Pt3d circumcirclePts[3])
Is a given point inside a circumcircle defined by three points?
Definition: geoms.cpp:172
template int gmPointInPolygon2D< Pt3d >(const Pt3d *a_verts, const size_t a_num, const double a_x, const double a_y, const double a_tol)
virtual void CheckPoint(const xms::Pt3d &a_pt)=0
double gmPerpendicularAngle(const Pt3d &a_pt1, const Pt3d &a_pt2)
Returns the angle in radians perpendicular to the two points.
Definition: geoms.cpp:1874
bool gmEqualPointsXY(double x1, double y1, double x2, double y2, double tolerance)
Returns true if the points are equal to within gmXyTol().
Definition: geoms.cpp:1308
Turn_enum gmTurn(const Pt3d &a_v1, const Pt3d &a_v2, const Pt3d &a_v3, double a_angtol)
Determine if angle a_v1, a_v2, a_v3 is a left turn, a right turn, colinear 180 degrees, or colinear 0 degrees.
Definition: geoms.cpp:863
double gmAngleBetween2DVectors(double dxp, double dyp, double dxn, double dyn)
Returns the angle (0-2PI) in radians between the edges p and n based on a ccw rotation from p to n...
Definition: geoms.cpp:603
bool gmIntersectLineSegmentsWithTol(const Pt3d &one1, const Pt3d &one2, const Pt3d &two1, const Pt3d &two2, double *xi, double *yi, double *zi1, double *zi2, double tol)
Intersects the plan projection of two line segments.
Definition: geoms.cpp:420
on
Definition: geoms.h:40
void gmGetConvexHull(const VecPt3d &a_pts, VecPt3d &a_hull, bool a_includeOn)
Calculate convex hull using Monotone chain aka Andrew&#39;s algorithm.
Definition: geoms.cpp:2211
virtual void CheckPoint(const xms::Pt3d &a_pt) override
Determine if a point is in or out.
Definition: geoms.cpp:2389
turns back on same segment
Definition: geoms.h:32
static void SetUpPolyWithHole(xms::VecPt3d &a_outPoly, xms::VecPt3d &a_inPolys)
Used in tests to create a polygon with lots of segments and 2 holes.
Definition: GmPolygon.cpp:624
void gmEnvelopeOfPts(const VecPt3d &a_pts, Pt3d &a_min, Pt3d &a_max)
Calculates the envelope of a vector of points.
Definition: geoms.cpp:1606
Pt2< double > Pt2d
boost::timer::cpu_timer m_timer
Timer.
Definition: geoms.t.h:65
_T Mfabs(_T a)
PtInOutOrOn_enum
point in, out, or on
Definition: geoms.h:36
Pt3d gmCreateVector(const Pt3d &a_p1, const Pt3d &a_p2)
creates a vector from a_p1 to a_p2
Definition: geoms.cpp:1982
#define XM_ZERO_TOL
bool gmInsideOrOnLineWithTol(const Pt3d *p1, const Pt3d *p2, const Pt3d *inpoint, const double x, const double y, const double tol, double *dist)
Returns true if the (x,y) is on the line segment (p1,p2) or on the same side of the line as "inpoint"...
Definition: geoms.cpp:1450
bool gmColinearWithTol(const Pt3d &p1, const Pt3d &p2, const Pt3d &p3, const double tol)
Returns true if (the three vertices are gmColinear. Result should be insensitive to the order of the ...
Definition: geoms.cpp:393
double gmPtDistanceAlongSegment(const Pt3d &a_pt1, const Pt3d &a_pt2, const Pt3d &a_pt, const double a_tol)
Finds the distance along a segment for the location closest to a_pt.
Definition: geoms.cpp:1749
turn right
Definition: geoms.h:30
double gmAngleBetweenEdges(const Pt3d &p1, const Pt3d &p2, const Pt3d &p3)
Returns the ccw angle (0-2pi) between p2-p1 and p2-p3.
Definition: geoms.cpp:655
int m_status
Status (in, out, on) of at least one pt.
Definition: geoms.t.h:67
VecPt3d gmArrayToVecPt3d(double *a_array, int a_size)
Useful in testing to create a VecPt3d from a C array of xy pairs.
Definition: geoms.cpp:1590
void DoTest()
Run the test. This is the main function to call.
Definition: geoms.cpp:2303
double gmPolygonArea(const Pt3d *pts, size_t npoints)
Compute 2d planview projection of area of polygon.
Definition: geoms.cpp:1537
void gmCalculateNormalizedPlaneCoefficients(const Pt3d &p1, const Pt3d &p2, const Pt3d &p3, double *a, double *b, double *c, double *d)
Calculates the plane coefficients for a triangle. Given point references calculate coefficents for pl...
Definition: geoms.cpp:105
bool gmLinesIntersect(const Pt3d &one1, const Pt3d &one2, const Pt3d &two1, const Pt3d &two2)
intersects the plan projection of two line segments (bad func name) segment 1 = one1,one2 = one1 + lambda(one2 - one1) segment 2 = two1,two2 = two1 + mu (two2 - two1)
Definition: geoms.cpp:966
Functions dealing with geometry.
bool GTEQ_TOL(_T A, _U B, _V tol)
void gmComponentMagnitudes(double *a_x, double *a_y, double *a_mag, double *a_dir, bool a_tomagdir)
converts the magnitude and angle to xy components or vice versa
Definition: geoms.cpp:1941
double gmComputeDeviationInDirection(const Pt3d &a_p0, const Pt3d &a_p1, const Pt3d &a_p2)
Computes the deviation in direction from one seg to next seg 1 is from a_p0 to a_p1 seg 2 is from a_p...
Definition: geoms.cpp:697
double trArea(const Pt3d &a_pt1, const Pt3d &a_pt2, const Pt3d &a_pt3)
Return the signed planar area of the triangle (CCW Positive).
Definition: triangles.cpp:46
#define XM_ENSURE_TRUE(...)
void gmCross3D(const Pt3d &a_vec1, const Pt3d &a_vec2, Pt3d *a_vec3)
Perform a cross product of Pt3d&#39;s.
Definition: geoms.cpp:2034
double gmComputeXyTol(const Pt3d &a_mn, const Pt3d &a_mx)
Given extents (min, max), compute a tolerance for the xy plane to be used with geometric functions...
Definition: geoms.cpp:1262
#define XM_ENSURE_TRUE_VOID_NO_ASSERT(...)
GmPointInPolyUnitTests()
constructor
Definition: geoms.cpp:2292
_T sqr(const _T x)
Pt3d gmComputeCentroid(const VecPt3d &a_points)
Computes the centroid of points (but not of a polygon). Shouldn&#39;t pass an empty vector (no checks are...
Definition: geoms.cpp:895
double gm2DDistanceToLineWithTol(const Pt3d *a_pt1, const Pt3d *a_pt2, double a_x, double a_y, double a_tol)
return the xy distance from (a_x,a_y) to line through (a_pt1, a_pt2)
Definition: geoms.cpp:2177
#define XM_NODATA
_T Mmax(_T a, _U b)
double gmXyTol(bool a_set, double a_value)
Get or set (set first time) global xy tolerance for float operations.
Definition: geoms.cpp:1279
double gmConvertAngleToBetween0And360(double a_angle, bool a_InDegrees)
given an angle, this function will return the corresponding angle that matches it in the range of 0 d...
Definition: geoms.cpp:1997
bool gmCircumcircleWithTol(const Pt3d *pt1, const Pt3d *pt2, const Pt3d *pt3, double *xc, double *yc, double *r2, double tol)
Computes center & radius squared for circumcircle of triangle made by the three points.
Definition: geoms.cpp:218
double gmCross2D(const double &dx1, const double &dy1, const double &dx2, const double &dy2)
Returns the cross product of two 2-d vectors.
Definition: geoms.cpp:579
void test_gmPointInPolygon2D_Speed()
Test lots of points for timing purposes. Only in release, not debug.
Definition: geoms.cpp:2506
#define XM_DISALLOW_COPY_AND_ASSIGN(TypeName)
bool EQ_TOL(const _T &A, const _U &B, const _V &tolerance)
error
Definition: geoms.h:37
Pt3< double > Pt3d
double gmFindClosestPtOnSegment(const Pt3d &a_pt1, const Pt3d &a_pt2, const Pt3d &a_pt, Pt3d &a_newpt, const double a_tol)
Finds the closest point to another point on a segment.
Definition: geoms.cpp:1714
void test_gmComputePolygonCentroid()
Definition: geoms.cpp:2476
bool gmEqualPointsXYZ(double x1, double y1, double z1, double x2, double y2, double z2, double tolerance)
Returns true if the points are equal to within tolerance.
Definition: geoms.cpp:1376
XMS Namespace.
Definition: geoms.cpp:34
Pt2< int > Pt2i
bool LT_TOL(_T A, _U B, _V tolerance)
out
Definition: geoms.h:39
turn left
Definition: geoms.h:29
int m_count
Number of points checked.
Definition: geoms.t.h:66
#define XM_SUCCESS
std::vector< xms::Pt3d > m_inPoly
Input polygon.
Definition: geoms.t.h:64
virtual void CheckPoints()
Check a lot of points to see if they are in the polys.
Definition: geoms.cpp:2319
bool gmLinesCross(const Pt3d &a_segment1Point1, const Pt3d &a_segment1Point2, const Pt3d &a_segment2Point1, const Pt3d &a_segment2Point2)
Determine whether 2 line segments cross. The segments may touch at the end points.
Definition: geoms.cpp:1013
Used for speed tests of various point in poly functions / classes.
Definition: geoms.t.h:42
#define XM_PI
int gmIntersectTriangleAndLineSegment(const Pt3d &a_pt1, const Pt3d &a_pt2, const Pt3d &a_t0, const Pt3d &a_t1, const Pt3d &a_t2, Pt3d &a_IntersectPt)
Determine if the line (described by a_pt1 and a_pt2) intersects the triangle (a_t0, a_t1, a_t2).
Definition: geoms.cpp:2075
Turn_enum
direction of turn between 3 points
Definition: geoms.h:28
bool gmPointInOrOnBox2d(const Pt3d &a_bMin, const Pt3d &a_bMax, const Pt3d &a_pt)
finds if a point is in or on a box in 2d
Definition: geoms.cpp:65
void gmAddToExtents(const Pt3d &a_pt, Pt3d &a_min, Pt3d &a_max)
Compares a_pt to a_min and a_max. If a_pt is less than a_min or greater than a_max, a_min and a_max are updated.
Definition: geoms.cpp:787
bool gmCounterClockwiseTri(const Pt3d &vtx0, const Pt3d &vtx1, const Pt3d &vtx2)
Returns true if the triangle is wrapped counter clockwise.
Definition: geoms.cpp:564
double gmDot3D(const Pt3d &a_vec1, const Pt3d &a_vec2)
Perform a dot product of Pt3d&#39;s.
Definition: geoms.cpp:2048
void test_gmComputeCentroid()
Definition: geoms.cpp:2449
_T Mmin(_T a, _U b)
int gmPointInPolygon2D(const VecPt3d &a_verts, const Pt3d &a_pt)
Definition: geoms.cpp:1209
bool gmBoxesOverlap2d(const Pt3d &a_b1Min, const Pt3d &a_b1Max, const Pt3d &a_b2Min, const Pt3d &a_b2Max)
finds if 2 boxes overlap in 2d
Definition: geoms.cpp:79
continue onward
Definition: geoms.h:31
void gmExtents2D(const VecPt3d &a_points, Pt2d &a_min, Pt2d &a_max)
Get the 2D extents of a vector of points.
Definition: geoms.cpp:1821
int gmPointInPolygon2D(const T *a_verts, const size_t a_num, const double a_x, const double a_y, const double a_tol)
Determines whether (a_x, a_y) is inside=1, on=0, or outside=-1 the polygon defined by the given verti...
Definition: geoms.cpp:1057
int gmCartToBary(const Pt3d *cart, const Pt3d *orig, double coef[6], int dir, Pt3d *bary)
Compute Barycentric coords for point. Use gmBaryPrepare to get the coefficients and direction...
Definition: geoms.cpp:275
int gmBaryPrepare(const Pt3d *p1, const Pt3d *p2, const Pt3d *p3, const Pt3d *norm, Pt3d *orig, double coef[6], int *dir, bool flag)
For a tri - compute dir & coefs to compute Barycentric coords.
Definition: geoms.cpp:315
template int gmPointInPolygon2D< Pt2i >(const Pt2i *a_verts, const size_t a_num, const double a_x, const double a_y, const double a_tol)
std::vector< xms::Pt3d > m_outPoly
Output polygon.
Definition: geoms.t.h:63
void gmExtents3D(const VecPt3d &a_points, Pt3d &a_min, Pt3d &a_max)
Get the 3D extents of a vector of points.
Definition: geoms.cpp:1856
in
Definition: geoms.h:38
Pt3d gmComputePolygonCentroid(const VecPt3d &pts)
Computes the plan view centroid of a non-self-intersecting polygon.
Definition: geoms.cpp:908
GmPointInPolyTester_gmPointInPolygon2D()
Constructor.
Definition: geoms.cpp:2379
bool GT_TOL(_T A, _U B, _V tolerance)
void testDoLineSegmentsCross()
Test determining if two lines intersect.
Definition: geoms.cpp:2544
double gmXyDistanceSquared(const Pt3d &pt1, const Pt3d &pt2)
Calculate XY distance between two 3D points.
Definition: geoms.cpp:202
std::vector< Pt3d > VecPt3d