polygon.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * polygon.cpp
  3. * Copyright (C) Andrew Tridgell 2011
  4. *
  5. * This file is free software: you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This file is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "AP_Math.h"
  19. #pragma GCC optimize("O2")
  20. /*
  21. * The point in polygon algorithm is based on:
  22. * https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html
  23. */
  24. /*
  25. * Polygon_outside(): test for a point in a polygon
  26. * Input: P = a point,
  27. * V[] = vertex points of a polygon V[n+1] with V[n]=V[0]
  28. * Return: true if P is outside the polygon
  29. *
  30. * This does not take account of the curvature of the earth, but we
  31. * expect that to be very small over the distances involved in the
  32. * fence boundary
  33. */
  34. template <typename T>
  35. bool Polygon_outside(const Vector2<T> &P, const Vector2<T> *V, unsigned n)
  36. {
  37. const bool complete = Polygon_complete(V, n);
  38. if (complete) {
  39. // the last point is the same as the first point; treat as if
  40. // the last point wasn't passed in
  41. n--;
  42. }
  43. unsigned i, j;
  44. // step through each edge pair-wise looking for crossings:
  45. bool outside = true;
  46. for (i=0; i<n; i++) {
  47. j = i+1;
  48. if (j >= n) {
  49. j = 0;
  50. }
  51. if ((V[i].y > P.y) == (V[j].y > P.y)) {
  52. continue;
  53. }
  54. const T dx1 = P.x - V[i].x;
  55. const T dx2 = V[j].x - V[i].x;
  56. const T dy1 = P.y - V[i].y;
  57. const T dy2 = V[j].y - V[i].y;
  58. const int8_t dx1s = (dx1 < 0) ? -1 : 1;
  59. const int8_t dx2s = (dx2 < 0) ? -1 : 1;
  60. const int8_t dy1s = (dy1 < 0) ? -1 : 1;
  61. const int8_t dy2s = (dy2 < 0) ? -1 : 1;
  62. const int8_t m1 = dx1s * dy2s;
  63. const int8_t m2 = dx2s * dy1s;
  64. // we avoid the 64 bit multiplies if we can based on sign checks.
  65. if (dy2 < 0) {
  66. if (m1 > m2) {
  67. outside = !outside;
  68. } else if (m1 < m2) {
  69. continue;
  70. } else {
  71. if (std::is_floating_point<T>::value) {
  72. if ( dx1 * dy2 > dx2 * dy1 ) {
  73. outside = !outside;
  74. }
  75. } else {
  76. if ( dx1 * (int64_t)dy2 > dx2 * (int64_t)dy1 ) {
  77. outside = !outside;
  78. }
  79. }
  80. }
  81. } else {
  82. if (m1 < m2) {
  83. outside = !outside;
  84. } else if (m1 > m2) {
  85. continue;
  86. } else {
  87. if (std::is_floating_point<T>::value) {
  88. if ( dx1 * dy2 < dx2 * dy1 ) {
  89. outside = !outside;
  90. }
  91. } else {
  92. if ( dx1 * (int64_t)dy2 < dx2 * (int64_t)dy1 ) {
  93. outside = !outside;
  94. }
  95. }
  96. }
  97. }
  98. }
  99. return outside;
  100. }
  101. /*
  102. * check if a polygon is complete.
  103. *
  104. * We consider a polygon to be complete if we have at least 4 points,
  105. * and the first point is the same as the last point. That is the
  106. * minimum requirement for the Polygon_outside function to work
  107. */
  108. template <typename T>
  109. bool Polygon_complete(const Vector2<T> *V, unsigned n)
  110. {
  111. return (n >= 4 && V[n-1] == V[0]);
  112. }
  113. // Necessary to avoid linker errors
  114. template bool Polygon_outside<int32_t>(const Vector2l &P, const Vector2l *V, unsigned n);
  115. template bool Polygon_complete<int32_t>(const Vector2l *V, unsigned n);
  116. template bool Polygon_outside<float>(const Vector2f &P, const Vector2f *V, unsigned n);
  117. template bool Polygon_complete<float>(const Vector2f *V, unsigned n);
  118. /*
  119. determine if the polygon of N verticies defined by points V is
  120. intersected by a line from point p1 to point p2
  121. intersection argument returns the intersection closest to p1
  122. */
  123. bool Polygon_intersects(const Vector2f *V, unsigned N, const Vector2f &p1, const Vector2f &p2, Vector2f &intersection)
  124. {
  125. const bool complete = Polygon_complete(V, N);
  126. if (complete) {
  127. // if the last point is the same as the first point
  128. // treat as if the last point wasn't passed in
  129. N--;
  130. }
  131. float intersect_dist_sq = FLT_MAX;
  132. for (uint8_t i=0; i<N; i++) {
  133. uint8_t j = i+1;
  134. if (j >= N) {
  135. j = 0;
  136. }
  137. const Vector2f &v1 = V[i];
  138. const Vector2f &v2 = V[j];
  139. // optimisations for common cases
  140. if (v1.x > p1.x && v2.x > p1.x && v1.x > p2.x && v2.x > p2.x) {
  141. continue;
  142. }
  143. if (v1.y > p1.y && v2.y > p1.y && v1.y > p2.y && v2.y > p2.y) {
  144. continue;
  145. }
  146. if (v1.x < p1.x && v2.x < p1.x && v1.x < p2.x && v2.x < p2.x) {
  147. continue;
  148. }
  149. if (v1.y < p1.y && v2.y < p1.y && v1.y < p2.y && v2.y < p2.y) {
  150. continue;
  151. }
  152. Vector2f intersect_tmp;
  153. if (Vector2f::segment_intersection(v1,v2,p1,p2,intersect_tmp)) {
  154. float dist_sq = sq(intersect_tmp.x - p1.x) + sq(intersect_tmp.y - p1.y);
  155. if (dist_sq < intersect_dist_sq) {
  156. intersect_dist_sq = dist_sq;
  157. intersection = intersect_tmp;
  158. }
  159. }
  160. }
  161. return (intersect_dist_sq < FLT_MAX);
  162. }
  163. /*
  164. return the closest distance that a line from p1 to p2 comes to an
  165. edge of closed polygon V, defined by N points
  166. negative numbers indicate the line cross into the polygon with the negative size being the distance from p2 to the intersection point closest to p1
  167. */
  168. float Polygon_closest_distance_line(const Vector2f *V, unsigned N, const Vector2f &p1, const Vector2f &p2)
  169. {
  170. Vector2f intersection;
  171. if (Polygon_intersects(V,N,p1,p2,intersection)) {
  172. return -sqrtf(sq(intersection.x - p2.x) + sq(intersection.y - p2.y));
  173. }
  174. float closest_sq = FLT_MAX;
  175. for (uint8_t i=0; i<N-1; i++) {
  176. const Vector2f &v1 = V[i];
  177. const Vector2f &v2 = V[i+1];
  178. float dist_sq = Vector2f::closest_distance_between_lines_squared(v1, v2, p1, p2);
  179. if (dist_sq < closest_sq) {
  180. closest_sq = dist_sq;
  181. }
  182. }
  183. return sqrtf(closest_sq);
  184. }
  185. /*
  186. return the closest distance that point p comes to an edge of closed
  187. polygon V, defined by N points
  188. */
  189. float Polygon_closest_distance_point(const Vector2f *V, unsigned N, const Vector2f &p)
  190. {
  191. float closest_sq = FLT_MAX;
  192. for (uint8_t i=0; i<N-1; i++) {
  193. const Vector2f &v1 = V[i];
  194. const Vector2f &v2 = V[i+1];
  195. float dist_sq = Vector2f::closest_distance_between_line_and_point_squared(v1, v2, p);
  196. if (dist_sq < closest_sq) {
  197. closest_sq = dist_sq;
  198. }
  199. }
  200. return sqrtf(closest_sq);
  201. }