parry3d_f64/transformation/convex_hull3/
initial_mesh.rs1use super::{ConvexHullError, TriangleFacet};
2use crate::math::Real;
3use crate::shape::Triangle;
4use crate::transformation;
5use crate::transformation::convex_hull_utils::support_point_id;
6use crate::utils;
7use alloc::{vec, vec::Vec};
8use core::cmp::Ordering;
9use na::{Point2, Point3, Vector3};
10
11#[derive(Debug)]
12pub enum InitialMesh {
13 Facets(Vec<TriangleFacet>),
14 ResultMesh(Vec<Point3<Real>>, Vec<[u32; 3]>),
15}
16
17fn build_degenerate_mesh_point(point: Point3<Real>) -> (Vec<Point3<Real>>, Vec<[u32; 3]>) {
18 let ta = [0u32; 3];
19 let tb = [0u32; 3];
20
21 (vec![point], vec![ta, tb])
22}
23
24fn build_degenerate_mesh_segment(
25 dir: &Vector3<Real>,
26 points: &[Point3<Real>],
27) -> (Vec<Point3<Real>>, Vec<[u32; 3]>) {
28 let a = utils::point_cloud_support_point(dir, points);
29 let b = utils::point_cloud_support_point(&-*dir, points);
30
31 let ta = [0u32, 1, 0];
32 let tb = [1u32, 0, 0];
33
34 (vec![a, b], vec![ta, tb])
35}
36
37pub fn try_get_initial_mesh(
38 original_points: &[Point3<Real>],
39 normalized_points: &mut [Point3<Real>],
40 undecidable: &mut Vec<usize>,
41) -> Result<InitialMesh, ConvexHullError> {
42 let eigvec;
46 let eigval;
47
48 #[cfg(not(feature = "improved_fixed_point_support"))]
49 {
50 let cov_mat = utils::cov(normalized_points);
51 let eig = cov_mat.symmetric_eigen();
52 eigvec = eig.eigenvectors;
53 eigval = eig.eigenvalues;
54 }
55
56 #[cfg(feature = "improved_fixed_point_support")]
57 {
58 eigvec = Matrix3::identity();
59 eigval = Vector3::repeat(1.0);
60 }
61
62 let mut eigpairs = [
63 (eigvec.column(0).into_owned(), eigval[0]),
64 (eigvec.column(1).into_owned(), eigval[1]),
65 (eigvec.column(2).into_owned(), eigval[2]),
66 ];
67
68 eigpairs.sort_by(|a, b| {
72 if a.1 > b.1 {
73 Ordering::Less } else if a.1 < b.1 {
75 Ordering::Greater
76 } else {
77 Ordering::Equal
78 }
79 });
80
81 let mut dimension = 0;
85 while dimension < 3 {
86 if relative_eq!(eigpairs[dimension].1, 0.0, epsilon = 1.0e-7) {
87 break;
88 }
89
90 dimension += 1;
91 }
92
93 match dimension {
94 0 => {
95 let (vtx, idx) = build_degenerate_mesh_point(original_points[0]);
97 Ok(InitialMesh::ResultMesh(vtx, idx))
98 }
99 1 => {
100 let (vtx, idx) = build_degenerate_mesh_segment(&eigpairs[0].0, original_points);
102 Ok(InitialMesh::ResultMesh(vtx, idx))
103 }
104 2 => {
105 let axis1 = &eigpairs[0].0;
108 let axis2 = &eigpairs[1].0;
109
110 let mut subspace_points = Vec::with_capacity(normalized_points.len());
111
112 for point in normalized_points.iter() {
113 subspace_points.push(Point2::new(
114 point.coords.dot(axis1),
115 point.coords.dot(axis2),
116 ))
117 }
118
119 let idx = transformation::convex_hull2_idx(&subspace_points[..]);
121
122 let npoints = idx.len();
124 let coords = idx.into_iter().map(|i| original_points[i]).collect();
125 let mut triangles = Vec::with_capacity(npoints + npoints - 4);
126
127 for id in 1u32..npoints as u32 - 1 {
128 triangles.push([0, id, id + 1]);
129 }
130
131 for id in 0u32..npoints as u32 - 2 {
135 let a = npoints as u32 - 1;
136 triangles.push([a, id + 1, id]);
137 }
138
139 Ok(InitialMesh::ResultMesh(coords, triangles))
140 }
141 3 => {
142 let center = utils::center(normalized_points);
145
146 for point in normalized_points.iter_mut() {
147 *point = Point3::from((*point - center) / eigval.amax());
148 }
149
150 let p1 = support_point_id(&eigpairs[0].0, normalized_points)
151 .ok_or(ConvexHullError::MissingSupportPoint)?;
152 let p2 = support_point_id(&-eigpairs[0].0, normalized_points)
153 .ok_or(ConvexHullError::MissingSupportPoint)?;
154
155 let mut max_area = 0.0;
156 let mut p3 = usize::MAX;
157
158 for (i, point) in normalized_points.iter().enumerate() {
159 let area =
160 Triangle::new(normalized_points[p1], normalized_points[p2], *point).area();
161
162 if area > max_area {
163 max_area = area;
164 p3 = i;
165 }
166 }
167
168 if p3 == usize::MAX {
169 Err(ConvexHullError::InternalError("no triangle found."))
170 } else {
171 let mut f1 = TriangleFacet::new(p1, p2, p3, normalized_points);
173 let mut f2 = TriangleFacet::new(p2, p1, p3, normalized_points);
174
175 f1.set_facets_adjascency(1, 1, 1, 0, 2, 1);
177 f2.set_facets_adjascency(0, 0, 0, 0, 2, 1);
178
179 let mut facets = vec![f1, f2];
180
181 for point in 0..normalized_points.len() {
184 if normalized_points[point] == normalized_points[p1]
185 || normalized_points[point] == normalized_points[p2]
186 || normalized_points[point] == normalized_points[p3]
187 {
188 continue;
189 }
190
191 let mut furthest = usize::MAX;
192 let mut furthest_dist = 0.0;
193
194 for (i, curr_facet) in facets.iter().enumerate() {
195 if curr_facet.can_see_point(point, normalized_points) {
196 let distance = curr_facet.distance_to_point(point, normalized_points);
197
198 if distance > furthest_dist {
199 furthest = i;
200 furthest_dist = distance;
201 }
202 }
203 }
204
205 if furthest != usize::MAX {
206 facets[furthest].add_visible_point(point, normalized_points);
207 } else {
208 undecidable.push(point);
209 }
210
211 }
213
214 super::check_facet_links(0, &facets[..]);
215 super::check_facet_links(1, &facets[..]);
216
217 Ok(InitialMesh::Facets(facets))
218 }
219 }
220 _ => Err(ConvexHullError::Unreachable),
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 #[test]
227 #[cfg(feature = "f32")]
228 fn try_get_initial_mesh_should_fail_for_missing_support_points() {
233 use super::*;
234 use crate::transformation::try_convex_hull;
235 use na::Point3;
236
237 let point_cloud = vec![
238 Point3::new(103.05024, 303.44974, 106.125),
239 Point3::new(103.21692, 303.44974, 106.125015),
240 Point3::new(104.16538, 303.44974, 106.125),
241 Point3::new(106.55025, 303.44974, 106.125),
242 Point3::new(106.55043, 303.44974, 106.125),
243 ];
244 let result = try_convex_hull(&point_cloud);
245 assert_eq!(ConvexHullError::MissingSupportPoint, result.unwrap_err());
246 }
247}