1mod access;
48mod elements;
49pub mod integrations;
50mod iter;
51mod ops;
52mod plane_slice;
53pub mod primitives;
54#[cfg(feature = "rerun")]
55mod rerun_impl;
56mod selection;
57#[cfg(feature = "serde")]
58mod serialize;
59pub mod utils;
60
61pub use elements::*;
62pub use iter::*;
63pub use ops::*;
64pub use plane_slice::*;
65pub use selection::*;
66
67use hashbrown::HashMap;
68use parry3d::partitioning::{Bvh, BvhWorkspace};
69
70use glam::Vec3;
71use slotmap::{SecondaryMap, SlotMap};
72use tracing::{error, instrument};
73
74use crate::utils::unwrap_or_return;
75
76#[cfg(feature = "rerun")]
77lazy_static::lazy_static! {
78 pub static ref RR: rerun::RecordingStream = rerun::RecordingStreamBuilder::new("mesh_graph").spawn().unwrap();
79}
80
81#[derive(Clone, Default)]
85#[cfg_attr(feature = "bevy", derive(bevy::prelude::Component))]
86#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
87#[cfg_attr(
88 feature = "serde",
89 serde(from = "crate::serialize::MeshGraphIntermediate")
90)]
91pub struct MeshGraph {
92 #[cfg_attr(feature = "serde", serde(skip))]
94 pub bvh: Bvh,
95 #[cfg_attr(feature = "serde", serde(skip))]
97 pub bvh_workspace: BvhWorkspace,
98 #[cfg_attr(feature = "serde", serde(skip))]
100 pub index_to_face_id: HashMap<u32, FaceId>,
101 #[cfg_attr(feature = "serde", serde(skip))]
103 pub next_index: u32,
104
105 pub vertices: SlotMap<VertexId, Vertex>,
107 pub halfedges: SlotMap<HalfedgeId, Halfedge>,
109 pub faces: SlotMap<FaceId, Face>,
111
112 pub positions: SecondaryMap<VertexId, Vec3>,
114 pub vertex_normals: Option<SecondaryMap<VertexId, Vec3>>,
116
117 #[cfg_attr(feature = "serde", serde(skip))]
119 pub outgoing_halfedges: SecondaryMap<VertexId, Vec<HalfedgeId>>,
120}
121
122impl MeshGraph {
123 #[inline]
125 pub fn new() -> Self {
126 Self::default()
127 }
128
129 pub fn triangles(vertex_positions: &[Vec3]) -> Self {
134 assert!(
135 vertex_positions.len().is_multiple_of(3),
136 "Number of vertex positions should be a multiple of 3"
137 );
138
139 let mut unique_positions: Vec<Vec3> = Vec::with_capacity(vertex_positions.len() / 3);
141 let mut face_indices = Vec::with_capacity(vertex_positions.len());
142
143 for vertex_pos in vertex_positions {
144 let mut idx = None;
146 for (j, pos) in unique_positions.iter().enumerate() {
147 const EPSILON: f32 = 1e-5;
148
149 if pos.distance_squared(*vertex_pos) < EPSILON {
150 idx = Some(j);
151 break;
152 }
153 }
154
155 let vertex_idx = if let Some(idx) = idx {
157 idx
158 } else {
159 let new_idx = unique_positions.len();
160 unique_positions.push(*vertex_pos);
161
162 #[cfg(feature = "rerun")]
163 RR.log(
164 "meshgraph/construct/vertices",
165 &rerun::Points3D::new(unique_positions.iter().map(crate::utils::vec3_array)),
166 )
167 .unwrap();
168
169 new_idx
170 };
171
172 face_indices.push(vertex_idx);
174 }
175
176 Self::indexed_triangles(&unique_positions, &face_indices)
178 }
179
180 #[instrument]
183 pub fn indexed_triangles(vertex_positions: &[Vec3], face_indices: &[usize]) -> Self {
184 let mut mesh_graph = Self {
185 bvh: Bvh::new(),
186 bvh_workspace: BvhWorkspace::default(),
187 index_to_face_id: HashMap::with_capacity(face_indices.len() / 3),
188 next_index: 0,
189
190 vertices: SlotMap::with_capacity_and_key(vertex_positions.len()),
191 halfedges: SlotMap::with_capacity_and_key(face_indices.len()),
192 faces: SlotMap::with_capacity_and_key(face_indices.len() / 3),
193
194 positions: SecondaryMap::with_capacity(vertex_positions.len()),
195 vertex_normals: None,
196 outgoing_halfedges: SecondaryMap::with_capacity(vertex_positions.len()),
197 };
198
199 let mut vertex_ids = Vec::with_capacity(vertex_positions.len());
200
201 for pos in vertex_positions {
202 vertex_ids.push(mesh_graph.add_vertex(*pos));
203 }
204
205 for chunk in face_indices.chunks_exact(3) {
206 let a = vertex_ids[chunk[0]];
207 let b = vertex_ids[chunk[1]];
208 let c = vertex_ids[chunk[2]];
209
210 if a == b || b == c || c == a {
211 #[cfg(feature = "rerun")]
212 RR.log(
213 "meshgraph/construct/zero_face",
214 &rerun::Points3D::new(
215 [
216 mesh_graph.positions[a],
217 mesh_graph.positions[b],
218 mesh_graph.positions[c],
219 ]
220 .iter()
221 .map(crate::utils::vec3_array),
222 ),
223 )
224 .unwrap();
225
226 continue;
227 }
228
229 let he_a_id = mesh_graph.add_or_get_edge(a, b).start_to_end_he_id;
230 let he_b_id = mesh_graph.add_or_get_edge(b, c).start_to_end_he_id;
231 let he_c_id = mesh_graph.add_or_get_edge(c, a).start_to_end_he_id;
232
233 let _face_id = mesh_graph.add_face(he_a_id, he_b_id, he_c_id);
234 }
235
236 mesh_graph.make_all_outgoing_halfedges_boundary_if_possible();
237 mesh_graph.rebuild_bvh();
238
239 mesh_graph
240 }
241
242 pub fn compute_vertex_normal(&mut self, vertex_id: VertexId) {
244 if self.vertex_normals.is_none() {
245 return;
246 }
247
248 let vertex = unwrap_or_return!(self.vertices.get(vertex_id), "Vertex not found");
249
250 let mut normal = Vec3::ZERO;
251
252 for face_id in vertex.faces(self) {
253 let face = unwrap_or_return!(self.faces.get(face_id), "Face not found");
254 normal += unwrap_or_return!(face.normal(self), "Face normal not found");
255 }
256
257 self.vertex_normals
258 .as_mut()
259 .unwrap()
260 .insert(vertex_id, normal.normalize());
261 }
262
263 #[instrument(skip(self))]
265 pub fn compute_vertex_normals(&mut self) {
266 let mut normals = SecondaryMap::with_capacity(self.vertices.len());
267
268 for face in self.faces.values() {
269 let ha_a_id = face.halfedge;
270 let he_a = self.halfedges[ha_a_id];
271
272 let he_b_id = he_a
273 .next
274 .expect("Halfedge has definitely a face and thus a next halfedge");
275 let he_b = self.halfedges[he_b_id];
276
277 let a = match he_a.start_vertex(self) {
278 Some(v) => v,
279 None => {
280 error!("Start vertex not found");
281 continue;
282 }
283 };
284 let b = he_a.end_vertex;
285 let c = he_b.end_vertex;
286
287 let diff_a = self.positions[c] - self.positions[a];
288 let diff_b = self.positions[c] - self.positions[b];
289
290 let face_normal = diff_a.cross(diff_b);
292
293 *normals.entry(a).unwrap().or_default() += face_normal;
294 *normals.entry(b).unwrap().or_default() += face_normal;
295 *normals.entry(c).unwrap().or_default() += face_normal;
296 }
297
298 self.vertex_normals = Some(normals);
299 self.normalize_vertex_normals();
300 }
301
302 pub fn normalize_vertex_normals(&mut self) {
304 if let Some(normals) = &mut self.vertex_normals {
305 for normal in normals.values_mut() {
306 *normal = normal.normalize_or_zero();
307 }
308 }
309 }
310
311 #[inline]
313 pub fn optimize_bvh_incremental(&mut self) {
314 self.bvh.optimize_incremental(&mut self.bvh_workspace);
315 }
316
317 #[inline]
319 pub fn refit_bvh(&mut self) {
320 self.bvh.refit(&mut self.bvh_workspace);
321 }
322
323 #[inline]
325 pub fn rebuild_bvh(&mut self) {
326 self.bvh = Bvh::new();
327 self.bvh_workspace = BvhWorkspace::default();
328
329 for face in self.faces.values() {
330 self.bvh
331 .insert_or_update_partially(face.aabb(self), face.index, 0.0);
332 }
333 self.bvh
334 .rebuild(&mut self.bvh_workspace, Default::default());
335 }
336
337 #[instrument(skip_all)]
338 pub fn rebuild_outgoing_halfedges(&mut self) {
339 self.outgoing_halfedges.clear();
340
341 for halfedge in self.halfedges.values() {
342 let Some(twin_id) = halfedge.twin else {
343 error!("Halfedge has no twin");
344 continue;
345 };
346
347 let Some(entry) = self.outgoing_halfedges.entry(halfedge.end_vertex) else {
348 error!("Vertex key invalid");
349 continue;
350 };
351
352 entry.or_default().push(twin_id);
353 }
354 }
355}