@@ -9,12 +9,15 @@ proc tup_to_point[T](t: (T, T)): Point[T] =
9
9
(x: t[0 ], y: t[1 ])
10
10
11
11
proc is_counter_clockwise (p1, p2, p3: Point ): bool =
12
+ # # Do the given points form a counter-clockwise turn?
12
13
(p3.y - p1.y) * (p2.x - p1.x) < (p2.y - p1.y) * (p3.x - p1.x)
13
14
14
15
proc polar_angle (reference, point: Point ): float =
16
+ # # Find the polar angle of a point relative to a reference point
15
17
arctan2 (float (point.y - reference.y), float (point.x - reference.x))
16
18
17
19
proc flipped_point_cmp (pa, pb: Point ): int =
20
+ # # Compare points first by their y-coordinate, then x-coordinate.
18
21
if (pa.y, pa.x) < (pb.y, pb.x): - 1
19
22
elif pa == pb: 0
20
23
else : 1
@@ -23,21 +26,26 @@ proc graham_scan(gift: seq[Point]): seq[Point] =
23
26
assert (gift.len >= 3 )
24
27
var points = sorted (deduplicate (gift), flipped_point_cmp)
25
28
let pivot = points[0 ]
29
+ # Mimic sorting a sliced sequence without copying
26
30
sort (toOpenArray (points, 1 , high (points)),
27
31
proc (pa, pb: Point ): int =
28
32
if polar_angle (pivot, pa) < polar_angle (pivot, pb): - 1
29
33
else : 1 )
30
34
var
35
+ # Hull pointer
31
36
m = 1
37
+ # Needed because the iteration variable from a slice is immutable
32
38
en = toSeq (low (points) + 2 .. high (points))
33
39
for i in mitems (en):
34
40
while is_counter_clockwise (points[m - 1 ], points[m], points[i]):
35
41
if m > 1 :
36
42
m -= 1
43
+ # All points are collinear
37
44
elif i == points.len:
38
45
break
39
46
else :
40
47
i += 1
48
+ # Counter-clockwise point found, update hull and swap
41
49
m += 1
42
50
swap (points[i], points[m])
43
51
points[0 .. m]
0 commit comments