1#[cfg(feature = "rerun")]
2use std::borrow::Borrow;
3
4#[cfg(any(test, feature = "rerun"))]
5use glam::Vec3;
6#[cfg(feature = "rerun")]
7use glam::{Quat, Vec2};
8
9#[cfg(feature = "rerun")]
10pub fn vec3_array(v: impl Borrow<Vec3>) -> [f32; 3] {
11 [v.borrow().x, v.borrow().y, v.borrow().z]
12}
13
14#[cfg(feature = "rerun")]
15pub fn vec2_array(v: impl Borrow<Vec2>) -> [f32; 3] {
16 [v.borrow().x, v.borrow().y, 0.0]
17}
18
19#[cfg(feature = "rerun")]
20pub fn quat_array(q: impl Borrow<Quat>) -> [f32; 4] {
21 [q.borrow().x, q.borrow().y, q.borrow().z, q.borrow().w]
22}
23
24#[macro_export]
25macro_rules! error_none {
26 ($msg:literal $(, $args:expr)*) => {
27 || {
28 tracing::error!($msg $(, $args)*);
29 None
30 }
31 };
32}
33
34macro_rules! unwrap_or_return {
35 ($code:expr, $error:expr, $ret:expr) => {
36 match $code {
37 Some(value) => value,
38 None => {
39 tracing::error!($error);
40 return $ret;
41 }
42 }
43 };
44 ($code:expr, $error:expr) => {
45 match $code {
46 Some(value) => value,
47 None => {
48 tracing::error!($error);
49 return;
50 }
51 }
52 };
53}
54
55#[cfg(test)]
59use crate::{HalfedgeId, MeshGraph, VertexId};
60
61#[cfg(test)]
64pub(crate) fn build_grid(n: usize) -> MeshGraph {
65 let mut g = MeshGraph::new();
66
67 let cell = 1.0;
68 let mut v = vec![vec![]; n + 1];
69 for (j, row) in v.iter_mut().enumerate() {
70 for i in 0..=n {
71 let id = g.add_vertex(Vec3::new(i as f32 * cell, j as f32 * cell, 0.0));
72 row.push(id);
73 }
74 }
75
76 let edge = |g: &mut MeshGraph, a: VertexId, b: VertexId| -> HalfedgeId {
77 g.add_or_get_edge(a, b).unwrap().start_to_end_he_id
78 };
79
80 for j in 0..n {
81 for i in 0..n {
82 let a = v[j][i];
83 let b = v[j][i + 1];
84 let c = v[j + 1][i + 1];
85 let d = v[j + 1][i];
86
87 let he_ab = edge(&mut g, a, b);
89 let he_bc = edge(&mut g, b, c);
90 let he_ca = edge(&mut g, c, a);
91 g.add_face(he_ab, he_bc, he_ca);
92
93 let he_ac = edge(&mut g, a, c);
94 let he_cd = edge(&mut g, c, d);
95 let he_da = edge(&mut g, d, a);
96 g.add_face(he_ac, he_cd, he_da);
97 }
98 }
99
100 g
101}
102
103#[cfg(test)]
107pub(crate) fn mesh_invariant_violations(mg: &MeshGraph) -> Vec<String> {
108 let mut problems = Vec::new();
109
110 for (he_id, he) in &mg.halfedges {
111 let Some(twin_id) = he.twin else {
112 problems.push(format!("he {he_id:?}: missing twin"));
113 continue;
114 };
115 match mg.halfedges.get(twin_id) {
116 Some(twin) if twin.twin == Some(he_id) => {}
117 _ => problems.push(format!(
118 "he {he_id:?}: twin {twin_id:?} does not point back"
119 )),
120 }
121
122 let Some(sv) = he.start_vertex(mg) else {
123 problems.push(format!("he {he_id:?}: no start vertex"));
124 continue;
125 };
126 if !mg.vertices.contains_key(sv) || !mg.positions.contains_key(sv) {
127 problems.push(format!("he {he_id:?}: start vertex {sv:?} is dead"));
128 }
129 if !mg.vertices.contains_key(he.end_vertex) || !mg.positions.contains_key(he.end_vertex) {
130 problems.push(format!(
131 "he {he_id:?}: end vertex {:?} is dead",
132 he.end_vertex
133 ));
134 }
135 if let Some(f) = he.face
136 && !mg.faces.contains_key(f)
137 {
138 problems.push(format!("he {he_id:?}: face {f:?} is dead"));
139 }
140 if let Some(n) = he.next
141 && !mg.halfedges.contains_key(n)
142 {
143 problems.push(format!("he {he_id:?}: next {n:?} is dead"));
144 }
145
146 match mg.outgoing_halfedges.get(sv) {
148 Some(list) if list.contains(&he_id) => {}
149 _ => problems.push(format!("he {he_id:?}: not in outgoing_halfedges[{sv:?}]")),
150 }
151 }
152
153 for (v_id, list) in &mg.outgoing_halfedges {
154 for &he_id in list {
155 let Some(he) = mg.halfedges.get(he_id) else {
156 problems.push(format!("outgoing_halfedges[{v_id:?}]: stale he {he_id:?}"));
157 continue;
158 };
159 if he.start_vertex(mg) != Some(v_id) {
160 problems.push(format!(
161 "outgoing_halfedges[{v_id:?}]: he {he_id:?} does not start here"
162 ));
163 }
164 }
165 }
166
167 problems
168}
169
170#[cfg(test)]
171pub(crate) fn get_tracing_subscriber() {
172 if let Err(e) = tracing_subscriber::fmt()
173 .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
174 .with_line_number(true)
175 .pretty()
176 .try_init()
177 {
178 tracing::warn!("Tracing subscriber already initialized: {}", e);
179 }
180}
181
182pub(crate) use unwrap_or_return;
183
184#[cfg(test)]
185fn extend_outer_corners(
186 meshgraph: &mut crate::MeshGraph,
187 new_vertex_ids: &mut Vec<crate::VertexId>,
188 outer_vertex_ids: &[crate::VertexId],
189 scalar: f32,
190 steps: usize,
191) {
192 if steps == 0 {
193 return;
194 }
195
196 let mut corner_vertex_ids = Vec::with_capacity(outer_vertex_ids.len());
197
198 for i in 0..outer_vertex_ids.len() {
200 let point_1 = meshgraph.positions.get(outer_vertex_ids[i]).unwrap();
201 let point_2 = meshgraph
202 .positions
203 .get(outer_vertex_ids[(i + 1) % outer_vertex_ids.len()])
204 .unwrap();
205
206 let mut point_3 = point_1
207 + ((point_2 - point_1) * 0.5)
208 + (point_1 + point_2).normalize() * scalar / steps as f32;
209
210 point_3.z = 0.0; let vertex_id = meshgraph.add_vertex(point_3);
213 corner_vertex_ids.push(vertex_id);
214 }
215
216 for cv_i in 0..corner_vertex_ids.len() {
217 let corner_vertex_id = corner_vertex_ids[cv_i];
218 let vertex_id = outer_vertex_ids[cv_i];
219 let next_vertext_id = outer_vertex_ids[(cv_i + 1) % outer_vertex_ids.len()];
220 let halfedge_vertex_to_corner_id = meshgraph
221 .add_or_get_edge(vertex_id, corner_vertex_id)
222 .unwrap()
223 .start_to_end_he_id;
224 let halfedge_vertex_to_next_vertex_id = meshgraph
225 .add_or_get_edge(vertex_id, next_vertext_id)
226 .unwrap()
227 .start_to_end_he_id;
228
229 meshgraph
230 .add_face_from_halfedges(
231 halfedge_vertex_to_corner_id,
232 halfedge_vertex_to_next_vertex_id,
233 )
234 .unwrap();
235
236 let halfedge_corner_to_next_vertex_id = meshgraph
237 .add_or_get_edge(corner_vertex_id, next_vertext_id)
238 .unwrap()
239 .start_to_end_he_id;
240
241 let halfedge_next_vertex_to_next_corner_vertex_id = meshgraph
242 .add_or_get_edge(
243 next_vertext_id,
244 corner_vertex_ids[(cv_i + 1) % corner_vertex_ids.len()],
245 )
246 .unwrap()
247 .start_to_end_he_id;
248
249 meshgraph
250 .add_face_from_halfedges(
251 halfedge_corner_to_next_vertex_id,
252 halfedge_next_vertex_to_next_corner_vertex_id,
253 )
254 .unwrap();
255 }
256
257 extend_outer_corners(
258 meshgraph,
259 new_vertex_ids,
260 &corner_vertex_ids,
261 scalar,
262 steps - 1,
263 );
264
265 new_vertex_ids.extend(corner_vertex_ids);
266}
267
268#[cfg(test)]
272pub(crate) fn extend_with(
273 meshgraph: &mut crate::MeshGraph,
274 center_and_points: &[Vec3],
275 matrix: glam::Mat4,
276 scalar: f32,
277 steps: usize,
278) -> Vec<crate::VertexId> {
279 let (center, points) = center_and_points.split_first().unwrap();
280 let center_id = meshgraph.add_vertex(*center);
281
282 let mut vertex_ids = Vec::new();
283 let mut halfedge_ids = Vec::new();
284
285 for point in points {
286 let vertex_id = meshgraph.add_vertex(*point);
287 let halfedge_id = meshgraph
288 .add_or_get_edge(center_id, vertex_id)
289 .unwrap()
290 .start_to_end_he_id;
291
292 vertex_ids.push(vertex_id);
293 halfedge_ids.push(halfedge_id);
294 }
295
296 for i in 0..points.len() {
297 meshgraph
298 .add_face_from_halfedges(halfedge_ids[i], halfedge_ids[(i + 1) % points.len()])
299 .unwrap();
300 }
301
302 let mut new_vertex_ids = vec![center_id];
303 new_vertex_ids.extend(vertex_ids.clone());
304 extend_outer_corners(meshgraph, &mut new_vertex_ids, &vertex_ids, scalar, steps);
305
306 for new_vertex_id in new_vertex_ids.iter() {
307 if let Some(pos) = meshgraph.positions.get_mut(*new_vertex_id) {
308 *pos = matrix.transform_point3(*pos);
309 };
310 }
311
312 new_vertex_ids
313}