ncollide3d/transformation/
convex_hull2.rs
1use std::marker::PhantomData;
2
3#[cfg(feature = "dim2")]
4use crate::procedural::Polyline;
5use crate::transformation::convex_hull_utils::{indexed_support_point_id, support_point_id};
6use na::{self, Point2, Vector2};
7use simba::scalar::RealField;
8
9#[cfg(feature = "dim2")]
11pub fn convex_hull2<N: RealField + Copy>(points: &[Point2<N>]) -> Polyline<N> {
12 let idx = convex_hull2_idx(points);
13 let mut pts = Vec::new();
14
15 for id in idx.into_iter() {
16 pts.push(points[id].clone());
17 }
18
19 Polyline::new(pts, None)
20}
21
22pub fn convex_hull2_idx<N: RealField + Copy>(points: &[Point2<N>]) -> Vec<usize> {
25 let mut undecidable_points = Vec::new();
26 let mut segments = get_initial_polyline(points, &mut undecidable_points);
27
28 let mut i = 0;
29 while i != segments.len() {
30 if !segments[i].valid {
31 i = i + 1;
32 continue;
33 }
34
35 let pt_id =
36 indexed_support_point_id(&segments[i].normal, points, &segments[i].visible_points[..]);
37
38 if let Some(point) = pt_id {
39 segments[i].valid = false;
40
41 attach_and_push_facets2(
42 segments[i].prev,
43 segments[i].next,
44 point,
45 &points[..],
46 &mut segments,
47 i,
48 &mut undecidable_points,
49 );
50 }
51
52 i = i + 1;
53 }
54
55 let mut idx = Vec::new();
56 let mut curr_facet = 0;
57
58 while !segments[curr_facet].valid {
59 curr_facet = curr_facet + 1
60 }
61
62 let first_facet = curr_facet;
63
64 loop {
65 let curr = &segments[curr_facet];
66
67 assert!(curr.valid);
68
69 idx.push(curr.pts[0]);
70
71 curr_facet = curr.next;
72
73 if curr_facet == first_facet {
74 break;
75 }
76 }
77
78 idx
79}
80
81fn get_initial_polyline<N: RealField + Copy>(
82 points: &[Point2<N>],
83 undecidable: &mut Vec<usize>,
84) -> Vec<SegmentFacet<N>> {
85 let mut res = Vec::new();
86
87 assert!(points.len() >= 2);
88
89 let p1 = support_point_id(&Vector2::x(), points).unwrap();
90 let mut p2 = p1;
91
92 let direction = [-Vector2::x(), Vector2::y(), -Vector2::y()];
93
94 for dir in direction.iter() {
95 p2 = support_point_id(dir, points).unwrap();
96
97 let p1p2 = points[p2] - points[p1];
98
99 if !p1p2.norm_squared().is_zero() {
100 break;
101 }
102 }
103
104 assert!(
105 p1 != p2,
106 "Failed to build the 2d convex hull of this point cloud."
107 );
108
109 let mut f1 = SegmentFacet::new(p1, p2, 1, 1, points);
111 let mut f2 = SegmentFacet::new(p2, p1, 0, 0, points);
112
113 for i in 0..points.len() {
115 if i == p1 || i == p2 {
116 continue;
117 }
118 if f1.can_be_seen_by(i, points) {
119 f1.visible_points.push(i);
120 } else if f2.can_be_seen_by(i, points) {
121 f2.visible_points.push(i);
122 } else {
123 undecidable.push(i);
125 }
126 }
127
128 res.push(f1);
129 res.push(f2);
130
131 res
132}
133
134fn attach_and_push_facets2<N: RealField + Copy>(
135 prev_facet: usize,
136 next_facet: usize,
137 point: usize,
138 points: &[Point2<N>],
139 segments: &mut Vec<SegmentFacet<N>>,
140 removed_facet: usize,
141 undecidable: &mut Vec<usize>,
142) {
143 let new_facet1_id = segments.len();
144 let new_facet2_id = new_facet1_id + 1;
145 let prev_pt = segments[prev_facet].pts[1];
146 let next_pt = segments[next_facet].pts[0];
147
148 let mut new_facet1 = SegmentFacet::new(prev_pt, point, prev_facet, new_facet2_id, points);
149 let mut new_facet2 = SegmentFacet::new(point, next_pt, new_facet1_id, next_facet, points);
150
151 segments[prev_facet].next = new_facet1_id;
152 segments[next_facet].prev = new_facet2_id;
153
154 for visible_point in segments[removed_facet].visible_points.iter() {
156 if *visible_point == point {
157 continue;
158 }
159
160 if new_facet1.can_be_seen_by(*visible_point, points) {
161 new_facet1.visible_points.push(*visible_point);
162 } else if new_facet2.can_be_seen_by(*visible_point, points) {
163 new_facet2.visible_points.push(*visible_point);
164 }
165 }
167
168 let mut i = 0;
170
171 while i != undecidable.len() {
172 if new_facet1.can_be_seen_by(undecidable[i], points) {
173 new_facet1.visible_points.push(undecidable[i]);
174 let _ = undecidable.swap_remove(i);
175 } else if new_facet2.can_be_seen_by(undecidable[i], points) {
176 new_facet2.visible_points.push(undecidable[i]);
177 let _ = undecidable.swap_remove(i);
178 } else {
179 i = i + 1;
180 }
181 }
182
183 segments.push(new_facet1);
184 segments.push(new_facet2);
185}
186
187struct SegmentFacet<N: RealField + Copy> {
188 pub valid: bool,
189 pub normal: Vector2<N>,
190 pub next: usize,
191 pub prev: usize,
192 pub pts: [usize; 2],
193 pub visible_points: Vec<usize>,
194 pt_type: PhantomData<Point2<N>>,
195}
196
197impl<N: RealField + Copy> SegmentFacet<N> {
198 pub fn new(
199 p1: usize,
200 p2: usize,
201 prev: usize,
202 next: usize,
203 points: &[Point2<N>],
204 ) -> SegmentFacet<N> {
205 let p1p2 = points[p2] - points[p1];
206
207 let mut normal = Vector2::new(-p1p2.y, p1p2.x);
208
209 if normal.normalize_mut().is_zero() {
210 panic!("ConvexHull hull failure: a segment must not be affinely dependent.");
211 }
212
213 SegmentFacet {
214 valid: true,
215 normal: normal,
216 prev: prev,
217 next: next,
218 pts: [p1, p2],
219 visible_points: Vec::new(),
220 pt_type: PhantomData,
221 }
222 }
223
224 pub fn can_be_seen_by(&self, point: usize, points: &[Point2<N>]) -> bool {
225 let p0 = &points[self.pts[0]];
226 let pt = &points[point];
227
228 let _eps = N::default_epsilon();
229
230 (*pt - *p0).dot(&self.normal) > _eps * na::convert(100.0f64)
231 }
232}