1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use crate::prelude::{Point, SimplePolygon, Edge, Side};
use num_traits::Num;
pub fn convex_hull<T>(points: Vec<Point<T>>) -> SimplePolygon<T>
where T: Num + Ord + Copy {
let p = {
let mut p = points;
p.sort();
p
};
assert!(p.len() >= 2);
let minmin = 0;
let p_minmin = p[minmin];
let maxmax = p.len() - 1;
let p_maxmax = p[maxmax];
let minmax = p.iter().enumerate()
.take_while(|(_, p)| p.x == p_minmin.x)
.last().unwrap().0;
let p_minmax = p[minmax];
let maxmin = p.iter().enumerate().rev()
.take_while(|(_, p)| p.x == p_maxmax.x)
.last().unwrap().0;
let p_maxmin = p[maxmin];
debug_assert!(minmin <= minmax);
debug_assert!(minmax <= maxmin || p_minmax.x == p_maxmin.x);
debug_assert!(maxmin <= maxmax);
debug_assert!(p.iter().all(|&p| p_minmin <= p));
debug_assert!(p.iter().all(|&p| p_maxmax >= p));
debug_assert!(p.iter().all(|&p|
p_minmax.x < p.x || (p_minmax.x == p.x && p_minmax.y >= p.y)
));
debug_assert!(p.iter().all(|&p|
p_maxmin.x > p.x || (p_maxmin.x == p.x && p_maxmin.y <= p.y)
));
if p_minmin.x == p_maxmax.x {
if p_minmin.y == p_maxmax.y {
SimplePolygon::new(vec![p_minmin])
} else {
SimplePolygon::new(vec![p_minmin, p_maxmax])
}
} else {
let build_half_hull =
|l: Edge<T>, points: &[Point<T>]| {
let mut stack = Vec::new();
stack.push(l.start);
for &pi in points {
if l.side_of(pi) == Side::Right {
while stack.len() >= 2 {
let pt1 = stack[stack.len() - 1];
let pt2 = stack[stack.len() - 2];
if Edge::new(pt2, pt1).side_of(pi) == Side::Left {
break;
}
stack.pop();
}
stack.push(pi);
}
}
stack
};
let l_min = Edge::new(p_minmin, p_maxmin);
let mut lower_half_hull = build_half_hull(l_min, &p[minmax + 1..maxmin]);
if p_maxmin != p_maxmax {
lower_half_hull.push(p_maxmin);
}
let l_max = Edge::new(p_maxmax, p_minmax);
let mut upper_half_hull = build_half_hull(l_max, &p[minmax + 1..maxmin]);
if p_minmax != p_minmin {
upper_half_hull.push(p_minmax);
}
lower_half_hull.append(&mut upper_half_hull);
SimplePolygon::new(lower_half_hull)
}
}