1use std;
4use std::collections::{BTreeSet, VecDeque};
5use approx;
6
7use crate::*;
8use super::*;
9
10use geometry::mesh::VertexEdgeTriangleMesh;
11use geometry::mesh::edge_triangle::TriangleKey;
12
13#[derive(Clone, Debug, PartialEq)]
15pub struct Hull2 <S> {
16 points : Vec <Point2 <S>>
19}
20
21#[derive(Clone, Debug, PartialEq)]
23pub struct Hull3 <S> {
24 points : Vec <Point3 <S>>
25}
26
27impl <S> Hull2 <S> {
28 pub fn from_points (points : &[Point2 <S>]) -> Option <Self> where S : Real {
38 Self::from_points_indices (points).map (|indices|{
39 let points = indices.iter().map (|i| points[*i as usize]).collect();
40 Hull2 { points }
41 })
42 }
43
44 pub fn points (&self) -> &[Point2 <S>] {
46 &self.points
47 }
48
49 fn from_points_indices (points : &[Point2 <S>]) -> Option <Vec <u32>> where S : Real {
50 use std::cmp::Ordering;
53 match points.len() {
54 0 => return None,
55 1 => return Some (vec![0]),
56 2 => {
57 let v = if points[0] == points[1] {
58 vec![0]
59 } else {
60 vec![0, 1]
61 };
62 return Some (v)
63 }
64 _ => {} }
66 let mut indexed_points = points.iter().cloned().enumerate()
67 .collect::<Vec <(usize, Point2 <S>)>>();
68 let start_index = indexed_points.iter().min_by (|a, b|{
70 let cmp = a.1.0.y.partial_cmp (&b.1.0.y).unwrap();
71 if cmp == Ordering::Equal {
72 a.1.0.x.partial_cmp (&b.1.0.x).unwrap()
73 } else {
74 cmp
75 }
76 }).unwrap().0;
77 let start_point = indexed_points[start_index].1;
78 indexed_points.sort_by (|a, b| {
80 if a.0 == start_index {
81 return Ordering::Less
82 }
83 if b.0 == start_index {
84 return Ordering::Greater
85 }
86 let angle_a = (a.1.0.y - start_point.0.y)
87 .atan2 (a.1.0.x - start_point.0.x);
88 let angle_b = (b.1.0.y - start_point.0.y)
89 .atan2 (b.1.0.x - start_point.0.x);
90 let angle_cmp = angle_a.partial_cmp (&angle_b).unwrap();
91 if angle_cmp == Ordering::Equal {
92 let dist_a = (a.1.0.x - start_point.0.x).powi (2) +
94 (a.1.0.y - start_point.0.y).powi (2);
95 let dist_b = (b.1.0.x - start_point.0.x).powi (2) +
96 (b.1.0.y - start_point.0.y).powi (2);
97 dist_a.partial_cmp (&dist_b).unwrap()
98 } else {
99 angle_cmp
100 }
101 });
102 let mut stack : Vec <u32> = Vec::new();
104 for (point_index, point) in indexed_points {
105 while stack.len() >= 2 {
106 let top = stack[stack.len() - 1];
107 let second = stack[stack.len() -2];
108 let p1 = points[second as usize];
109 let p2 = points[top as usize];
110 let p3 = point;
111 let det = Matrix2 {
112 cols: vector2 (p2 - p1, p3 - p1)
113 }.determinant();
114 if det <= S::zero() {
115 stack.pop();
116 } else {
117 break
118 }
119 }
120 stack.push (point_index as u32)
121 }
122 Some (stack)
123 }
124}
125
126impl <S> Hull3 <S> {
127 pub fn from_points (points : &[Point3 <S>]) -> Option <Self> where
128 S : Real + approx::RelativeEq
129 {
130 match points.len() {
134 0 => return None,
135 1 => return Some (Hull3 { points: points.to_vec() }),
136 2 => {
137 let mut points = points.to_vec();
138 points.dedup();
139 return Some (Hull3 { points })
140 }
141 _ => {}
142 }
143 let get_point = |i : u32| points[i as usize];
144 let collect_points = |indices : &[u32]|
145 indices.iter().cloned().map (get_point).collect();
146 let sorted = {
147 let mut sorted = (0..points.len() as u32).collect::<Vec<_>>();
148 sorted.sort_by (|a, b|
149 Point3::partial_cmp (&get_point (*a), &get_point (*b)).unwrap());
150 sorted.dedup_by_key (|i| get_point(*i));
151 sorted
152 };
153 let mut hull = Vec::with_capacity (sorted.len());
154 hull.push (sorted[0]); let mut current = 1;
156 let mut dimension = 0;
157 for i in &sorted[current..] {
159 if get_point (hull[0]) != get_point (*i) {
160 dimension = 1;
161 break
162 }
163 current += 1;
164 }
165 debug_assert_eq!(hull.len(), 1);
166 if dimension == 0 {
167 let points = collect_points (hull.as_slice());
168 return Some (Hull3 { points })
169 }
170 hull.push (sorted[current]); current += 1;
173 for i in &sorted[current..] {
174 if !colinear_3d (&get_point (hull[0]), &get_point (hull[1]), &get_point (*i)) {
175 dimension = 2;
176 break
177 }
178 hull.push (sorted[current]);
179 current += 1;
180 }
181 if hull.len() > 2 {
182 hull.sort_by (|a, b|
184 Point3::partial_cmp (&get_point (*a), &get_point (*b)).unwrap());
185 hull.drain (1..hull.len()-1);
186 }
187 debug_assert_eq!(hull.len(), 2);
188 if dimension == 1 {
189 let points = collect_points (hull.as_slice());
190 return Some (Hull3 { points })
191 }
192 hull.push (sorted[current]); current += 1;
195 while current < sorted.len() {
196 if !coplanar_3d (
197 &get_point (hull[0]), &get_point (hull[1]), &get_point (hull[2]),
198 &get_point (sorted[current])
199 ) {
200 dimension = 3;
201 break
202 }
203 hull.push (sorted[current]);
204 current += 1;
205 }
206 if hull.len() > 3 {
207 let v0 = get_point (hull[0]);
209 let v1 = get_point (hull[1]);
210 let v2 = get_point (hull[2]);
211 let diff1 = v1 - v0;
212 let diff2 = v2 - v0;
213 let normal = diff1.cross (diff2);
214 let signs = normal.sigvec();
215 let c;
216 #[allow(clippy::collapsible_else_if)]
217 if normal.x > normal.y {
218 if normal.x > normal.z {
219 if signs[0] > S::zero() {
220 c = [1, 2];
221 } else {
222 c = [2, 1];
223 }
224 } else {
225 if signs[2] > S::zero() {
226 c = [0, 1];
227 } else {
228 c = [1, 0];
229 }
230 }
231 } else {
232 if normal.y > normal.z {
233 if signs[1] > S::zero() {
234 c = [2, 0];
235 } else {
236 c = [0, 2];
237 }
238 } else {
239 if signs[2] > S::zero() {
240 c = [0, 1];
241 } else {
242 c = [1, 0];
243 }
244 }
245 }
246 let projections = hull.iter().cloned()
247 .map (|i| point2 (get_point (i).0[c[0]], get_point (i).0[c[1]]))
248 .collect::<Vec <_>>();
249 let hull2_indices = Hull2::from_points_indices (projections.as_slice()).unwrap();
250 hull = hull2_indices.iter().map (|i| hull[*i as usize]).collect::<Vec <_>>();
251 }
252 if dimension == 2 {
253 let points = collect_points (hull.as_slice());
254 return Some (Hull3 { points })
255 }
256 let plane_side = |a, b, c, d| {
258 let [s0, s1, s2, s3] = [a, b, c, d].map (get_point);
259 let diff1 = s1 - s0;
260 let diff2 = s2 - s0;
261 let diff3 = s3 - s0;
262 diff1.dot (diff2.cross (diff3)).signum_or_zero()
263 };
264 let sign = plane_side (hull[0], hull[1], hull[2], sorted[current]);
265 let mut h0;
266 let mut h1;
267 let mut mesh = VertexEdgeTriangleMesh::default();
268 if sign > S::zero() {
269 h0 = hull[0];
270 for i in 1..hull.len()-1 {
271 h1 = hull[i];
272 let h2 = hull[i+1];
273 let _inserted = mesh.insert (h0, h2, h1);
274 debug_assert!(_inserted.is_some());
275 }
276 h0 = sorted[current];
277 let mut i1 = hull.len() - 1;
278 let mut i2 = 0;
279 while i2 < hull.len() {
280 h1 = hull[i1];
281 let h2 = hull[i2];
282 let _inserted = mesh.insert (h0, h1, h2);
283 debug_assert!(_inserted.is_some());
284 i1 = i2;
286 i2 += 1;
287 }
288 } else {
289 h0 = hull[0];
290 for i in 1..hull.len()-1 {
291 h1 = hull[i];
292 let h2 = hull[i+1];
293 let _inserted = mesh.insert (h0, h1, h2);
294 debug_assert!(_inserted.is_some());
295 }
296 h0 = sorted[current];
297 let mut i1 = hull.len() - 1;
298 let mut i2 = 0;
299 while i2 < hull.len() {
300 h1 = hull[i1];
301 let h2 = hull[i2];
302 let _inserted = mesh.insert (h0, h2, h1);
303 debug_assert!(_inserted.is_some());
304 i1 = i2;
306 i2 += 1;
307 }
308 }
309 let mut terminator : Vec <[u32; 2]> = Vec::new();
310 current += 1;
311 while current < sorted.len() {
312 let vertex = mesh.get_vertex (h0).unwrap();
313 h1 = sorted[current];
314 let mut visible = VecDeque::<TriangleKey>::new();
315 let mut visited = BTreeSet::<TriangleKey>::new();
316 for triangle_key in vertex.adjacent_triangles().iter() {
317 let triangle = mesh.get_triangle (triangle_key).unwrap();
318 let sign = plane_side (
319 triangle.vertices()[0], triangle.vertices()[1], triangle.vertices()[2], h1);
320 if sign > S::zero() {
321 visible.push_back (*triangle_key);
322 visited.insert (*triangle_key);
323 break
324 }
325 }
326 debug_assert!(visible.len() > 0);
327 debug_assert!(terminator.is_empty());
328 while visible.len() > 0 {
329 let triangle_key = visible.pop_front().unwrap();
330 let triangle = mesh.get_triangle (&triangle_key).cloned().unwrap();
331 for (i, adjacent_key) in triangle.adjacent_triangles().iter().enumerate() {
332 if let Some (key) = adjacent_key {
333 let adjacent = mesh.get_triangle (key).unwrap();
334 if plane_side (
335 adjacent.vertices()[0], adjacent.vertices()[1], adjacent.vertices()[2], h1
336 ) <= S::zero() {
337 terminator.push (
338 [triangle.vertices()[i], triangle.vertices()[(i + 1) % 3]]);
339 } else if visited.insert (*key) {
340 visible.push_back (*key);
341 }
342 }
343 }
344 visited.remove (&triangle_key);
345 let _removed = mesh.remove (
346 triangle.vertices()[0], triangle.vertices()[1], triangle.vertices()[2]);
347 debug_assert!(_removed);
348 }
349 for edge in terminator.drain (..) {
350 let _inserted = mesh.insert (edge[0], edge[1], h1);
351 debug_assert!(_inserted.is_some());
352 }
353 h0 = h1;
354 current += 1;
355 }
356 let points = mesh.vertices().keys().cloned().map (get_point).collect();
357 Some (Hull3 { points })
358 }
359
360 pub fn points (&self) -> &[Point3 <S>] {
361 &self.points
362 }
363}
364
365#[cfg(test)]
366mod tests {
367 use super::*;
368
369 #[test]
370 fn hull2() {
371 use crate::*;
372 let points : Vec <Point2 <f32>> = [
374 [ 1.0, 1.0],
375 [ 1.0, 1.0]
376 ].map (Point2::from).into_iter().collect();
377 let hull = Hull2::from_points (points.as_slice()).unwrap();
378 assert_eq!(hull.points(), &[[1.0, 1.0].into()]);
379 let points : Vec <Point2 <f32>> = [
381 [ 0.0, 0.0],
382 [ 1.0, 3.0],
383 [ 2.0, -3.0],
384 [-3.0, -1.0]
385 ].map (Point2::from).into_iter().collect();
386 let hull = Hull2::from_points (points.as_slice()).unwrap();
387 let points : Vec <Point2 <f32>> = [
389 [ 2.0, -3.0],
390 [ 1.0, 3.0],
391 [-3.0, -1.0]
392 ].map (Point2::from).into_iter().collect();
393 assert_eq!(hull.points(), points);
394 let points : Vec <Point2 <f32>> = [
396 [ 0.0, 2.0],
397 [-2.0, -2.0],
398 [ 0.0, -2.0],
399 [ 2.0, -2.0]
400 ].map (Point2::from).into_iter().collect();
401 let hull = Hull2::from_points (points.as_slice()).unwrap();
402 let points : Vec <Point2 <f32>> = [
404 [-2.0, -2.0],
405 [ 2.0, -2.0],
406 [ 0.0, 2.0]
407 ].map (Point2::from).into_iter().collect();
408 assert_eq!(hull.points(), points);
409 let points : Vec <Point2 <f32>> = [
411 [ 0.0, 6.0],
413 [ 1.0, 5.0],
414 [ 2.0, 4.0],
415 [ 3.0, 3.0],
416 [ 3.0, 1.0],
417 [ 3.0, -1.0],
418 [ 3.0, -3.0],
419 [ 1.0, -3.0],
420 [-1.0, -3.0],
421 [-3.0, -3.0],
422 [-3.0, -1.0],
423 [-3.0, 1.0],
424 [-3.0, 3.0],
425 [-2.0, 4.0],
426 [-1.0, 5.0],
427 [-1.0, 2.0],
429 [ 2.0, -1.0],
430 [ 0.0, 3.0],
431 [-2.0, -2.0]
432 ].map (Point2::from).into_iter().collect();
433 let hull = Hull2::from_points (points.as_slice()).unwrap();
434 let points : Vec <Point2 <f32>> = [
436 [-3.0, -3.0],
437 [ 3.0, -3.0],
438 [ 3.0, 3.0],
439 [ 0.0, 6.0],
440 [-3.0, 3.0]
441 ].map (Point2::from).into_iter().collect();
442 assert_eq!(hull.points(), points);
443 }
444
445 #[test]
446 fn hull3() {
447 let points : Vec <Point3 <f32>> = [
449 [-1.0, -4.0, -1.0],
450 [-1.0, -4.0, -1.0]
451 ].map (Point3::from).into_iter().collect();
452 let hull = Hull3::from_points (points.as_slice()).unwrap();
453 assert_eq!(hull.points(), &[
454 [-1.0, -4.0, -1.0]
455 ].map (Into::into));
456 let points : Vec <Point3 <f32>> = [
458 [-1.0, -4.0, -1.0],
459 [ 0.0, 0.0, 0.0],
460 [ 1.0, 4.0, 1.0]
461 ].map (Point3::from).into_iter().collect();
462 let hull = Hull3::from_points (points.as_slice()).unwrap();
463 assert_eq!(hull.points(), &[
464 [-1.0, -4.0, -1.0],
465 [ 1.0, 4.0, 1.0]
466 ].map (Into::into));
467 let points : Vec <Point3 <f32>> = [
469 [-1.0, -4.0, 0.0],
470 [ 2.0, 2.0, 0.0],
471 [-1.0, -1.0, 0.0],
472 [-4.0, -1.0, 0.0],
473 [ 0.0, 2.0, 0.0]
474 ].map (Point3::from).into_iter().collect();
475 let hull = Hull3::from_points (points.as_slice()).unwrap();
476 assert_eq!(hull.points(), &[
477 [-1.0, -4.0, 0.0],
478 [ 2.0, 2.0, 0.0],
479 [ 0.0, 2.0, 0.0],
480 [-4.0, -1.0, 0.0]
481 ].map (Into::into));
482 let points : Vec <Point3 <f32>> = [
484 [-1.0, -4.0, -1.0],
485 [ 2.0, 2.0, 2.0],
486 [-4.0, -1.0, 2.0],
487 [ 0.0, 2.0, -3.0]
488 ].map (Point3::from).into_iter().collect();
489 let hull = Hull3::from_points (points.as_slice()).unwrap();
490 assert_eq!(hull.points(), &[
491 [-1.0, -4.0, -1.0],
492 [ 2.0, 2.0, 2.0],
493 [-4.0, -1.0, 2.0],
494 [ 0.0, 2.0, -3.0]
495 ].map (Into::into));
496 let points : Vec <Point3 <f32>> = [
498 [-1.0, -4.0, -1.0],
499 [ 2.0, 2.0, 2.0],
500 [-4.0, -1.0, 2.0],
501 [ 0.0, 2.0, -3.0],
502 [ 0.1, 0.2, 0.3],
503 [-0.1, -0.2, -0.3],
504 [-0.1, 0.2, 0.3]
505 ].map (Point3::from).into_iter().collect();
506 let hull = Hull3::from_points (points.as_slice()).unwrap();
507 assert_eq!(hull.points(), &[
508 [-1.0, -4.0, -1.0],
509 [ 2.0, 2.0, 2.0],
510 [-4.0, -1.0, 2.0],
511 [ 0.0, 2.0, -3.0]
512 ].map (Into::into));
513 }
514}