1818 -> GeeksforGeeks: https://www.geeksforgeeks.org/convex-hull-set-1-jarviss-algorithm-or-wrapping/
1919"""
2020
21- # pytest: disable=pytest-run-parallel
22-
2321from __future__ import annotations
2422
2523
2624class Point :
27- """
28- Represents a 2D point with x and y coordinates.
29-
30- >>> p = Point(1.0, 2.0)
31- >>> p.x
32- 1.0
33- >>> p.y
34- 2.0
35- """
25+ """Represents a 2D point with x and y coordinates."""
3626
3727 def __init__ (self , x_coordinate : float , y_coordinate : float ) -> None :
3828 self .x = x_coordinate
@@ -58,33 +48,14 @@ def _cross_product(origin: Point, point_a: Point, point_b: Point) -> float:
5848 > 0: Counter-clockwise turn (left turn)
5949 = 0: Collinear
6050 < 0: Clockwise turn (right turn)
61-
62- >>> origin = Point(0, 0)
63- >>> point_a = Point(1, 1)
64- >>> point_b = Point(2, 0)
65- >>> _cross_product(origin, point_a, point_b) < 0
66- True
67- >>> _cross_product(origin, Point(1, 0), Point(2, 0)) == 0
68- True
69- >>> _cross_product(origin, Point(1, 0), Point(1, 1)) > 0
70- True
7151 """
7252 return (point_a .x - origin .x ) * (point_b .y - origin .y ) - (point_a .y - origin .y ) * (
7353 point_b .x - origin .x
7454 )
7555
7656
7757def _is_point_on_segment (p1 : Point , p2 : Point , point : Point ) -> bool :
78- """
79- Check if a point lies on the line segment between p1 and p2.
80-
81- >>> _is_point_on_segment(Point(0, 0), Point(2, 2), Point(1, 1))
82- True
83- >>> _is_point_on_segment(Point(0, 0), Point(2, 2), Point(3, 3))
84- False
85- >>> _is_point_on_segment(Point(0, 0), Point(2, 0), Point(1, 0))
86- True
87- """
58+ """Check if a point lies on the line segment between p1 and p2."""
8859 # Check if point is collinear with segment endpoints
8960 cross = (point .y - p1 .y ) * (p2 .x - p1 .x ) - (point .x - p1 .x ) * (p2 .y - p1 .y )
9061
@@ -110,52 +81,6 @@ def jarvis_march(points: list[Point]) -> list[Point]:
11081 Returns:
11182 List of Points that form the convex hull in counter-clockwise order.
11283 Returns empty list if there are fewer than 3 non-collinear points.
113-
114- Examples:
115- >>> # Triangle
116- >>> p1, p2, p3 = Point(1, 1), Point(2, 1), Point(1.5, 2)
117- >>> hull = jarvis_march([p1, p2, p3])
118- >>> len(hull)
119- 3
120- >>> all(p in hull for p in [p1, p2, p3])
121- True
122-
123- >>> # Collinear points return empty hull
124- >>> points = [Point(i, 0) for i in range(5)]
125- >>> jarvis_march(points)
126- []
127-
128- >>> # Rectangle with interior point - interior point excluded
129- >>> p1, p2 = Point(1, 1), Point(2, 1)
130- >>> p3, p4 = Point(2, 2), Point(1, 2)
131- >>> p5 = Point(1.5, 1.5)
132- >>> hull = jarvis_march([p1, p2, p3, p4, p5])
133- >>> len(hull)
134- 4
135- >>> p5 in hull
136- False
137-
138- >>> # Star shape - only tips are in hull
139- >>> tips = [
140- ... Point(-5, 6), Point(-11, 0), Point(-9, -8),
141- ... Point(4, 4), Point(6, -7)
142- ... ]
143- >>> interior = [Point(-7, -2), Point(-2, -4), Point(0, 1)]
144- >>> hull = jarvis_march(tips + interior)
145- >>> len(hull)
146- 5
147- >>> all(p in hull for p in tips)
148- True
149- >>> any(p in hull for p in interior)
150- False
151-
152- >>> # Too few points
153- >>> jarvis_march([])
154- []
155- >>> jarvis_march([Point(0, 0)])
156- []
157- >>> jarvis_march([Point(0, 0), Point(1, 1)])
158- []
15984 """
16085 if len (points ) <= 2 :
16186 return []
@@ -211,6 +136,7 @@ def jarvis_march(points: list[Point]) -> list[Point]:
211136
212137
213138if __name__ == "__main__" :
214- import doctest
215-
216- doctest .testmod ()
139+ # Example usage
140+ points = [Point (0 , 0 ), Point (1 , 1 ), Point (0 , 1 ), Point (1 , 0 ), Point (0.5 , 0.5 )]
141+ hull = jarvis_march (points )
142+ print (f"Convex hull: { hull } " )
0 commit comments