1#![cfg(any(
16 target_arch = "wasm32",
17 all(not(feature = "qhull"), feature = "quick_convex_hull")
18))]
19
20use glam_det::Point3;
21use log::warn;
22pub use qchull::Config;
23use qchull::{
24 build_convex_hull, ConvexHull as QuickConvexHull,
25 ConvexHullConstructError as QuickConvexHullConstructError,
26 ConvexHullConstructState as QuickConvexHullConstructState,
27};
28
29use crate::{
30 ConvexHull, ConvexHullConstructError, ConvexHullConstructState, ConvexMesh, HalfPlane,
31};
32
33impl ConvexHull {
34 pub fn new(
35 points: &[Point3],
36 config: &Config,
37 ) -> Result<(ConvexHull, ConvexHullConstructState), ConvexHullConstructError> {
38 let result = build_convex_hull(points, config);
39 match result {
40 Ok((hull, state)) => Ok((hull.into(), state.into())),
41 Err(e) => Err(e.into()),
42 }
43 }
44}
45
46impl From<QuickConvexHullConstructState> for ConvexHullConstructState {
47 fn from(state: QuickConvexHullConstructState) -> Self {
48 match state {
49 QuickConvexHullConstructState::Success => ConvexHullConstructState::Success,
50 QuickConvexHullConstructState::PointCountLessThanFour => {
51 ConvexHullConstructState::PointCountLessThanFour
52 }
53 QuickConvexHullConstructState::VolumeTooSmall => {
54 ConvexHullConstructState::VolumeTooSmall
55 }
56 QuickConvexHullConstructState::PointCountOverflow => {
57 ConvexHullConstructState::PointCountOverflow
58 }
59 QuickConvexHullConstructState::FaceCountLimitHit => {
60 ConvexHullConstructState::FaceCountLimitHit
61 }
62 }
63 }
64}
65
66impl From<QuickConvexHullConstructError> for ConvexHullConstructError {
67 fn from(error: QuickConvexHullConstructError) -> Self {
68 match error {
69 QuickConvexHullConstructError::Degenerate => ConvexHullConstructError::Degenerate,
70 }
71 }
72}
73
74impl From<QuickConvexHull> for crate::ConvexHull {
75 fn from(convex_hull: QuickConvexHull) -> Self {
76 let planes: Vec<_> = convex_hull
77 .bounding_planes
78 .iter()
79 .map(|v| HalfPlane {
80 normal: v.normal,
81 offset: v.offset,
82 center: v.center,
83 })
84 .collect();
85
86 crate::ConvexHull {
87 points: convex_hull.points,
88 bounding_planes: planes,
89 face_indices_start: convex_hull.face_indices_start,
90 face_vertex_indices: convex_hull.face_vertex_indices,
91 center: convex_hull.center,
92 volume: convex_hull.volume,
93 total_area: 1.0,
94 shift_center: convex_hull.shift_center,
95 debug: None,
96 }
97 }
98}
99
100impl From<qchull::ConvexMesh> for crate::ConvexMesh {
101 fn from(v: qchull::ConvexMesh) -> Self {
102 crate::ConvexMesh {
103 vertices: (v.vertices().to_vec()),
104 triangles: v.triangles().to_vec(),
105 }
106 }
107}
108
109impl crate::ConvexMesh {
110 pub fn new(
111 points: &[Point3],
112 ) -> Result<(crate::ConvexMesh, ConvexHullConstructState), ConvexHullConstructError> {
113 let mut config = Config::default();
114 config.set_shift_point_align_aabb_center(false);
115 let (hull, state) = ConvexHull::new(points, &config)?;
116 if state != ConvexHullConstructState::Success {
117 warn!("ConvexMesh state mismatch");
118 }
119 let iter = hull.triangle_index_iter();
120 let triangles = iter
121 .flat_map(|v| [v[0] as u32, v[1] as u32, v[2] as u32])
122 .collect::<Vec<_>>();
123 let vertices = hull.points;
124 Ok((
125 ConvexMesh {
126 vertices,
127 triangles,
128 },
129 state,
130 ))
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use glam_det::Point3;
137 use qchull::{
138 ConvexHullConstructError as QuickConvexHullConstructError,
139 ConvexHullConstructState as QuickConvexHullConstructState,
140 };
141 use wasm_bindgen_test::*;
142
143 use crate::{Config, ConvexHullConstructError, ConvexHullConstructState};
144 wasm_bindgen_test_configure!(run_in_browser);
145
146 #[test]
147 fn test_build_convex_face() {
148 let points = vec![Point3::new(0.0, 0.0, 0.0), Point3::new(0.0, 0.0, 0.1)];
149
150 let config = Config::default();
151 let result = crate::ConvexHull::new(&points, &config);
152 let (_hull, state) = result.unwrap();
153 assert_eq!(state, ConvexHullConstructState::PointCountLessThanFour);
154
155 let points = vec![
157 Point3::new(0.0, 0.0, 0.0),
158 Point3::new(1.0, 0.0, 0.0),
159 Point3::new(0.0, 1.0, 0.0),
160 Point3::new(0.0, 0.0, 1.0),
161 Point3::new(1.0, 1.0, 0.0),
162 Point3::new(1.0, 0.0, 1.0),
163 Point3::new(0.0, 1.0, 1.0),
164 Point3::new(1.0, 1.0, 1.0),
165 ];
166 let config = Config::default();
167 let result = crate::ConvexHull::new(&points, &config);
168 let (_hull, state) = result.unwrap();
169 assert_eq!(state, ConvexHullConstructState::Success);
170 }
171 #[test]
172 fn test_from_quick_convex_hull_construct_state() {
173 let quick_success = QuickConvexHullConstructState::Success;
175 let success: ConvexHullConstructState = quick_success.into();
176 assert_eq!(success, ConvexHullConstructState::Success);
177
178 let quick_point_count_less = QuickConvexHullConstructState::PointCountLessThanFour;
179 let point_count_less: ConvexHullConstructState = quick_point_count_less.into();
180 assert_eq!(
181 point_count_less,
182 ConvexHullConstructState::PointCountLessThanFour
183 );
184
185 let quick_volume_too_small = QuickConvexHullConstructState::VolumeTooSmall;
186 let volume_too_small: ConvexHullConstructState = quick_volume_too_small.into();
187 assert_eq!(volume_too_small, ConvexHullConstructState::VolumeTooSmall);
188
189 let quick_point_count_overflow = QuickConvexHullConstructState::PointCountOverflow;
190 let point_count_overflow: ConvexHullConstructState = quick_point_count_overflow.into();
191 assert_eq!(
192 point_count_overflow,
193 ConvexHullConstructState::PointCountOverflow
194 );
195
196 let quick_face_count_limit_hit = QuickConvexHullConstructState::FaceCountLimitHit;
197 let face_count_limit_hit: ConvexHullConstructState = quick_face_count_limit_hit.into();
198 assert_eq!(
199 face_count_limit_hit,
200 ConvexHullConstructState::FaceCountLimitHit
201 );
202 }
203
204 #[test]
205 fn test_from_quick_convex_hull_construct_error() {
206 let quick_degenerate = QuickConvexHullConstructError::Degenerate;
208 let degenerate: ConvexHullConstructError = quick_degenerate.into();
209 assert_eq!(degenerate, ConvexHullConstructError::Degenerate);
210 }
211}