parry3d/transformation/convex_hull3/
convex_hull.rs1use super::InitialMesh;
2use super::{ConvexHullError, TriangleFacet};
3use crate::math::Real;
4use crate::transformation::convex_hull_utils::indexed_support_point_nth;
5use crate::transformation::convex_hull_utils::{indexed_support_point_id, normalize};
6use crate::utils;
7use alloc::{vec, vec::Vec};
8use na::{self, Point3};
9
10pub fn convex_hull(points: &[Point3<Real>]) -> (Vec<Point3<Real>>, Vec<[u32; 3]>) {
12 try_convex_hull(points).unwrap()
13}
14
15pub fn try_convex_hull(
17 points: &[Point3<Real>],
18) -> Result<(Vec<Point3<Real>>, Vec<[u32; 3]>), ConvexHullError> {
19 if points.len() < 3 {
20 return Err(ConvexHullError::IncompleteInput);
21 }
22
23 let mut normalized_points = points.to_vec();
26 let _ = normalize(&mut normalized_points[..]);
27
28 let mut undecidable_points = Vec::new();
29 let mut silhouette_loop_facets_and_idx = Vec::new();
30 let mut removed_facets = Vec::new();
31
32 let mut triangles;
33
34 match super::try_get_initial_mesh(points, &mut normalized_points[..], &mut undecidable_points)?
35 {
36 InitialMesh::Facets(facets) => {
37 triangles = facets;
38 }
39 InitialMesh::ResultMesh(vertices, indices) => {
40 return Ok((vertices, indices));
41 }
42 }
43
44 let mut i = 0;
45 while i != triangles.len() {
46 silhouette_loop_facets_and_idx.clear();
47
48 if !triangles[i].valid || triangles[i].affinely_dependent {
49 i += 1;
50 continue;
51 }
52
53 let pt_id = indexed_support_point_id(
55 &triangles[i].normal,
56 &normalized_points[..],
57 triangles[i].visible_points[..].iter().copied(),
58 );
59
60 if let Some(point) = pt_id {
61 triangles[i].valid = false;
62
63 removed_facets.clear();
64 removed_facets.push(i);
65
66 for j in 0usize..3 {
67 compute_silhouette(
69 triangles[i].adj[j],
70 triangles[i].indirect_adj_id[j],
71 point,
72 &mut silhouette_loop_facets_and_idx,
73 &normalized_points[..],
74 &mut removed_facets,
75 &mut triangles[..],
76 );
77 }
78
79 fix_silhouette_topology(
83 &normalized_points,
84 &mut silhouette_loop_facets_and_idx,
85 &mut removed_facets,
86 &mut triangles[..],
87 )?;
88
89 if silhouette_loop_facets_and_idx.is_empty() {
99 let mut any_valid = false;
102 for triangle in &triangles[i + 1..] {
103 if triangle.valid && !triangle.affinely_dependent {
104 any_valid = true;
105 }
106 }
107
108 if any_valid {
109 return Err(ConvexHullError::InternalError(
110 "Internal error: exiting an unfinished work.",
111 ));
112 }
113
114 triangles[i].valid = true;
116 break;
117 }
118
119 attach_and_push_facets(
120 &silhouette_loop_facets_and_idx[..],
121 point,
122 &normalized_points[..],
123 &mut triangles,
124 &removed_facets[..],
125 &mut undecidable_points,
126 );
127
128 }
135
136 i += 1;
137 }
138
139 let mut idx = Vec::new();
140
141 for facet in triangles.iter() {
142 if facet.valid {
143 idx.push([
144 facet.pts[0] as u32,
145 facet.pts[1] as u32,
146 facet.pts[2] as u32,
147 ]);
148 }
149 }
150
151 let mut points = points.to_vec();
152 utils::remove_unused_points(&mut points, &mut idx[..]);
153 Ok((points, idx))
156}
157
158fn compute_silhouette(
159 facet: usize,
160 indirect_id: usize,
161 point: usize,
162 out_facets_and_idx: &mut Vec<(usize, usize)>,
163 points: &[Point3<Real>],
164 removed_facets: &mut Vec<usize>,
165 triangles: &mut [TriangleFacet],
166) {
167 if triangles[facet].valid {
168 if !triangles[facet].order_independent_can_be_seen_by_point(point, points) {
169 out_facets_and_idx.push((facet, indirect_id));
176 } else {
177 triangles[facet].valid = false; removed_facets.push(facet);
179 compute_silhouette(
182 triangles[facet].adj[(indirect_id + 1) % 3],
183 triangles[facet].indirect_adj_id[(indirect_id + 1) % 3],
184 point,
185 out_facets_and_idx,
186 points,
187 removed_facets,
188 triangles,
189 );
190
191 compute_silhouette(
192 triangles[facet].adj[(indirect_id + 2) % 3],
193 triangles[facet].indirect_adj_id[(indirect_id + 2) % 3],
194 point,
195 out_facets_and_idx,
196 points,
197 removed_facets,
198 triangles,
199 );
200 }
201 } else {
202 }
204}
205
206fn fix_silhouette_topology(
207 points: &[Point3<Real>],
208 out_facets_and_idx: &mut Vec<(usize, usize)>,
209 removed_facets: &mut Vec<usize>,
210 triangles: &mut [TriangleFacet],
211) -> Result<(), ConvexHullError> {
212 let mut workspace = vec![0; points.len()];
214 let mut needs_fixing = false;
215
216 for (facet, adj_id) in &*out_facets_and_idx {
220 let p = triangles[*facet].second_point_from_edge(*adj_id);
221 workspace[p] += 1;
222
223 if workspace[p] > 1 {
224 needs_fixing = true;
225 }
226 }
227
228 if needs_fixing {
231 let mut loop_start = 0;
234 for (facet, adj_id) in &*out_facets_and_idx {
235 let p1 = points[triangles[*facet].second_point_from_edge(*adj_id)];
236 let p2 = points[triangles[*facet].first_point_from_edge(*adj_id)];
237 let supp = indexed_support_point_nth(
238 &(p2 - p1),
239 points,
240 out_facets_and_idx
241 .iter()
242 .map(|(f, ai)| triangles[*f].second_point_from_edge(*ai)),
243 )
244 .ok_or(ConvexHullError::MissingSupportPoint)?;
245 let selected = &out_facets_and_idx[supp];
246 if workspace[triangles[selected.0].second_point_from_edge(selected.1)] == 1 {
247 loop_start = supp;
249 break;
250 }
251 }
252
253 let mut removing = None;
254 let old_facets_and_idx = core::mem::take(out_facets_and_idx);
255
256 for i in 0..old_facets_and_idx.len() {
257 let facet_id = (loop_start + i) % old_facets_and_idx.len();
258 let (facet, adj_id) = old_facets_and_idx[facet_id];
259
260 match removing {
261 Some(p) => {
262 let p1 = triangles[facet].second_point_from_edge(adj_id);
263 if p == p1 {
264 removing = None;
265 }
266 }
267 _ => {
268 let p1 = triangles[facet].second_point_from_edge(adj_id);
269 if workspace[p1] > 1 {
270 removing = Some(p1);
271 }
272 }
273 }
274
275 if removing.is_some() {
276 if triangles[facet].valid {
277 triangles[facet].valid = false;
278 removed_facets.push(facet);
279 }
280 } else {
281 out_facets_and_idx.push((facet, adj_id));
282 }
283
284 }
295
296 }
298
299 Ok(())
300}
301
302fn attach_and_push_facets(
303 silhouette_loop_facets_and_idx: &[(usize, usize)],
304 point: usize,
305 points: &[Point3<Real>],
306 triangles: &mut Vec<TriangleFacet>,
307 removed_facets: &[usize],
308 undecidable: &mut Vec<usize>,
309) {
310 let mut new_facets = Vec::with_capacity(silhouette_loop_facets_and_idx.len());
312
313 let mut adj_facet: usize;
315 let mut indirect_id: usize;
316
317 for silhouette_loop_facets_and_id in silhouette_loop_facets_and_idx {
318 adj_facet = silhouette_loop_facets_and_id.0;
319 indirect_id = silhouette_loop_facets_and_id.1;
320
321 let facet = TriangleFacet::new(
328 point,
329 triangles[adj_facet].second_point_from_edge(indirect_id),
330 triangles[adj_facet].first_point_from_edge(indirect_id),
331 points,
332 );
333 new_facets.push(facet);
334 }
335 for i in 0..silhouette_loop_facets_and_idx.len() {
339 let prev_facet = if i == 0 {
340 triangles.len() + silhouette_loop_facets_and_idx.len() - 1
341 } else {
342 triangles.len() + i - 1
343 };
344
345 let (middle_facet, middle_id) = silhouette_loop_facets_and_idx[i];
346 let next_facet = triangles.len() + (i + 1) % silhouette_loop_facets_and_idx.len();
347
348 new_facets[i].set_facets_adjascency(prev_facet, middle_facet, next_facet, 2, middle_id, 0);
349 assert!(!triangles[triangles[middle_facet].adj[middle_id]].valid); triangles[middle_facet].adj[middle_id] = triangles.len() + i; triangles[middle_facet].indirect_adj_id[middle_id] = 1;
352 }
353
354 for curr_facet in removed_facets.iter() {
357 for visible_point in triangles[*curr_facet].visible_points.iter() {
358 if points[*visible_point] == points[point] {
359 continue;
360 }
361
362 let mut furthest = usize::MAX;
363 let mut furthest_dist = 0.0;
364
365 for (i, curr_facet) in new_facets.iter_mut().enumerate() {
366 if !curr_facet.affinely_dependent {
367 let distance = curr_facet.distance_to_point(*visible_point, points);
368
369 if distance > furthest_dist {
370 furthest = i;
371 furthest_dist = distance;
372 }
373 }
374 }
375
376 if furthest != usize::MAX && new_facets[furthest].can_see_point(*visible_point, points)
377 {
378 new_facets[furthest].add_visible_point(*visible_point, points);
379 }
380
381 }
384 }
385
386 let mut i = 0;
388
389 while i != undecidable.len() {
390 let mut furthest = usize::MAX;
391 let mut furthest_dist = 0.0;
392 let undecidable_point = undecidable[i];
393
394 for (j, curr_facet) in new_facets.iter_mut().enumerate() {
395 if curr_facet.can_see_point(undecidable_point, points) {
396 let distance = curr_facet.distance_to_point(undecidable_point, points);
397
398 if distance > furthest_dist {
399 furthest = j;
400 furthest_dist = distance;
401 }
402 }
403 }
404
405 if furthest != usize::MAX {
406 new_facets[furthest].add_visible_point(undecidable_point, points);
407 let _ = undecidable.swap_remove(i);
408 } else {
409 i += 1;
410 }
411 }
412
413 triangles.append(&mut new_facets);
416}
417
418#[cfg(test)]
419mod test {
420 use crate::transformation;
421 #[cfg(feature = "dim2")]
422 use na::Point2;
423
424 #[cfg(feature = "dim2")]
425 #[test]
426 fn test_simple_convex_hull() {
427 let points = [
428 Point2::new(4.723881f32, 3.597233),
429 Point2::new(3.333363, 3.429991),
430 Point2::new(3.137215, 2.812263),
431 ];
432
433 let chull = transformation::convex_hull(points.as_slice());
434
435 assert!(chull.coords.len() == 3);
436 }
437
438 #[cfg(feature = "dim3")]
439 #[test]
440 fn test_ball_convex_hull() {
441 use crate::shape::Ball;
442
443 let (points, _) = Ball::new(0.4).to_trimesh(20, 20);
445 let (vertices, _) = transformation::convex_hull(points.as_slice());
446
447 assert!(vertices.len() == vertices.len());
449 }
450}