math_utils/geometry/primitive/
hull.rs1use std;
4
5use crate::*;
6
7#[derive(Clone, Debug, PartialEq)]
9pub struct Hull2 <S> {
10 points : Vec <Point2 <S>>
13}
14
15#[derive(Clone, Debug, PartialEq)]
17pub struct Hull3 <S> {
18 points : Vec <Point3 <S>>
19}
20
21impl <S> Hull2 <S> {
22 pub fn from_points (points : &[Point2 <S>]) -> Option <Self> where S : Real {
32 use std::cmp::Ordering;
35 match points.len() {
36 0 => return None,
37 1 => return Some (Hull2 { points: points.to_vec() }),
38 2 => {
39 let mut points = points.to_vec();
40 points.dedup();
41 return Some (Hull2 { points})
42 }
43 _ => {} }
45 let mut indexed_points = points.iter().cloned().enumerate()
46 .collect::<Vec <(usize, Point2 <S>)>>();
47 let start_index = indexed_points.iter().min_by (|a, b|{
49 let cmp = a.1.0.y.partial_cmp (&b.1.0.y).unwrap();
50 if cmp == Ordering::Equal {
51 a.1.0.x.partial_cmp (&b.1.0.x).unwrap()
52 } else {
53 cmp
54 }
55 }).unwrap().0;
56 let start_point = indexed_points[start_index].1;
57 indexed_points.sort_by (|a, b| {
59 if a.0 == start_index {
60 return Ordering::Less
61 }
62 if b.0 == start_index {
63 return Ordering::Greater
64 }
65 let angle_a = (a.1.0.y - start_point.0.y)
66 .atan2 (a.1.0.x - start_point.0.x);
67 let angle_b = (b.1.0.y - start_point.0.y)
68 .atan2 (b.1.0.x - start_point.0.x);
69 let angle_cmp = angle_a.partial_cmp (&angle_b).unwrap();
70 if angle_cmp == Ordering::Equal {
71 let dist_a = (a.1.0.x - start_point.0.x).powi (2) +
73 (a.1.0.y - start_point.0.y).powi (2);
74 let dist_b = (b.1.0.x - start_point.0.x).powi (2) +
75 (b.1.0.y - start_point.0.y).powi (2);
76 dist_a.partial_cmp (&dist_b).unwrap()
77 } else {
78 angle_cmp
79 }
80 });
81 let mut stack : Vec <usize> = Vec::new();
83 for (point_index, point) in indexed_points {
84 while stack.len() >= 2 {
85 let top = stack[stack.len() - 1];
86 let second = stack[stack.len() -2];
87 let p1 = points[second];
88 let p2 = points[top];
89 let p3 = point;
90 let det = Matrix2 {
91 cols: vector2 (p2 - p1, p3 - p1)
92 }.determinant();
93 if det <= S::zero() {
94 stack.pop();
95 } else {
96 break
97 }
98 }
99 stack.push (point_index)
100 }
101 let p = points;
102 let points = stack.iter().map (|i| p[*i]).collect();
103 Some (Hull2 { points })
104 }
105
106 pub fn points (&self) -> &[Point2 <S>] {
108 &self.points
109 }
110}
111
112impl <S> Hull3 <S> {
113 pub fn from_points (_points : &[Point3 <S>]) -> Option <Self> where S : Real {
114 unimplemented!("TODO")
117 }
118
119 pub fn points (&self) -> &[Point3 <S>] {
120 &self.points
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127 #[test]
128 fn hull2() {
129 use crate::*;
130 let points : Vec <Point2 <f32>> = [
132 [ 1.0, 1.0],
133 [ 1.0, 1.0]
134 ].map (Point2::from).into_iter().collect();
135 let hull = Hull2::from_points (points.as_slice()).unwrap();
136 assert_eq!(hull.points(), &[[1.0, 1.0].into()]);
137 let points : Vec <Point2 <f32>> = [
139 [ 0.0, 0.0],
140 [ 1.0, 3.0],
141 [ 2.0, -3.0],
142 [-3.0, -1.0]
143 ].map (Point2::from).into_iter().collect();
144 let hull = Hull2::from_points (points.as_slice()).unwrap();
145 let points : Vec <Point2 <f32>> = [
147 [ 2.0, -3.0],
148 [ 1.0, 3.0],
149 [-3.0, -1.0]
150 ].map (Point2::from).into_iter().collect();
151 assert_eq!(hull.points(), points);
152 let points : Vec <Point2 <f32>> = [
154 [ 0.0, 2.0],
155 [-2.0, -2.0],
156 [ 0.0, -2.0],
157 [ 2.0, -2.0]
158 ].map (Point2::from).into_iter().collect();
159 let hull = Hull2::from_points (points.as_slice()).unwrap();
160 let points : Vec <Point2 <f32>> = [
162 [-2.0, -2.0],
163 [ 2.0, -2.0],
164 [ 0.0, 2.0]
165 ].map (Point2::from).into_iter().collect();
166 assert_eq!(hull.points(), points);
167 let points : Vec <Point2 <f32>> = [
169 [ 0.0, 6.0],
171 [ 1.0, 5.0],
172 [ 2.0, 4.0],
173 [ 3.0, 3.0],
174 [ 3.0, 1.0],
175 [ 3.0, -1.0],
176 [ 3.0, -3.0],
177 [ 1.0, -3.0],
178 [-1.0, -3.0],
179 [-3.0, -3.0],
180 [-3.0, -1.0],
181 [-3.0, 1.0],
182 [-3.0, 3.0],
183 [-2.0, 4.0],
184 [-1.0, 5.0],
185 [-1.0, 2.0],
187 [ 2.0, -1.0],
188 [ 0.0, 3.0],
189 [-2.0, -2.0]
190 ].map (Point2::from).into_iter().collect();
191 let hull = Hull2::from_points (points.as_slice()).unwrap();
192 let points : Vec <Point2 <f32>> = [
194 [-3.0, -3.0],
195 [ 3.0, -3.0],
196 [ 3.0, 3.0],
197 [ 0.0, 6.0],
198 [-3.0, 3.0]
199 ].map (Point2::from).into_iter().collect();
200 assert_eq!(hull.points(), points);
201 }
202}