11# cython: language_level=3
22# distutils: language = c++
3- # Copyright (c) 2020-2023 , Manfred Moitzi
3+ # Copyright (c) 2020-2024 , Manfred Moitzi
44# License: MIT License
55# type: ignore -- pylance sucks at type-checking cython files
66from typing import Iterable, TYPE_CHECKING, Sequence, Optional, Tuple
@@ -199,3 +199,80 @@ def arc_angle_span_rad(double start, double end) -> float:
199199 if end < start:
200200 end += M_TAU
201201 return end - start
202+
203+
204+ def is_point_in_polygon_2d (
205+ point: Vec2 , polygon: list[Vec2], double abs_tol = TOLERANCE
206+ ) -> int:
207+ """
208+ Test if `point` is inside `polygon`. Returns +1 for inside , 0 for on the
209+ boundary and -1 for outside.
210+
211+ Supports convex and concave polygons with clockwise or counter-clockwise oriented
212+ polygon vertices. Does not raise an exception for degenerated polygons.
213+
214+
215+ Args:
216+ point: 2D point to test as :class:`Vec2`
217+ polygon: list of 2D points as :class:`Vec2`
218+ abs_tol: tolerance for distance check
219+
220+ Returns:
221+ +1 for inside , 0 for on the boundary , -1 for outside
222+
223+ """
224+ # Source: http://www.faqs.org/faqs/graphics/algorithms-faq/
225+ # Subject 2.03: How do I find if a point lies within a polygon?
226+ # Numpy version was just 10x faster , this version is 23x faster than the Python
227+ # version!
228+ cdef double a , b , c , d , x , y , x1 , y1 , x2 , y2
229+ cdef list vertices = polygon
230+ cdef Vec2 p1 , p2
231+ cdef int size , last , i
232+ cdef bint inside = 0
233+
234+ size = len (vertices)
235+ if size < 3: # empty polygon
236+ return -1
237+ last = size - 1
238+ p1 = < Vec2> vertices[0 ]
239+ p2 = < Vec2> vertices[last]
240+
241+ if v2_isclose(p1 , p2 , REL_TOL , ABS_TOL ): # open polygon
242+ size -= 1
243+ last -= 1
244+ if size < 3 :
245+ return - 1
246+
247+ x = point.x
248+ y = point.y
249+ p1 = < Vec2> vertices[last]
250+ x1 = p1.x
251+ y1 = p1.y
252+
253+ for i in range (size):
254+ p2 = < Vec2> vertices[i]
255+ x2 = p2.x
256+ y2 = p2.y
257+
258+ # is point on polygon boundary line:
259+ # is point in x-range of line
260+ a, b = (x2, x1) if x2 < x1 else (x1, x2)
261+ if a <= x <= b:
262+ # is point in y-range of line
263+ c, d = (y2, y1) if y2 < y1 else (y1, y2)
264+ if (c <= y <= d) and fabs(
265+ (y2 - y1) * x - (x2 - x1) * y + (x2 * y1 - y2 * x1)
266+ ) <= abs_tol:
267+ return 0 # on boundary line
268+ if ((y1 <= y < y2) or (y2 <= y < y1)) and (
269+ x < (x2 - x1) * (y - y1) / (y2 - y1) + x1
270+ ):
271+ inside = not inside
272+ x1 = x2
273+ y1 = y2
274+ if inside:
275+ return 1 # inside polygon
276+ else :
277+ return - 1 # outside polygon
278+
0 commit comments