parry3d_f64/transformation/convex_hull3/
initial_mesh.rs1use super::{ConvexHullError, TriangleFacet};
2use crate::math::{MatExt, Vector2, Vector3};
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;
9
10#[derive(Debug)]
11pub enum InitialMesh {
12 Facets(Vec<TriangleFacet>),
13 ResultMesh(Vec<Vector3>, Vec<[u32; 3]>),
14}
15
16fn build_degenerate_mesh_point(point: Vector3) -> (Vec<Vector3>, Vec<[u32; 3]>) {
17 let ta = [0u32; 3];
18 let tb = [0u32; 3];
19
20 (vec![point], vec![ta, tb])
21}
22
23fn build_degenerate_mesh_segment(
24 dir: Vector3,
25 points: &[Vector3],
26) -> (Vec<Vector3>, Vec<[u32; 3]>) {
27 let a = utils::point_cloud_support_point(dir, points);
28 let b = utils::point_cloud_support_point(-dir, points);
29
30 let ta = [0u32, 1, 0];
31 let tb = [1u32, 0, 0];
32
33 (vec![a, b], vec![ta, tb])
34}
35
36pub fn try_get_initial_mesh(
37 original_points: &[Vector3],
38 normalized_points: &mut [Vector3],
39 undecidable: &mut Vec<usize>,
40) -> Result<InitialMesh, ConvexHullError> {
41 let eigvec;
45 let eigval;
46
47 #[cfg(not(feature = "improved_fixed_point_support"))]
48 {
49 let cov_mat = utils::cov(normalized_points);
50 let eig = cov_mat.symmetric_eigen();
51 eigvec = eig.eigenvectors;
52 eigval = eig.eigenvalues;
53 }
54
55 #[cfg(feature = "improved_fixed_point_support")]
56 {
57 use crate::math::{Matrix3, MatrixExt};
58 eigvec = Matrix3::identity();
59 eigval = Vector3::splat(1.0);
60 }
61
62 let mut eigpairs = [
63 (eigvec.x_axis, eigval[0]),
64 (eigvec.y_axis, eigval[1]),
65 (eigvec.z_axis, 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(Vector2::new(point.dot(axis1), point.dot(axis2)))
114 }
115
116 let idx = transformation::convex_hull2_idx(&subspace_points[..]);
118
119 let npoints = idx.len();
121 let coords = idx.into_iter().map(|i| original_points[i]).collect();
122 let mut triangles = Vec::with_capacity(npoints + npoints - 4);
123
124 for id in 1u32..npoints as u32 - 1 {
125 triangles.push([0, id, id + 1]);
126 }
127
128 for id in 0u32..npoints as u32 - 2 {
132 let a = npoints as u32 - 1;
133 triangles.push([a, id + 1, id]);
134 }
135
136 Ok(InitialMesh::ResultMesh(coords, triangles))
137 }
138 3 => {
139 let center = utils::center(normalized_points);
142
143 let max_eigval = {
145 let ax = eigval.x.abs();
146 let ay = eigval.y.abs();
147 let az = eigval.z.abs();
148 ax.max(ay).max(az)
149 };
150
151 for point in normalized_points.iter_mut() {
152 *point = Vector3::from((*point - center) / max_eigval);
153 }
154
155 let p1 = support_point_id(eigpairs[0].0, normalized_points)
156 .ok_or(ConvexHullError::MissingSupportPoint)?;
157 let p2 = support_point_id(-eigpairs[0].0, normalized_points)
158 .ok_or(ConvexHullError::MissingSupportPoint)?;
159
160 let mut max_area = 0.0;
161 let mut p3 = usize::MAX;
162
163 for (i, point) in normalized_points.iter().enumerate() {
164 let area =
165 Triangle::new(normalized_points[p1], normalized_points[p2], *point).area();
166
167 if area > max_area {
168 max_area = area;
169 p3 = i;
170 }
171 }
172
173 if p3 == usize::MAX {
174 Err(ConvexHullError::InternalError("no triangle found."))
175 } else {
176 let mut f1 = TriangleFacet::new(p1, p2, p3, normalized_points);
178 let mut f2 = TriangleFacet::new(p2, p1, p3, normalized_points);
179
180 f1.set_facets_adjascency(1, 1, 1, 0, 2, 1);
182 f2.set_facets_adjascency(0, 0, 0, 0, 2, 1);
183
184 let mut facets = vec![f1, f2];
185
186 for point in 0..normalized_points.len() {
189 if normalized_points[point] == normalized_points[p1]
190 || normalized_points[point] == normalized_points[p2]
191 || normalized_points[point] == normalized_points[p3]
192 {
193 continue;
194 }
195
196 let mut furthest = usize::MAX;
197 let mut furthest_dist = 0.0;
198
199 for (i, curr_facet) in facets.iter().enumerate() {
200 if curr_facet.can_see_point(point, normalized_points) {
201 let distance = curr_facet.distance_to_point(point, normalized_points);
202
203 if distance > furthest_dist {
204 furthest = i;
205 furthest_dist = distance;
206 }
207 }
208 }
209
210 if furthest != usize::MAX {
211 facets[furthest].add_visible_point(point, normalized_points);
212 } else {
213 undecidable.push(point);
214 }
215
216 }
218
219 super::check_facet_links(0, &facets[..]);
220 super::check_facet_links(1, &facets[..]);
221
222 Ok(InitialMesh::Facets(facets))
223 }
224 }
225 _ => Err(ConvexHullError::Unreachable),
226 }
227}
228
229#[cfg(test)]
230mod tests {
231 #[test]
232 #[cfg(feature = "f32")]
233 fn try_get_initial_mesh_should_fail_for_missing_support_points() {
234 use super::*;
235 use crate::math::Vector;
236 use crate::transformation::try_convex_hull;
237
238 let point_cloud = vec![
239 Vector::new(103.05024, 303.44974, 106.125),
240 Vector::new(103.21692, 303.44974, 106.125015),
241 Vector::new(104.16538, 303.44974, 106.125),
242 Vector::new(106.55025, 303.44974, 106.125),
243 Vector::new(106.55043, 303.44974, 106.125),
244 ];
245 let result = try_convex_hull(&point_cloud);
246 assert!(result.is_ok());
247 }
248}