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