Find the convex hull of a set of points using the Jarvis March algorithm. The algorithm starts with the leftmost point and wraps around the set of points, selecting the most counter-clockwise point at each step. Args: points: List of Point objects representing 2D coordinat
(points: list[Point])
| 118 | |
| 119 | |
| 120 | def jarvis_march(points: list[Point]) -> list[Point]: |
| 121 | """ |
| 122 | Find the convex hull of a set of points using the Jarvis March algorithm. |
| 123 | |
| 124 | The algorithm starts with the leftmost point and wraps around the set of |
| 125 | points, selecting the most counter-clockwise point at each step. |
| 126 | |
| 127 | Args: |
| 128 | points: List of Point objects representing 2D coordinates |
| 129 | |
| 130 | Returns: |
| 131 | List of Points that form the convex hull in counter-clockwise order. |
| 132 | Returns empty list if there are fewer than 3 non-collinear points. |
| 133 | """ |
| 134 | if len(points) <= 2: |
| 135 | return [] |
| 136 | |
| 137 | # Remove duplicate points to avoid infinite loops |
| 138 | unique_points = list(set(points)) |
| 139 | |
| 140 | if len(unique_points) <= 2: |
| 141 | return [] |
| 142 | |
| 143 | convex_hull: list[Point] = [] |
| 144 | |
| 145 | # Find the leftmost point |
| 146 | left_point_idx = _find_leftmost_point(unique_points) |
| 147 | convex_hull.append( |
| 148 | Point(unique_points[left_point_idx].x, unique_points[left_point_idx].y) |
| 149 | ) |
| 150 | |
| 151 | current_idx = left_point_idx |
| 152 | while True: |
| 153 | # Find the next counter-clockwise point |
| 154 | next_idx = _find_next_hull_point(unique_points, current_idx) |
| 155 | |
| 156 | if next_idx == left_point_idx: |
| 157 | break |
| 158 | |
| 159 | if next_idx == current_idx: |
| 160 | break |
| 161 | |
| 162 | current_idx = next_idx |
| 163 | _add_point_to_hull(convex_hull, unique_points[current_idx]) |
| 164 | |
| 165 | # Check for degenerate cases |
| 166 | if len(convex_hull) <= 2: |
| 167 | return [] |
| 168 | |
| 169 | # Check if last point is collinear with first and second-to-last |
| 170 | last = len(convex_hull) - 1 |
| 171 | if _is_point_on_segment(convex_hull[last - 1], convex_hull[last], convex_hull[0]): |
| 172 | convex_hull.pop() |
| 173 | if len(convex_hull) == 2: |
| 174 | return [] |
| 175 | |
| 176 | # Verify the hull forms a valid polygon |
| 177 | if not _is_valid_polygon(convex_hull): |