1
1
from algorithm import sorted
2
2
from math import arctan2
3
- from sequtils import deduplicate, map
3
+ from sequtils import deduplicate, map, toSeq
4
4
import sugar
5
5
6
6
type Point[T: SomeNumber] = tuple [x, y: T]
@@ -20,22 +20,30 @@ proc flipped_point_cmp(pa, pb: Point): int =
20
20
else : 1
21
21
22
22
proc graham_scan(gift: seq [Point]) : seq [Point] =
23
- # TODO make sure input has length >= 3
23
+ assert(gift.len >= 3 )
24
24
let
25
25
gift_without_duplicates = sorted(deduplicate(gift), flipped_point_cmp)
26
- start = gift_without_duplicates[0 ]
27
- candidates = sorted(gift_without_duplicates[1 ..^ 1 ],
28
- proc (pa, pb: Point): int =
29
- if polar_angle(start, pa) < polar_angle(start, pb): - 1
30
- else : 1 )
31
- # TODO take the approach outlined in the text where we perform rotations on
32
- # the candidates, rather than add to a new sequence
33
- var hull = @ [start, candidates[0 ], candidates[1 ]]
34
- for candidate in candidates:
35
- while not is_counter_clockwise(hull[^ 2 ], hull[^ 1 ], candidate):
36
- discard pop(hull)
37
- add(hull, candidate)
38
- hull
26
+ pivot = gift_without_duplicates[0 ]
27
+ var
28
+ points = sorted(gift_without_duplicates[1 ..^ 1 ],
29
+ proc (pa, pb: Point): int =
30
+ if polar_angle(pivot, pa) < polar_angle(pivot, pb): - 1
31
+ else : 1 )
32
+ points.insert(pivot, 0 )
33
+ var
34
+ m = 1
35
+ en = toSeq(low(points) + 2 .. high(points))
36
+ for i in mitems(en):
37
+ while is_counter_clockwise(points[m - 1 ], points[m], points[i]) :
38
+ if m > 1 :
39
+ m -= 1
40
+ elif i == points.len:
41
+ break
42
+ else :
43
+ i += 1
44
+ m += 1
45
+ swap(points[i], points[m])
46
+ points[0 .. m]
39
47
40
48
when isMainModule :
41
49
let
0 commit comments