You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

geometry.cpp 6.5 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /**
  2. * @file geometry.cpp
  3. * @author donkey (anjingyu_ws@foxmail.com)
  4. * @brief Implementation of basic geometry functions in \c ns::geo
  5. * @version 0.1.0
  6. * @date 2020-05-15
  7. *
  8. * @copyright Copyright (c) 2020- donkey <anjingyu_ws@foxmail.com>.
  9. *
  10. */
  11. #include "geo/geometry.h"
  12. #include <cmath> /**< std::sqrt std::fabs */
  13. namespace ns {
  14. namespace geo {
  15. bool Geometry::perpendicularDistanceOn(double ptX, double ptY, double startX, double startY, double endX, double endY, double *distance)
  16. {
  17. double dot = (ptX - endX) * (startX - endX) + (ptY - endY) * (startY - endY);
  18. double d2 = (startX - endX) * (startX - endX) + (startY - endY) * (startY - endY);
  19. double r = dot / d2;
  20. bool on = (r <= 1.0 && r >= 0.0);
  21. if (distance == nullptr)
  22. {
  23. return on;
  24. }
  25. if (on)
  26. {
  27. // Out of range
  28. if (r < 0.0 || r > 1.0)
  29. {
  30. *distance = 0.0;
  31. }
  32. else
  33. {
  34. if (startX == endX)
  35. {
  36. *distance = std::fabs(ptX - startX);
  37. }
  38. else
  39. {
  40. double lineK = (endY - startY) / (endX - startX);
  41. double lineC = (endX * startY - startX * endY) / (endX - startX);
  42. *distance = std::fabs(lineK * ptX - ptY + lineC) / (std::sqrt(lineK * lineK + 1));
  43. }
  44. // Get the foot of prependicular
  45. // double u = ((ptX - startX) * (startX - endX) + (ptY - startY) * (startY - endY)) / d2;
  46. // double footX = startX + u * (startX - endX);
  47. // double footY = startY + u * (startY - endY);
  48. }
  49. }
  50. else
  51. {
  52. *distance = 0.0;
  53. }
  54. return on;
  55. }
  56. bool Geometry::prependicularDistanceOn(double ptX, double ptY, double ptZ,
  57. double startX, double startY, double startZ,
  58. double endX, double endY, double endZ,
  59. double *distance)
  60. {
  61. double dot = (ptX - endX) * (startX - endX) + (ptY - endY) * (startY - endY) + (ptZ - endZ) * (startZ - endZ);
  62. double d2 = (startX - endX) * (startX - endX) + (startY - endY) * (startY - endY) + (startZ - endZ) * (startZ - endZ);
  63. double r = dot / d2;
  64. bool on = (r <= 1.0 && r >= 0.0);
  65. if (distance == nullptr)
  66. {
  67. return on;
  68. }
  69. if (on)
  70. {
  71. // d = (AB x AC)/|AB| S = (AB X AC) / 2 = distance * |AB| / 2
  72. // TODO
  73. }
  74. else
  75. {
  76. distance = 0.0;
  77. }
  78. return as*sin_A;
  79. }
  80. // Dot product of vector1(x1, y1) and vector2(x2, y2)
  81. // result = x1 * x2 + y1 * y2
  82. static inline double _dot(double x1, double y1, double x2, double y2)
  83. {
  84. return x1 * x2 + y1 * y2
  85. }
  86. // Cross product of vector1(x1, y1) and vector2(x2, y2)
  87. // result = x1 * y2 - x2 * y1
  88. static inline double _cross(double x1, double y1, double x2, double y2)
  89. {
  90. return x1 * y2 - x2 * y1
  91. }
  92. // Calculate the distance of point to line.
  93. //
  94. // vector1 (endX - startX, endY - startY)
  95. // vector2 (x - startX, y - startY)
  96. //
  97. // result = |vector1 X vector2| / |vector1|
  98. double Geometry::distancePoint2Line(x, y, startX, startY, endX, endY)
  99. {
  100. double vec1x = endX - startX;
  101. double vec1y = endY - startY;
  102. double vec2x = x - startX;
  103. double vec2y = y - startY;
  104. double dis = std::abs(_cross(vec1x, vec1y, vec2x,
  105. vec2y)) / std::sqrt(vec1x * vec1x + vec1y * vec1y)
  106. return dis
  107. }
  108. static int _getLineIntersection(float p0_x, float p0_y, float p1_x, float p1_y,
  109. float p2_x, float p2_y, float p3_x, float p3_y, float *i_x, float *i_y)
  110. {
  111. float s02_x, s02_y, s10_x, s10_y, s32_x, s32_y, s_numer, t_numer, denom, t;
  112. s10_x = p1_x - p0_x;
  113. s10_y = p1_y - p0_y;
  114. s32_x = p3_x - p2_x;
  115. s32_y = p3_y - p2_y;
  116. denom = s10_x * s32_y - s32_x * s10_y;
  117. if (denom == 0)
  118. return 0; // Collinear
  119. bool denomPositive = denom > 0;
  120. s02_x = p0_x - p2_x;
  121. s02_y = p0_y - p2_y;
  122. s_numer = s10_x * s02_y - s10_y * s02_x;
  123. if ((s_numer < 0) == denomPositive)
  124. return 0; // No collision
  125. t_numer = s32_x * s02_y - s32_y * s02_x;
  126. if ((t_numer < 0) == denomPositive)
  127. return 0; // No collision
  128. if (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive))
  129. return 0; // No collision
  130. // Collision detected
  131. t = t_numer / denom;
  132. if (i_x != NULL)
  133. *i_x = p0_x + (t * s10_x);
  134. if (i_y != NULL)
  135. *i_y = p0_y + (t * s10_y);
  136. return 1;
  137. }
  138. //find intersect
  139. //return value :
  140. //1(one intersection) 0 (parallel,no intersection) 2(same line)
  141. //@param point: if return value is one, point is the intersection point.
  142. static int _findLine2LineIntersection2D(
  143. const VectorD2D& p0, const VectorD2D& p1,
  144. const VectorD2D& p2, const VectorD2D& p3, VectorD2D& point)
  145. {
  146. const double epsilon = 1e-7;
  147. VectorD2D d0 = p1 - p0;
  148. VectorD2D d1 = p3 - p2;
  149. VectorD2D diff = p2 - p0;
  150. double krossd0d1 = d0.x()*d1.y() - d1.x()*d0.y();
  151. double sqrkrossd0d1 = krossd0d1*krossd0d1;
  152. double sqrlen0 = d0.length2();
  153. double sqrlen1 = d1.length2();
  154. if (sqrkrossd0d1 > epsilon * sqrlen0 * sqrlen1)
  155. {
  156. double s = diff.x() * d1.y() - d1.x() * diff.y();
  157. point = p0 + s * d0;
  158. }
  159. double krossdiffd0 = diff.x()*d0.y() - d0.x()*diff.y();
  160. double sqrkrossdiffd0 = krossdiffd0*krossdiffd0;
  161. double sqrlendiff = diff.length2();
  162. if (sqrkrossdiffd0 > epsilon * sqrlen0 * sqrlendiff)
  163. {
  164. return 0;
  165. }
  166. return 2;
  167. }
  168. //test intersect
  169. //return value :
  170. //1(one intersection) 0 (parallel,no intersection) 2(same line)
  171. int testLine2LineIntersection2D(
  172. const VectorD2D& p0, const VectorD2D& p1,
  173. const VectorD2D& p2, const VectorD2D& p3)
  174. {
  175. const double epsilon = 1e-7;
  176. //one intersection
  177. VectorD2D d0 = p1 - p0;
  178. VectorD2D d1 = p3 - p2;
  179. double krossd0d1 = d0.x()*d1.y() - d1.x()*d0.y();
  180. double sqrKrossd0d1 = krossd0d1 * krossd0d1;
  181. double sqrL0 = d0.length2();
  182. double sqrL1 = d1.length2();
  183. if (sqrKrossd0d1 > epsilon * sqrL0 * sqrL1)
  184. {
  185. return 1;
  186. }
  187. //parallel
  188. Vec2d diff = p2 - p0;
  189. double sqrdiff = diff.length2();
  190. double krossdiffd0 = diff.x()*d0.y() - d0.x()*diff.y();
  191. double sqrkrossDiffd0 = krossdiffd0 * krossdiffd0;
  192. if (sqrkrossDiffd0 > epsilon * sqrdiff * sqrL0)
  193. {
  194. return 0;
  195. }
  196. //same line
  197. return 2;
  198. }
  199. } // namespace geo
  200. } // namespace ns