52 bool gmPointInOrOnBox2d(
const Pt3d& a_bMin,
const Pt3d& a_bMax,
const Pt3d& a_pt)
54 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)
66 bool gmBoxesOverlap2d(
const Pt3d& a_b1Min,
71 if (a_b1Max.x < a_b2Min.x)
73 if (a_b1Min.x > a_b2Max.x)
75 if (a_b1Max.y < a_b2Min.y)
77 if (a_b1Min.y > a_b2Max.y)
92 void gmCalculateNormalizedPlaneCoefficients(
const Pt3d& p1,
101 gmCalculateNormalizedPlaneCoefficients(&p1, &p2, &p3, a, b, c, d);
114 void gmCalculateNormalizedPlaneCoefficients(
const Pt3d* p1,
122 double x1(p1->x), y1(p1->y), z1(p1->z);
123 double x2(p2->x), y2(p2->y), z2(p2->z);
124 double x3(p3->x), y3(p3->y), z3(p3->z);
125 *a = (y1 * (z2 - z3) + y2 * (z3 - z1) + y3 * (z1 - z2));
126 *b = (z1 * (x2 - x3) + z2 * (x3 - x1) + z3 * (x1 - x2));
127 *c = (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2));
128 double mag(sqrt((*a) * (*a) + (*b) * (*b) + (*c) * (*c)));
132 *d = -(*a) * x1 - (*b) * y1 - (*c) * z1;
140 double gmMiddleZ(
const VecPt3d& a_points)
145 for (
size_t i = 0; i < a_points.size(); ++i)
147 double z = a_points[i].z;
148 zmin = std::min(zmin, z);
149 zmax = std::max(zmax, z);
151 return (zmin + zmax) / 2.0;
159 PtInOutOrOn_enum gmPtInCircumcircle(
const Pt3d& pt,
Pt3d circumcirclePts[3])
163 if (!gmCircumcircleWithTol(&circumcirclePts[0], &circumcirclePts[1], &circumcirclePts[2], &xc,
164 &yc, &r2, gmXyTol()))
169 double delta = sqrt(r2) - sqrt(
sqr(pt.x - xc) +
sqr(pt.y - yc));
170 if (fabs(delta) > gmXyTol())
172 if (delta > gmXyTol())
189 double gmXyDistanceSquared(
const Pt3d& pt1,
const Pt3d& pt2)
191 return (
sqr(pt1.x - pt2.x) +
sqr(pt1.y - pt2.y));
205 bool gmCircumcircleWithTol(
const Pt3d* pt1,
214 double det11, det12, det13, det21, det22, det23;
217 det11 = pt1->x - pt2->x;
218 det12 = pt1->y - pt2->y;
219 det13 = det11 * (pt1->x + pt2->x) / 2.0 + det12 * (pt1->y + pt2->y) / 2.0;
221 det21 = pt3->x - pt2->x;
222 det22 = pt3->y - pt2->y;
223 det23 = det21 * (pt3->x + pt2->x) / 2.0 + det22 * (pt3->y + pt2->y) / 2.0;
225 determinate = det11 * det22 - det12 * det21;
227 if (fabs(determinate) < tol)
247 *xc = (det13 * det22 - det23 * det12) / determinate;
248 *yc = (det11 * det23 - det21 * det13) / determinate;
249 *r2 =
sqr(pt1->x - *xc) +
sqr(pt1->y - *yc);
262 int gmCartToBary(
const Pt3d* cart,
const Pt3d* orig,
double coef[6],
int dir,
Pt3d* bary)
265 x = cart->x - orig->x;
266 y = cart->y - orig->y;
267 z = cart->z - orig->z;
272 bary->x = coef[0] * y + coef[1] * z + coef[2];
273 bary->y = coef[3] * y + coef[4] * z + coef[5];
274 bary->z = 1.0 - bary->x - bary->y;
277 bary->x = coef[0] * z + coef[1] * x + coef[2];
278 bary->y = coef[3] * z + coef[4] * x + coef[5];
279 bary->z = 1.0 - bary->x - bary->y;
282 bary->x = coef[0] * x + coef[1] * y + coef[2];
283 bary->y = coef[3] * x + coef[4] * y + coef[5];
284 bary->z = 1.0 - bary->x - bary->y;
302 int gmBaryPrepare(
const Pt3d* p1,
311 double x1, x2, x3, y1, y2, y3, z1, z2, z3, sizeinv;
316 if (x1 > y1 && x1 > z1)
325 orig->x =
Mmin(p1->x,
Mmin(p2->x, p3->x));
326 orig->y =
Mmin(p1->y,
Mmin(p2->y, p3->y));
327 orig->z =
Mmin(p1->z,
Mmin(p2->z, p3->z));
330 x1 = p1->x - orig->x;
331 y1 = p1->y - orig->y;
332 z1 = p1->z - orig->z;
333 x2 = p2->x - orig->x;
334 y2 = p2->y - orig->y;
335 z2 = p2->z - orig->z;
336 x3 = p3->x - orig->x;
337 y3 = p3->y - orig->y;
338 z3 = p3->z - orig->z;
342 sizeinv = 1.0 / ((y2 - y3) * (z1 - z3) - (z2 - z3) * (y1 - y3));
343 coef[0] = (z3 - z2) * sizeinv;
344 coef[1] = (y2 - y3) * sizeinv;
345 coef[2] = (y3 * z2 - z3 * y2) * sizeinv;
346 coef[3] = (z1 - z3) * sizeinv;
347 coef[4] = (y3 - y1) * sizeinv;
348 coef[5] = (y1 * z3 - z1 * y3) * sizeinv;
351 sizeinv = 1.0 / ((z2 - z3) * (x1 - x3) - (x2 - x3) * (z1 - z3));
352 coef[0] = (x3 - x2) * sizeinv;
353 coef[1] = (z2 - z3) * sizeinv;
354 coef[2] = (z3 * x2 - x3 * z2) * sizeinv;
355 coef[3] = (x1 - x3) * sizeinv;
356 coef[4] = (z3 - z1) * sizeinv;
357 coef[5] = (z1 * x3 - x1 * z3) * sizeinv;
360 sizeinv = 1.0 / ((x2 - x3) * (y1 - y3) - (y2 - y3) * (x1 - x3));
361 coef[0] = (y3 - y2) * sizeinv;
362 coef[1] = (x2 - x3) * sizeinv;
363 coef[2] = (x3 * y2 - y3 * x2) * sizeinv;
364 coef[3] = (y1 - y3) * sizeinv;
365 coef[4] = (x3 - x1) * sizeinv;
366 coef[5] = (x1 * y3 - y1 * x3) * sizeinv;
380 bool gmColinearWithTol(
const Pt3d& p1,
const Pt3d& p2,
const Pt3d& p3,
const double tol)
382 if (gmOnLineWithTol(p1, p2, p3.x, p3.y, tol))
384 else if (gmOnLineWithTol(p2, p3, p1.x, p1.y, tol))
386 else if (gmOnLineWithTol(p3, p1, p2.x, p2.y, tol))
407 bool gmIntersectLineSegmentsWithTol(
const Pt3d& one1,
417 double minx1, minx2, miny1, miny2, maxx1, maxx2, maxy1, maxy2;
418 double dx1, dy1, dz1, dx2, dy2, dz2, lambda, mu, cross;
421 minx1 = std::min(one1.x, one2.x);
422 maxx2 = std::max(two1.x, two2.x);
423 if (
GT_TOL(minx1, maxx2, tol))
427 maxx1 = std::max(one1.x, one2.x);
428 minx2 = std::min(two1.x, two2.x);
429 if (
LT_TOL(maxx1, minx2, tol))
433 miny1 = std::min(one1.y, one2.y);
434 maxy2 = std::max(two1.y, two2.y);
435 if (
GT_TOL(miny1, maxy2, tol))
439 maxy1 = std::max(one1.y, one2.y);
440 miny2 = std::min(two1.y, two2.y);
441 if (
LT_TOL(maxy1, miny2, tol))
446 dx1 = one2.x - one1.x;
447 dy1 = one2.y - one1.y;
448 dz1 = one2.z - one1.z;
449 dx2 = two2.x - two1.x;
450 dy2 = two2.y - two1.y;
451 dz2 = two2.z - two1.z;
453 cross = (dx1 * dy2) -
458 if (
EQ_TOL(cross, 0.0, tol))
461 lambda = (dy2 * (two1.x - one1.x) + dx2 * (one1.y - two1.y)) / cross;
470 bool checkDistance(
false);
474 checkDistance =
true;
476 else if (lambda > 1.0)
479 checkDistance =
true;
486 if (fabs(dx2) > fabs(dy2))
487 mu = (one1.x + lambda * dx1 - two1.x) / dx2;
489 mu = (one1.y + lambda * dy1 - two1.y) / dy2;
496 checkDistance =
true;
501 checkDistance =
true;
505 Pt3d lambdapos = one1 +
Pt3d(lambda * dx1, lambda * dy1, lambda * dz1);
506 Pt3d mupos = two1 +
Pt3d(mu * dx2, mu * dy2, mu * dz2);
509 if (!gmEqualPointsXY(lambdapos, mupos, tol))
515 if (gmColinearWithTol(one1, one2, lambdapos, tol / 2) &&
516 gmColinearWithTol(two1, two2, lambdapos, tol / 2))
551 bool gmCounterClockwiseTri(
const Pt3d& vtx0,
const Pt3d& vtx1,
const Pt3d& vtx2)
553 double triarea1 = trArea(vtx0, vtx1, vtx2);
554 return (triarea1 > 0.0);
566 double gmCross2D(
const double& dx1,
const double& dy1,
const double& dx2,
const double& dy2)
568 return (dx1 * dy2) - (dx2 * dy1);
579 double gmAngleBetween2DVectors(
double dxp,
double dyp,
double dxn,
double dyn)
583 magn = sqrt(
sqr(dxn) +
sqr(dyn));
584 magp = sqrt(
sqr(dxp) +
sqr(dyp));
585 return gmAngleBetween2DVectors(dxp, dyp, dxn, dyn, magn, magp);
598 double gmAngleBetween2DVectors(
double dxp,
605 double theangle, cosign;
607 if (a_magn == 0.0 || a_magp == 0.0)
609 cosign = (dxn * dxp + dyn * dyp) / (a_magn * a_magp);
614 theangle = acos(cosign);
617 if ((dxn * dxp) + (dyn * dyp) < 0.0)
620 else if (gmCross2D(dxp, dyp, dxn, dyn) < 0.0)
621 theangle = 2 *
XM_PI - theangle;
631 double gmAngleBetweenEdges(
const Pt3d& p1,
const Pt3d& p2,
const Pt3d& p3)
633 double dxp, dyp, dxn, dyn;
639 return gmAngleBetween2DVectors(dxp, dyp, dxn, dyn);
648 double gmAngleBetweenEdges(
const Pt2d& p1,
const Pt2d& p2,
const Pt2d& p3)
650 double dxp, dyp, dxn, dyn;
656 return gmAngleBetween2DVectors(dxp, dyp, dxn, dyn);
673 double gmComputeDeviationInDirection(
const Pt3d& a_p0,
const Pt3d& a_p1,
const Pt3d& a_p2)
675 double x1, y1, x2, y2, m, cosine_dev;
676 x1 = a_p1.x - a_p0.x;
677 y1 = a_p1.y - a_p0.y;
678 x2 = a_p2.x - a_p1.x;
679 y2 = a_p2.y - a_p1.y;
680 m = sqrt(x1 * x1 + y1 * y1) * sqrt(x2 * x2 + y2 * y2);
683 cosine_dev =
Mmin((x1 * x2 + y1 * y2) / (m), 1.0);
684 cosine_dev =
Mmax(cosine_dev, -1.0);
685 return acos(cosine_dev);
708 bool gmOnLineWithTol(
const Pt3d& p1,
715 double dx = p2.x - p1.x;
716 double dy = p2.y - p1.y;
717 double mag = sqrt(
sqr(dx) +
sqr(dy));
720 return gmEqualPointsXY(p1.x, p1.y, x, y);
723 double a = -dy / mag;
725 double c = -a * p2.x - b * p2.y;
727 double d = a * x + b * y + c;
728 return fabs(d) <= tol;
743 bool gmOnLineAndBetweenEndpointsWithTol(
const Pt3d& a_pt1,
749 if ((
Mmin(a_pt1.x, a_pt2.x) - a_tol <= a_x &&
Mmax(a_pt1.x, a_pt2.x) + a_tol >= a_x) &&
750 (
Mmin(a_pt1.y, a_pt2.y) - a_tol <= a_y &&
Mmax(a_pt1.y, a_pt2.y) + a_tol >= a_y))
751 return gmOnLineWithTol(a_pt1, a_pt2, a_x, a_y, a_tol) ==
true;
763 void gmAddToExtents(
const Pt3d& a_pt,
Pt3d& a_min,
Pt3d& a_max)
765 a_min.x = std::min(a_pt.x, a_min.x);
766 a_min.y = std::min(a_pt.y, a_min.y);
767 a_min.z = std::min(a_pt.z, a_min.z);
768 a_max.x = std::max(a_pt.x, a_max.x);
769 a_max.y = std::max(a_pt.y, a_max.y);
770 a_max.z = std::max(a_pt.z, a_max.z);
778 void gmAddToExtents(
const Pt3d& a_pt,
Pt2d& a_min,
Pt2d& a_max)
780 a_min.
x = std::min(a_pt.x, a_min.
x);
781 a_min.
y = std::min(a_pt.y, a_min.
y);
782 a_max.
x = std::max(a_pt.x, a_max.
x);
783 a_max.
y = std::max(a_pt.y, a_max.
y);
791 void gmAddToExtents(
const Pt2d& a_pt,
Pt3d& a_min,
Pt3d& a_max)
793 a_min.x = std::min(a_pt.
x, a_min.x);
794 a_min.y = std::min(a_pt.
y, a_min.y);
795 a_max.x = std::max(a_pt.
x, a_max.x);
796 a_max.y = std::max(a_pt.
y, a_max.y);
808 double gmXyDistance(
double x1,
double y1,
double x2,
double y2)
810 return sqrt(
sqr(x1 - x2) +
sqr(y1 - y2));
818 double gmXyDistance(
const Pt3d& pt1,
const Pt3d& pt2)
820 return sqrt(
sqr(pt1.x - pt2.x) +
sqr(pt1.y - pt2.y));
839 Turn_enum gmTurn(
const Pt3d& a_v1,
const Pt3d& a_v2,
const Pt3d& a_v3,
double a_angtol)
842 double dx32 = a_v3.x - a_v2.x;
843 double dy32 = a_v3.y - a_v2.y;
844 double dx12 = a_v1.x - a_v2.x;
845 double dy12 = a_v1.y - a_v2.y;
846 double d32 = sqrt(dx32 * dx32 + dy32 * dy32);
847 double d12 = sqrt(dx12 * dx12 + dy12 * dy12);
848 double mag = d12 * d32;
849 double sint = (dx32 * dy12 - dx12 * dy32) / mag;
854 else if (sint < -a_angtol)
860 double cost = (dx12 * dx32 + dy12 * dy32) / mag;
862 return TURN_COLINEAR_180;
863 return TURN_COLINEAR_0;
874 size_t size = a_points.size();
875 for (
size_t i = 0; i < size; ++i)
876 centroid += a_points[i];
877 return (centroid / (
double)size);
892 for (i = 0; i < pts.size(); ++i)
896 xMax = (x > xMax) ? x : xMax;
897 yMax = (y > yMax) ? y : yMax;
898 xMin = (x < xMin) ? x : xMin;
899 yMin = (y < yMin) ? y : yMin;
901 double xOffset = (xMax + xMin) / 2.0;
902 double yOffset = (yMax + yMin) / 2.0;
904 double signedArea = 0.0;
905 for (i = 0; i < pts.size() - 1; ++i)
907 double x0 = pts[i].x - xOffset;
908 double y0 = pts[i].y - yOffset;
909 double x1 = pts[i + 1].x - xOffset;
910 double y1 = pts[i + 1].y - yOffset;
911 double a = x0 * y1 - x1 * y0;
913 centroid.x += (x0 + x1) * a;
914 centroid.y += (y0 + y1) * a;
917 double x0 = pts[i].x - xOffset;
918 double y0 = pts[i].y - yOffset;
919 double x1 = pts[0].x - xOffset;
920 double y1 = pts[0].y - yOffset;
921 double a = x0 * y1 - x1 * y0;
923 centroid.x += (x0 + x1) * a;
924 centroid.y += (y0 + y1) * a;
926 centroid.x /= (6.0 * signedArea);
927 centroid.y /= (6.0 * signedArea);
928 centroid.x += xOffset;
929 centroid.y += yOffset;
942 bool gmLinesIntersect(
const Pt3d& one1,
const Pt3d& one2,
const Pt3d& two1,
const Pt3d& two2)
945 double min = std::min(one1.x, one2.x);
946 double max = std::max(two1.x, two2.x);
947 const double tol(XM_ZERO_TOL);
948 if (
GT_TOL(min, max, tol))
950 max = std::max(one1.x, one2.x);
951 min = std::min(two1.x, two2.x);
952 if (
LT_TOL(max, min, tol))
954 min = std::min(one1.y, one2.y);
955 max = std::max(two1.y, two2.y);
956 if (
GT_TOL(min, max, tol))
958 max = std::max(one1.y, one2.y);
959 min = std::min(two1.y, two2.y);
960 if (
LT_TOL(max, min, tol))
963 Pt2d d1(one2 - one1), d2(two2 - two1);
967 double cross = (d2.x * d1.y) - (d2.y * d1.x);
971 double s = ((d1.x * (two1.y - one1.y)) + (d1.y * (one1.x - two1.x))) / cross;
975 double t = ((d2.x * (one1.y - two1.y)) + (d2.y * (two1.x - one1.x))) / cross;
994 template <
typename T>
995 int gmPointInPolygon2D(
const T* a_verts,
1001 if (a_verts && a_num)
1003 int nmleft = 0, nmrght = 0;
1004 double dy2 = fabs(a_verts[0].y - a_y);
1006 for (
size_t i = 0; i < a_num; i++)
1012 dy2 = fabs(a_verts[i2].y - a_y);
1019 if (((a_verts[i].x >= a_x) && (a_verts[i2].x <= a_x)) ||
1020 ((a_verts[i].x <= a_x) && (a_verts[i2].x >= a_x)))
1028 diff = a_verts[i].x - a_x;
1029 if (fabs(diff) <= a_tol)
1031 else if (a_verts[i].y < a_verts[i2].y)
1041 else if (dy2 <= a_tol)
1046 diff = a_verts[i2].x - a_x;
1047 if (fabs(diff) <= a_tol)
1049 else if (a_verts[i2].y < a_verts[i].y)
1058 else if (((a_verts[i].y < a_y) && (a_verts[i2].y > a_y)) ||
1059 ((a_verts[i].y > a_y) && (a_verts[i2].y < a_y)))
1063 double val = a_verts[i].x + (a_verts[i2].x - a_verts[i].x) * (a_y - a_verts[i].y) /
1064 (a_verts[i2].y - a_verts[i].y);
1066 if (fabs(diff) <= a_tol)
1074 nmleft = nmleft % 2;
1075 nmrght = nmrght % 2;
1076 if (nmleft != nmrght)
1078 else if (nmleft == 1)
1093 int gmPointInPolygon2D(
const Pt3d* a_verts,
size_t a_num,
double a_x,
double a_y)
1095 return gmPointInPolygon2D(a_verts, a_num, a_x, a_y, gmXyTol());
1104 int gmPointInPolygon2D(
const Pt3d* a_verts,
size_t a_num,
Pt3d a_pt)
1106 return gmPointInPolygon2D(a_verts, a_num, a_pt.x, a_pt.y, gmXyTol());
1115 int gmPointInPolygon2D(
const Pt2i* a_verts,
size_t a_num,
Pt2d a_pt)
1117 return gmPointInPolygon2D(a_verts, a_num, a_pt.
x, a_pt.
y, gmXyTol());
1126 int gmPointInPolygon2D(
const Pt2i* a_verts,
size_t a_num,
Pt3d a_pt)
1128 return gmPointInPolygon2D(a_verts, a_num, a_pt.x, a_pt.y, gmXyTol());
1137 int gmPointInPolygon2D(
const Pt2i* a_verts,
size_t a_num,
Pt2i a_pt)
1139 return gmPointInPolygon2D(a_verts, a_num, a_pt.x, a_pt.y, gmXyTol());
1147 int gmPointInPolygon2D(
const VecPt3d& a_verts,
const Pt3d& a_pt)
1149 return gmPointInPolygon2D(&a_verts[0], a_verts.size(), a_pt.x, a_pt.y, gmXyTol());
1160 template int gmPointInPolygon2D<Pt3d>(
const Pt3d* a_verts,
1164 const double a_tol);
1174 template int gmPointInPolygon2D<Pt2d>(
const Pt2d* a_verts,
1178 const double a_tol);
1188 template int gmPointInPolygon2D<Pt2i>(
const Pt2i* a_verts,
1192 const double a_tol);
1200 double gmComputeXyTol(
const Pt3d& a_mn,
const Pt3d& a_mx)
1202 double d = gmXyDistance(a_mn, a_mx);
1203 double const kFactor = 1e-9;
1204 double xytol = d * kFactor;
1205 if (xytol < kFactor)
1217 double gmXyTol(
bool a_set ,
double a_value )
1219 static double xytol = a_value;
1230 double gmZTol(
bool a_set,
double a_value)
1232 static double ztol = a_value;
1246 bool gmEqualPointsXY(
double x1,
double y1,
double x2,
double y2,
double tolerance)
1248 double dx = fabs(x1 - x2);
1249 double dy = fabs(y1 - y2);
1250 if (dx > tolerance || dy > tolerance)
1252 else if (sqrt(dx * dx + dy * dy) <= tolerance)
1265 bool gmEqualPointsXY(
double x1,
double y1,
double x2,
double y2)
1267 return gmEqualPointsXY(x1, y1, x2, y2, gmXyTol());
1276 bool gmEqualPointsXY(
const Pt2d& a_pt1,
const Pt2d& a_pt2,
double tol)
1278 return gmEqualPointsXY(a_pt1.
x, a_pt1.
y, a_pt2.
x, a_pt2.
y, tol);
1287 bool gmEqualPointsXY(
const Pt3d& a_pt1,
const Pt3d& a_pt2,
double tol)
1289 return gmEqualPointsXY(a_pt1.x, a_pt1.y, a_pt2.x, a_pt2.y, tol);
1297 bool gmEqualPointsXY(
const Pt2i& point1,
const Pt2i& point2)
1299 if (point1.x == point2.x && point1.y == point2.y)
1314 bool gmEqualPointsXYZ(
double x1,
1322 if ((fabs(x1 - x2) <= tolerance) && (fabs(y1 - y2) <= tolerance) && (fabs(z1 - z2) <= tolerance))
1336 bool gmEqualPointsXYZ(
double x1,
double y1,
double z1,
double x2,
double y2,
double z2)
1338 return gmEqualPointsXYZ(x1, y1, z1, x2, y2, z2, gmXyTol());
1347 bool gmEqualPointsXYZ(
const Pt3d& pt1,
const Pt3d& pt2,
double tol)
1349 return gmEqualPointsXYZ(pt1.x, pt1.y, pt1.z, pt2.x, pt2.y, pt2.z, tol);
1361 bool gmPointInTriangleWithTol(
const Pt3d* p1,
1368 if (gmInsideOrOnLineWithTol(p1, p2, p3, x, y, tol))
1369 if (gmInsideOrOnLineWithTol(p2, p3, p1, x, y, tol))
1370 if (gmInsideOrOnLineWithTol(p3, p1, p2, x, y, tol))
1388 bool gmInsideOrOnLineWithTol(
const Pt3d* p1,
1390 const Pt3d* inpoint,
1396 double dx, dy, a, b, c, mag;
1401 mag = sqrt(
sqr(dx) +
sqr(dy));
1404 return gmEqualPointsXY(p1->x, p1->y, x, y);
1410 c = -a * p1->x - b * p1->y;
1412 d1 = a * x + b * y + c;
1414 d2 = a * inpoint->x + b * inpoint->y + c;
1416 if (
Mfabs(d2) <= tol)
1425 if (
Mfabs(d1) <= tol)
1441 if ((d1 < 0.0) && (d2 < 0.0))
1449 else if ((d1 > 0.0) && (d2 > 0.0))
1475 double gmPolygonArea(
const Pt3d* pts,
size_t npoints)
1504 double x0 = pts[0].x;
1505 double y0 = pts[0].y;
1506 for (
id = 1;
id < npoints;
id++)
1508 x.push_back((pts[
id].x - x0));
1509 y.push_back((pts[
id].y - y0));
1511 for (
id = 0;
id < npoints - 2;
id++)
1513 area += (x[id] * y[
id + 1]);
1514 area -= (y[id] * x[
id + 1]);
1526 VecPt3d gmArrayToVecPt3d(
double* a_array,
int a_size)
1529 for (
int i = 0; i < a_size; i += 2)
1531 v[i / 2].x = a_array[i];
1532 v[i / 2].y = a_array[i + 1];
1544 a_min = a_max =
Pt3d();
1546 a_min = a_max = a_pts.front();
1547 for (
size_t i = 0; i < a_pts.size(); ++i)
1549 if (a_pts[i].x < a_min.x)
1550 a_min.x = a_pts[i].x;
1551 if (a_pts[i].y < a_min.y)
1552 a_min.y = a_pts[i].y;
1553 if (a_pts[i].z < a_min.z)
1554 a_min.z = a_pts[i].z;
1555 if (a_pts[i].x > a_max.x)
1556 a_max.x = a_pts[i].x;
1557 if (a_pts[i].y > a_max.y)
1558 a_max.y = a_pts[i].y;
1559 if (a_pts[i].z > a_max.z)
1560 a_max.z = a_pts[i].z;
1571 void gmOrderPointsCounterclockwise(
const VecPt3d& a_pts,
VecInt& a_ccwOrder,
int a_startindex)
1573 int numnodes = (int)a_pts.size();
1579 for (
int i = 0; i < numnodes; i++)
1585 center.
x = sumx / numnodes;
1586 center.
y = sumy / numnodes;
1590 std::vector<std::pair<float, int> > angleIndex(numnodes);
1591 for (
int i = 0; i < numnodes; i++)
1593 float angle = (float)(atan2(a_pts[i].y - center.
y, a_pts[i].x - center.
x));
1594 angleIndex[i] = std::pair<float, int>(angle, i);
1597 std::stable_sort(angleIndex.begin(), angleIndex.end());
1600 auto startIter = angleIndex.begin();
1601 while (startIter != angleIndex.end() && startIter->second != a_startindex)
1605 if (startIter == angleIndex.end())
1606 startIter = angleIndex.begin();
1609 a_ccwOrder.resize(numnodes, 0);
1611 for (
auto iter = startIter; iter != angleIndex.end(); ++iter)
1613 a_ccwOrder[j] = iter->second;
1616 for (
auto iter = angleIndex.begin(); iter != startIter; ++iter)
1618 a_ccwOrder[j] = iter->second;
1626 void gmOrderPointsCounterclockwise(
VecPt3d& a_pts)
1633 gmOrderPointsCounterclockwise(pts, ccwOrder);
1634 for (
size_t i = 0; i < ccwOrder.size(); ++i)
1636 a_pts[i] = pts[ccwOrder[i]];
1650 double gmFindClosestPtOnSegment(
const Pt3d& a_pt1,
1656 double t = gmPtDistanceAlongSegment(a_pt1, a_pt2, a_pt, a_tol);
1659 a_newpt.x = a_pt1.x;
1660 a_newpt.y = a_pt1.y;
1664 a_newpt.x = a_pt2.x;
1665 a_newpt.y = a_pt2.y;
1669 double dx = a_pt2.x - a_pt1.x;
1670 double dy = a_pt2.y - a_pt1.y;
1671 a_newpt.x = a_pt1.x + dx * t;
1672 a_newpt.y = a_pt1.y + dy * t;
1685 double gmPtDistanceAlongSegment(
const Pt3d& a_pt1,
1692 dx = a_pt2.x - a_pt1.x;
1693 dy = a_pt2.y - a_pt1.y;
1695 if ((dx == 0.0 && dy == 0.0) || (sqrt(dx * dx + dy * dy) <= a_tol))
1701 t = ((a_pt.x - a_pt1.x) * dx + (a_pt.y - a_pt1.y) * dy) / (dx * dx + dy * dy);
1718 bool gmInsideOfLineWithTol(
const Pt3d& a_vertex1,
1719 const Pt3d& a_vertex2,
1720 const Pt3d& a_oppositevertex,
1725 double dx = a_vertex2.x - a_vertex1.x;
1726 double dy = a_vertex2.y - a_vertex1.y;
1727 double mag = sqrt(
sqr(dx) +
sqr(dy));
1730 return gmEqualPointsXY(a_vertex1.x, a_vertex1.y, a_x, a_y);
1734 double a = -dy / mag;
1735 double b = dx / mag;
1736 double c = -a * a_vertex1.x - b * a_vertex1.y;
1738 double d1 = a * a_x + b * a_y + c;
1740 double d2 = a * a_oppositevertex.x + b * a_oppositevertex.y + c;
1741 if (fabs(d1) <= a_tol)
1743 else if ((d1 < 0.0) && (d2 < 0.0))
1745 else if ((d1 > 0.0) && (d2 > 0.0))
1761 a_min.
x = a_max.
x = a_points.at(0).x;
1762 a_min.
y = a_max.
y = a_points.at(0).y;
1763 for (
int i = 1; i < (int)a_points.size(); i++)
1765 gmAddToExtents(a_points[i], a_min, a_max);
1778 a_min.x = a_max.x = a_points.at(0).x;
1779 a_min.y = a_max.y = a_points.at(0).y;
1780 a_min.z = a_max.z = 0.0;
1781 for (
int i = 1; i < (int)a_points.size(); i++)
1783 gmAddToExtents((
Pt2d)a_points[i], a_min, a_max);
1796 a_min.x = a_max.x = a_points.at(0).x;
1797 a_min.y = a_max.y = a_points.at(0).y;
1798 a_min.z = a_max.z = a_points.at(0).z;
1799 for (
int i = 1; i < (int)a_points.size(); i++)
1801 gmAddToExtents(a_points[i], a_min, a_max);
1810 double gmPerpendicularAngle(
const Pt3d& a_pt1,
const Pt3d& a_pt2)
1813 double deltax, deltay, arad, theangle;
1815 deltax = a_pt1.x - a_pt2.x;
1816 deltay = a_pt1.y - a_pt2.y;
1817 hypot = sqrt(
sqr(deltax) +
sqr(deltay));
1818 arad = deltax / hypot;
1821 else if (arad < -.9999)
1824 theangle = acos(arad);
1826 theangle = 2 *
XM_PI - acos(arad);
1827 return (theangle - (XM_PI / 2));
1837 double gmBisectingAngle(
const Pt3d& a_p1,
const Pt3d& a_p2,
const Pt3d& a_p3)
1839 double dxn, dyn, dxp, dyp, magn, magp, angletoedge1, theanglebetween;
1842 dxp = a_p1.x - a_p2.x;
1843 dyp = a_p1.y - a_p2.y;
1844 dxn = a_p3.x - a_p2.x;
1845 dyn = a_p3.y - a_p2.y;
1846 angletoedge1 = atan2(dyp, dxp);
1847 magn = sqrt(
sqr(dxn) +
sqr(dyn));
1848 magp = sqrt(
sqr(dxp) +
sqr(dyp));
1849 cosign = (dxn * dxp + dyn * dyp) / (magn * magp);
1850 if (cosign > .99999)
1852 if (cosign < -.99999)
1854 theanglebetween = acos(cosign);
1855 if (theanglebetween == 0.0)
1857 if ((dxn * dxp) + (dyn * dyp) < 0.0)
1858 theanglebetween =
XM_PI;
1860 else if (gmCross2D(dxp, dyp, dxn, dyn) < 0.0)
1861 theanglebetween = 2 *
XM_PI - theanglebetween;
1862 return angletoedge1 + theanglebetween / 2.0;
1877 void gmComponentMagnitudes(
double* a_x,
double* a_y,
double* a_mag,
double* a_dir,
bool a_tomagdir)
1883 if (fabs(*a_x) < XM_ZERO_TOL && fabs(*a_y) < XM_ZERO_TOL)
1892 *a_mag = sqrt(
sqr(*a_x) +
sqr(*a_y));
1893 *a_dir = (atan(*a_y / *a_x)) * (180 / XM_PI);
1902 rads = *a_dir * (
XM_PI / 180);
1903 *a_x = cos(rads) * *a_mag;
1904 *a_y = sin(rads) * *a_mag;
1905 if (fabs(*a_x) < XM_ZERO_TOL)
1907 if (fabs(*a_y) < XM_ZERO_TOL)
1918 Pt3d gmCreateVector(
const Pt3d& a_p1,
const Pt3d& a_p2)
1921 vector.
x = a_p2.x - a_p1.x;
1922 vector.y = a_p2.y - a_p1.y;
1923 vector.z = a_p2.z - a_p1.z;
1933 double gmConvertAngleToBetween0And360(
double a_angle,
bool a_InDegrees
1936 double ang = a_angle;
1940 ang *= (180.0 /
XM_PI);
1943 #if BOOST_OS_WINDOWS
1944 while (
LT_TOL(ang, 0.0, DBL_EPSILON) && _finite(ang))
1947 while (
LT_TOL(ang, 0.0, DBL_EPSILON) && std::isfinite(ang))
1952 #if BOOST_OS_WINDOWS
1953 while (
GTEQ_TOL(ang, 360.0, DBL_EPSILON) && _finite(ang))
1956 while (
GTEQ_TOL(ang, 360.0, DBL_EPSILON) && std::isfinite(ang))
1970 void gmCross3D(
const Pt3d& a_vec1,
const Pt3d& a_vec2,
Pt3d* a_vec3)
1972 a_vec3->x = a_vec1.y * a_vec2.z - a_vec1.z * a_vec2.y;
1973 a_vec3->y = a_vec1.z * a_vec2.x - a_vec1.x * a_vec2.z;
1974 a_vec3->z = a_vec1.x * a_vec2.y - a_vec1.y * a_vec2.x;
1984 inline double gmDot3D(
const Pt3d& a_vec1,
const Pt3d& a_vec2)
1986 return (a_vec1.x * a_vec2.x + a_vec1.y * a_vec2.y + a_vec1.z * a_vec2.z);
2011 int gmIntersectTriangleAndLineSegment(
const Pt3d& a_pt1,
2016 Pt3d& a_IntersectPt)
2019 Pt3d dir, n, NullVector(0.0, 0.0, 0.0), u, v, w, w0;
2024 gmCross3D(u, v, &n);
2027 if (n == NullVector)
2033 dir = a_pt2 - a_pt1;
2035 a = -gmDot3D(n, w0);
2036 b = gmDot3D(n, dir);
2039 if (fabs(b) < XM_ZERO_TOL)
2058 if (r < -FLT_EPSILON || r > 1.0 + FLT_EPSILON)
2064 a_IntersectPt = a_pt1 + dir * r;
2067 double D, uu, uv, vv, wu, wv;
2072 w = a_IntersectPt - a_t0;
2075 D = uv * uv - uu * vv;
2080 s = (uv * wv - vv * wu) / D;
2081 if (s < 0.0 || s > 1.0)
2086 t = (uv * wu - uu * wv) / D;
2087 if (t < 0.0 || (s + t) > 1.0)
2113 double gm2DDistanceToLineWithTol(
const Pt3d* a_pt1,
2119 double a1, b1, c, mag;
2122 a1 = a_pt2->x - a_pt1->x;
2123 b1 = a_pt2->y - a_pt1->y;
2124 mag = sqrt(a1 * a1 + b1 * b1);
2128 return sqrt(
sqr(a_pt1->x - a_x) +
sqr(a_pt1->y - a_y));
2135 c = -a * a_pt1->x - b * a_pt1->y;
2137 dist = a * a_x + b * a_y + c;
2150 #include <boost/timer/timer.hpp>
2200 const double xStart = -5;
2201 const double xEnd = 55;
2202 const double yStart = 35;
2203 const double yEnd = -5;
2204 const double kIncrement = 1e-1;
2206 for (
double y = yStart; y >= yEnd; y -= kIncrement)
2208 for (
double x = xStart; x <= xEnd; x += kIncrement)
2228 boost::timer::cpu_times
const elapsed_times(
m_timer.elapsed());
2229 boost::timer::nanosecond_type time = elapsed_times.system + elapsed_times.user;
2232 const double NANO_PER_SEC = 1e9;
2233 double seconds = time / NANO_PER_SEC;
2236 int const kCountTotal = 240000;
2237 TS_ASSERT_EQUALS(
m_count, kCountTotal);
2245 TS_ASSERT(seconds <
MaxTime());
2271 int outer = xms::gmPointInPolygon2D(&m_outPoly[0], m_outPoly.size(), a_pt);
2272 int inner = xms::gmPointInPolygon2D(&m_inPoly[0], m_inPoly.size(), a_pt);
2273 if (outer == 1 && inner == -1)
2277 else if (outer == -1 || inner == 1)
2281 else if (outer == 0 || inner == 0)
2338 std::vector<Pt3d> points{{0, 0, 0}, {10, 0, 0}, {10, 5, 0}, {10, 10, 0}, {0, 10, 0}};
2339 const double kDelta = 1e-5;
2358 std::vector<Pt3d> points{{0, 0, 0}, {10, 0, 0}, {10, 5, 0}, {10, 10, 0}, {0, 10, 0}};
2359 const double kDelta = 1e-5;
2403 return *CxxTest::TestGroup::GetGroup(CxxTest::TG_INTERMEDIATE);
2427 using xms::gmPointInPolygon2D;
2430 xms::VecPt3d poly{{0, 0, 0}, {5, 0, 0}, {10, 0, 0}, {10, 5, 0}, {10, 10, 0}, {0, 10, 0}};
2431 for (
size_t i = 0; i < 2; ++i)
2436 std::reverse(poly.begin(), poly.end());
2438 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(-5, 15, 0)), -1);
2439 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(0, 15, 0)), -1);
2440 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(5, 15, 0)), -1);
2441 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(10, 15, 0)), -1);
2442 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(15, 15, 0)), -1);
2443 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(-5, 10, 0)), -1);
2444 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(0, 10, 0)), 0);
2445 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(5, 10, 0)), 0);
2446 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(10, 10, 0)), 0);
2447 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(15, 10, 0)), -1);
2448 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(-5, 5, 0)), -1);
2449 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(0, 5, 0)), 0);
2450 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(5, 5, 0)), 1);
2451 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(10, 5, 0)), 0);
2452 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(15, 5, 0)), -1);
2453 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(-5, 0, 0)), -1);
2454 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(0, 0, 0)), 0);
2455 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(5, 0, 0)), 0);
2456 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(10, 0, 0)), 0);
2457 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(15, 0, 0)), -1);
2458 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(-5, -5, 0)), -1);
2459 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(0, -5, 0)), -1);
2460 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(5, -5, 0)), -1);
2461 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(10, -5, 0)), -1);
2462 TS_ASSERT_EQUALS(gmPointInPolygon2D(&poly[0], poly.size(),
Pt3d(15, -5, 0)), -1);
virtual void Setup()
Setup the polygons.
For testing point in polygon speed.
virtual void GetResults()
Get the timer results and do some assertions.
bool GTEQ_TOL(_T A, _U B, _V tol)
static const double XM_DBL_LOWEST
bool EQ_TOL(const _T &A, const _U &B, const _V &tolerance)
Functions dealing with triangles.
virtual double MaxTime()=0
virtual double MaxTime() override
Maximum time test should take.
virtual void CheckPoint(const xms::Pt3d &a_pt)=0
virtual void CheckPoint(const xms::Pt3d &a_pt) override
Determine if a point is in or out.
bool LT_TOL(_T A, _U B, _V tolerance)
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.
boost::timer::cpu_timer m_timer
Timer.
std::vector< int > VecInt
int m_status
Status (in, out, on) of at least one pt.
void DoTest()
Run the test. This is the main function to call.
Functions dealing with geometry.
std::vector< double > VecDbl
#define XM_ENSURE_TRUE(...)
#define XM_ENSURE_TRUE_VOID_NO_ASSERT(...)
std::vector< Pt3d > VecPt3d
GmPointInPolyUnitTests()
constructor
bool GT_TOL(_T A, _U B, _V tolerance)
void test_gmPointInPolygon2D_Speed()
Test lots of points for timing purposes. Only in release, not debug.
#define XM_DISALLOW_COPY_AND_ASSIGN(TypeName)
void Set(T a_x, T a_y, T a_z)
void test_gmComputePolygonCentroid()
int m_count
Number of points checked.
std::vector< xms::Pt3d > m_inPoly
Input polygon.
virtual void CheckPoints()
Check a lot of points to see if they are in the polys.
Used for speed tests of various point in poly functions / classes.
void test_gmComputeCentroid()
std::vector< xms::Pt3d > m_outPoly
Output polygon.
GmPointInPolyTester_gmPointInPolygon2D()
Constructor.
static const double XM_DBL_HIGHEST