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.

convex_polygon.cpp 4.4 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. #include "geo/private/math/convex_polygon.h"
  2. #include <algorithm>
  3. namespace ns
  4. {
  5. namespace geo
  6. {
  7. // 从下面的网址搬运过来修改的计算点集的外接多边形
  8. // https://www.geeksforgeeks.org/convex-hull-set-1-jarviss-algorithm-or-wrapping/
  9. // 此处小数点后的精确度必须精确到10位以后结果才会准确
  10. // const double EPSION = 0.0000000000000001;
  11. const double EPSION = std::numeric_limits<double>::min();
  12. // A C++ program to find convex hull of a set of points. Refer
  13. // https://www.geeksforgeeks.org/orientation-3-ordered-points/
  14. // To find orientation of ordered triplet (p, q, r).
  15. // The function returns following values
  16. // 0 --> p, q and r are colinear
  17. // 1 --> Clockwise
  18. // 2 --> Counterclockwise
  19. namespace
  20. {
  21. int orientation(const PointD& p, const PointD& q, const PointD& r)
  22. {
  23. double val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
  24. if (std::abs(val) <= EPSION)
  25. return 0; // colinear 共线
  26. return (val > EPSION) ? 1 : 2; // clock or counterclock wise 顺时针或者逆时针方向
  27. }
  28. // 如果有重复点去除重复点
  29. std::vector<PointD> repeatPoints(const std::vector<PointD>& points)
  30. {
  31. std::vector<PointD> rePoints;
  32. for (size_t i = 0; i < points.size(); i++)
  33. {
  34. PointD tmpPoint(points[i].x, points[i].y, points[i].z);
  35. auto iter = std::find(rePoints.begin(), rePoints.end(), tmpPoint);
  36. if (iter == rePoints.end()) // 去除重复点
  37. {
  38. rePoints.emplace_back(tmpPoint);
  39. }
  40. }
  41. return rePoints;
  42. }
  43. } // namespace
  44. // Prints convex hull of a set of n points.
  45. std::vector<PointD> convexHull(const std::vector<PointD>& points)
  46. {
  47. std::vector<PointD> rePoints = repeatPoints(points);
  48. // Initialize Result
  49. std::vector<PointD> hull;
  50. // There must be at least 3 points
  51. size_t n = rePoints.size();
  52. if (n < 3)
  53. {
  54. return hull;
  55. }
  56. // Find the leftmost point
  57. size_t l = 0;
  58. for (size_t i = 1; i < n; i++)
  59. {
  60. if (rePoints[i].x < rePoints[l].x)
  61. {
  62. l = i;
  63. }
  64. }
  65. // Start from leftmost point, keep moving counterclockwise
  66. // until reach the start point again. This loop runs O(h)
  67. // times where h is number of points in result or output.
  68. size_t p = l, q, count = 0;
  69. do
  70. {
  71. // Add current point to result
  72. hull.push_back(rePoints[p]);
  73. // Search for a point 'q' such that orientation(p, x,
  74. // q) is counterclockwise for all points 'x'. The idea
  75. // is to keep track of last visited most counterclock-
  76. // wise point in q. If any point 'i' is more counterclock-
  77. // wise than q, then update q.
  78. q = (p + 1) % n;
  79. for (size_t i = 0; i < n; i++)
  80. {
  81. // If i is more counterclockwise than current q, then
  82. // update q
  83. if (orientation(rePoints[p], rePoints[i], rePoints[q]) == 2) // 按照逆时针方向循环
  84. {
  85. q = i;
  86. }
  87. }
  88. // Now q is the most counterclockwise with respect to p
  89. // Set p as q for next iteration, so that q is added to
  90. // result 'hull'
  91. p = q;
  92. count++;
  93. if (count == n) // 最多遍历n次跳出循环,避免出现死循环的现象
  94. {
  95. p = l;
  96. }
  97. } while (p != l); // While we don't come to first point
  98. return hull;
  99. }
  100. // 下面这个判断一个点是否在多边形内的方法,比较复杂,想了解原理直接看下面的参考网址
  101. // 参考网址:http://alienryderflex.com/polygon/
  102. bool pointInPolygon(const std::vector<PointD>& points, const PointD& point)
  103. {
  104. size_t j = points.size() - 1;
  105. bool oddNodes = false;
  106. for (size_t i = 0; i < points.size(); i++)
  107. {
  108. PointD tmpPointI = points[i];
  109. PointD tmpPointJ = points[j];
  110. if (((tmpPointI.y < point.y && tmpPointJ.y >= point.y) ||
  111. (tmpPointJ.y < point.y && tmpPointI.y >= point.y)) &&
  112. (tmpPointI.x <= point.x || tmpPointJ.x <= point.x))
  113. {
  114. oddNodes ^= (tmpPointI.x + (point.y - tmpPointI.y) / (tmpPointJ.y - tmpPointI.y) *
  115. (tmpPointJ.x - tmpPointI.x) <
  116. point.x);
  117. }
  118. j = i;
  119. }
  120. return oddNodes;
  121. }
  122. } // namespace geo
  123. } // namespace ns