|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- /**
- * @file geometry.cpp
- * @author donkey (anjingyu_ws@foxmail.com)
- * @brief Implementation of basic geometry functions in \c ns::geo
- * @version 0.1.0
- * @date 2020-05-15
- *
- * @copyright Copyright (c) 2020- donkey <anjingyu_ws@foxmail.com>.
- *
- */
-
- #include "geo/geometry.h"
-
- #include <cmath> /**< std::sqrt std::fabs */
-
- namespace ns {
- namespace geo {
-
- bool Geometry::perpendicularDistanceOn(double ptX, double ptY, double startX, double startY, double endX, double endY, double *distance)
- {
- double dot = (ptX - endX) * (startX - endX) + (ptY - endY) * (startY - endY);
- double d2 = (startX - endX) * (startX - endX) + (startY - endY) * (startY - endY);
- double r = dot / d2;
- bool on = (r <= 1.0 && r >= 0.0);
-
- if (distance == nullptr)
- {
- return on;
- }
-
- if (on)
- {
- // Out of range
- if (r < 0.0 || r > 1.0)
- {
- *distance = 0.0;
- }
- else
- {
- if (startX == endX)
- {
- *distance = std::fabs(ptX - startX);
- }
- else
- {
- double lineK = (endY - startY) / (endX - startX);
- double lineC = (endX * startY - startX * endY) / (endX - startX);
- *distance = std::fabs(lineK * ptX - ptY + lineC) / (std::sqrt(lineK * lineK + 1));
- }
-
- // Get the foot of prependicular
- // double u = ((ptX - startX) * (startX - endX) + (ptY - startY) * (startY - endY)) / d2;
- // double footX = startX + u * (startX - endX);
- // double footY = startY + u * (startY - endY);
- }
- }
- else
- {
- *distance = 0.0;
- }
-
- return on;
- }
-
- bool Geometry::prependicularDistanceOn(double ptX, double ptY, double ptZ,
- double startX, double startY, double startZ,
- double endX, double endY, double endZ,
- double *distance)
- {
- double dot = (ptX - endX) * (startX - endX) + (ptY - endY) * (startY - endY) + (ptZ - endZ) * (startZ - endZ);
- double d2 = (startX - endX) * (startX - endX) + (startY - endY) * (startY - endY) + (startZ - endZ) * (startZ - endZ);
- double r = dot / d2;
- bool on = (r <= 1.0 && r >= 0.0);
-
- if (distance == nullptr)
- {
- return on;
- }
-
- if (on)
- {
- // d = (AB x AC)/|AB| S = (AB X AC) / 2 = distance * |AB| / 2
- // TODO
- }
- else
- {
- distance = 0.0;
- }
-
- return as*sin_A;
- }
-
- // Dot product of vector1(x1, y1) and vector2(x2, y2)
- // result = x1 * x2 + y1 * y2
- static inline double _dot(double x1, double y1, double x2, double y2)
- {
- return x1 * x2 + y1 * y2
- }
-
-
- // Cross product of vector1(x1, y1) and vector2(x2, y2)
- // result = x1 * y2 - x2 * y1
- static inline double _cross(double x1, double y1, double x2, double y2)
- {
- return x1 * y2 - x2 * y1
- }
-
-
- // Calculate the distance of point to line.
- //
- // vector1 (endX - startX, endY - startY)
- // vector2 (x - startX, y - startY)
- //
- // result = |vector1 X vector2| / |vector1|
- double Geometry::distancePoint2Line(x, y, startX, startY, endX, endY)
- {
- double vec1x = endX - startX;
- double vec1y = endY - startY;
-
- double vec2x = x - startX;
- double vec2y = y - startY;
-
- double dis = std::abs(_cross(vec1x, vec1y, vec2x,
- vec2y)) / std::sqrt(vec1x * vec1x + vec1y * vec1y)
-
- return dis
- }
-
- static int _getLineIntersection(float p0_x, float p0_y, float p1_x, float p1_y,
- float p2_x, float p2_y, float p3_x, float p3_y, float *i_x, float *i_y)
- {
- float s02_x, s02_y, s10_x, s10_y, s32_x, s32_y, s_numer, t_numer, denom, t;
- s10_x = p1_x - p0_x;
- s10_y = p1_y - p0_y;
- s32_x = p3_x - p2_x;
- s32_y = p3_y - p2_y;
-
- denom = s10_x * s32_y - s32_x * s10_y;
- if (denom == 0)
- return 0; // Collinear
- bool denomPositive = denom > 0;
-
- s02_x = p0_x - p2_x;
- s02_y = p0_y - p2_y;
- s_numer = s10_x * s02_y - s10_y * s02_x;
- if ((s_numer < 0) == denomPositive)
- return 0; // No collision
-
- t_numer = s32_x * s02_y - s32_y * s02_x;
- if ((t_numer < 0) == denomPositive)
- return 0; // No collision
-
- if (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive))
- return 0; // No collision
- // Collision detected
- t = t_numer / denom;
- if (i_x != NULL)
- *i_x = p0_x + (t * s10_x);
- if (i_y != NULL)
- *i_y = p0_y + (t * s10_y);
-
- return 1;
- }
-
- //find intersect
- //return value :
- //1(one intersection) 0 (parallel,no intersection) 2(same line)
- //@param point: if return value is one, point is the intersection point.
- static int _findLine2LineIntersection2D(
- const VectorD2D& p0, const VectorD2D& p1,
- const VectorD2D& p2, const VectorD2D& p3, VectorD2D& point)
- {
- const double epsilon = 1e-7;
-
- VectorD2D d0 = p1 - p0;
- VectorD2D d1 = p3 - p2;
- VectorD2D diff = p2 - p0;
-
- double krossd0d1 = d0.x()*d1.y() - d1.x()*d0.y();
- double sqrkrossd0d1 = krossd0d1*krossd0d1;
- double sqrlen0 = d0.length2();
- double sqrlen1 = d1.length2();
-
- if (sqrkrossd0d1 > epsilon * sqrlen0 * sqrlen1)
- {
- double s = diff.x() * d1.y() - d1.x() * diff.y();
- point = p0 + s * d0;
- }
-
- double krossdiffd0 = diff.x()*d0.y() - d0.x()*diff.y();
- double sqrkrossdiffd0 = krossdiffd0*krossdiffd0;
- double sqrlendiff = diff.length2();
- if (sqrkrossdiffd0 > epsilon * sqrlen0 * sqrlendiff)
- {
- return 0;
- }
-
- return 2;
- }
-
- //test intersect
- //return value :
- //1(one intersection) 0 (parallel,no intersection) 2(same line)
- int testLine2LineIntersection2D(
- const VectorD2D& p0, const VectorD2D& p1,
- const VectorD2D& p2, const VectorD2D& p3)
- {
- const double epsilon = 1e-7;
-
- //one intersection
- VectorD2D d0 = p1 - p0;
- VectorD2D d1 = p3 - p2;
- double krossd0d1 = d0.x()*d1.y() - d1.x()*d0.y();
- double sqrKrossd0d1 = krossd0d1 * krossd0d1;
- double sqrL0 = d0.length2();
- double sqrL1 = d1.length2();
- if (sqrKrossd0d1 > epsilon * sqrL0 * sqrL1)
- {
- return 1;
- }
-
- //parallel
- Vec2d diff = p2 - p0;
- double sqrdiff = diff.length2();
- double krossdiffd0 = diff.x()*d0.y() - d0.x()*diff.y();
- double sqrkrossDiffd0 = krossdiffd0 * krossdiffd0;
- if (sqrkrossDiffd0 > epsilon * sqrdiff * sqrL0)
- {
- return 0;
- }
-
- //same line
- return 2;
- }
-
- } // namespace geo
- } // namespace ns
|