1use crate::bounding_volume::Aabb;
2use crate::math::{Isometry, Point, Real, Vector};
3use crate::partitioning::Qbvh;
4use crate::shape::{FeatureId, Shape, Triangle, TrianglePseudoNormals, TypedSimdCompositeShape};
5use crate::utils::HashablePartialEq;
6use alloc::{vec, vec::Vec};
7use core::fmt;
8#[cfg(feature = "dim3")]
9use {crate::shape::Cuboid, crate::utils::SortedPair, na::Unit};
10
11use {
12 crate::shape::composite_shape::SimdCompositeShape,
13 crate::utils::hashmap::{Entry, HashMap},
14 crate::utils::hashset::HashSet,
15};
16
17#[cfg(feature = "dim2")]
18use crate::transformation::ear_clipping::triangulate_ear_clipping;
19
20use crate::query::details::NormalConstraints;
21#[cfg(feature = "rkyv")]
22use rkyv::{bytecheck, CheckBytes};
23
24#[derive(thiserror::Error, Copy, Clone, Debug, PartialEq, Eq)]
26pub enum TopologyError {
27 #[error("the triangle {0} has at least two identical vertices.")]
29 BadTriangle(u32),
30 #[error("the triangles {triangle1} and {triangle2} sharing the edge {edge:?} have opposite orientations.")]
32 BadAdjacentTrianglesOrientation {
33 triangle1: u32,
35 triangle2: u32,
37 edge: (u32, u32),
39 },
40}
41
42#[derive(thiserror::Error, Copy, Clone, Debug, PartialEq, Eq)]
44pub enum TriMeshBuilderError {
45 #[error("A triangle mesh must contain at least one triangle.")]
47 EmptyIndices,
48 #[error("Topology Error: {0}")]
50 TopologyError(TopologyError),
51}
52
53#[derive(Default, Clone)]
60#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
61#[cfg_attr(
62 feature = "rkyv",
63 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
64 archive(check_bytes)
65)]
66#[repr(C)]
67#[cfg(feature = "dim3")]
68pub struct TriMeshPseudoNormals {
69 pub vertices_pseudo_normal: Vec<Vector<Real>>,
71 pub edges_pseudo_normal: Vec<[Vector<Real>; 3]>,
73}
74
75#[derive(Debug, Clone)]
77#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
78#[cfg_attr(
79 feature = "rkyv",
80 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
81 archive(check_bytes)
82)]
83#[repr(C)]
84pub struct TriMeshConnectedComponents {
85 pub face_colors: Vec<u32>,
88 pub grouped_faces: Vec<u32>,
90 pub ranges: Vec<usize>,
93}
94
95impl TriMeshConnectedComponents {
96 pub fn num_connected_components(&self) -> usize {
98 self.ranges.len() - 1
99 }
100
101 pub fn to_mesh_buffers(&self, mesh: &TriMesh) -> Vec<(Vec<Point<Real>>, Vec<[u32; 3]>)> {
107 let mut result = vec![];
108 let mut new_vtx_index: Vec<_> = vec![u32::MAX; mesh.vertices.len()];
109
110 for ranges in self.ranges.windows(2) {
111 let num_faces = ranges[1] - ranges[0];
112
113 if num_faces == 0 {
114 continue;
115 }
116
117 let mut vertices = Vec::with_capacity(num_faces);
118 let mut indices = Vec::with_capacity(num_faces);
119
120 for fid in ranges[0]..ranges[1] {
121 let vids = mesh.indices[self.grouped_faces[fid] as usize];
122 let new_vids = vids.map(|id| {
123 if new_vtx_index[id as usize] == u32::MAX {
124 vertices.push(mesh.vertices[id as usize]);
125 new_vtx_index[id as usize] = vertices.len() as u32 - 1;
126 }
127
128 new_vtx_index[id as usize]
129 });
130 indices.push(new_vids);
131 }
132
133 result.push((vertices, indices));
134 }
135
136 result
137 }
138
139 pub fn to_meshes(
146 &self,
147 mesh: &TriMesh,
148 flags: TriMeshFlags,
149 ) -> Vec<Result<TriMesh, TriMeshBuilderError>> {
150 self.to_mesh_buffers(mesh)
151 .into_iter()
152 .map(|(vtx, idx)| TriMesh::with_flags(vtx, idx, flags))
153 .collect()
154 }
155}
156
157#[derive(Clone, Copy, Debug)]
159#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
160#[cfg_attr(
161 feature = "rkyv",
162 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
163 archive(as = "Self")
164)]
165#[repr(C)]
166pub struct TopoVertex {
167 pub half_edge: u32,
169}
170
171#[derive(Clone, Copy, Debug)]
173#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
174#[cfg_attr(
175 feature = "rkyv",
176 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
177 archive(as = "Self")
178)]
179#[repr(C)]
180pub struct TopoFace {
181 pub half_edge: u32,
184}
185
186#[derive(Clone, Copy, Debug)]
188#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
189#[cfg_attr(
190 feature = "rkyv",
191 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, CheckBytes),
192 archive(as = "Self")
193)]
194#[repr(C)]
195pub struct TopoHalfEdge {
196 pub next: u32,
198 pub twin: u32,
202 pub vertex: u32,
204 pub face: u32,
206}
207
208#[derive(Default, Clone)]
210#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
211#[cfg_attr(
212 feature = "rkyv",
213 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
214 archive(check_bytes)
215)]
216#[repr(C)]
217pub struct TriMeshTopology {
218 pub vertices: Vec<TopoVertex>,
220 pub faces: Vec<TopoFace>,
222 pub half_edges: Vec<TopoHalfEdge>,
224}
225
226#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
227#[cfg_attr(
228 feature = "rkyv",
229 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
230 archive(as = "Self")
231)]
232#[repr(C)]
233#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
234pub struct TriMeshFlags(u16);
236
237bitflags::bitflags! {
238 impl TriMeshFlags: u16 {
239 const HALF_EDGE_TOPOLOGY = 1;
241 const CONNECTED_COMPONENTS = 1 << 1;
243 const DELETE_BAD_TOPOLOGY_TRIANGLES = 1 << 2;
245 const ORIENTED = 1 << 3;
249 const MERGE_DUPLICATE_VERTICES = 1 << 4;
254 const DELETE_DEGENERATE_TRIANGLES = 1 << 5;
260 const DELETE_DUPLICATE_TRIANGLES = 1 << 6;
267 const FIX_INTERNAL_EDGES = (1 << 7) | Self::MERGE_DUPLICATE_VERTICES.bits();
274 }
275}
276
277#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
278#[cfg_attr(
279 feature = "rkyv",
280 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
281 archive(check_bytes)
282)]
283#[repr(C)]
284#[derive(Clone)]
285pub struct TriMesh {
287 qbvh: Qbvh<u32>,
288 vertices: Vec<Point<Real>>,
289 indices: Vec<[u32; 3]>,
290 #[cfg(feature = "dim3")]
291 pub(crate) pseudo_normals: Option<TriMeshPseudoNormals>,
292 topology: Option<TriMeshTopology>,
293 connected_components: Option<TriMeshConnectedComponents>,
294 flags: TriMeshFlags,
295}
296
297impl fmt::Debug for TriMesh {
298 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299 write!(f, "GenericTriMesh")
300 }
301}
302
303impl TriMesh {
304 pub fn new(
306 vertices: Vec<Point<Real>>,
307 indices: Vec<[u32; 3]>,
308 ) -> Result<Self, TriMeshBuilderError> {
309 Self::with_flags(vertices, indices, TriMeshFlags::empty())
310 }
311
312 pub fn with_flags(
314 vertices: Vec<Point<Real>>,
315 indices: Vec<[u32; 3]>,
316 flags: TriMeshFlags,
317 ) -> Result<Self, TriMeshBuilderError> {
318 if indices.is_empty() {
319 return Err(TriMeshBuilderError::EmptyIndices);
320 }
321
322 let mut result = Self {
323 qbvh: Qbvh::new(),
324 vertices,
325 indices,
326 #[cfg(feature = "dim3")]
327 pseudo_normals: None,
328 topology: None,
329 connected_components: None,
330 flags: TriMeshFlags::empty(),
331 };
332
333 let _ = result.set_flags(flags);
334
335 if result.qbvh.raw_nodes().is_empty() {
336 result.rebuild_qbvh();
338 }
339
340 Ok(result)
341 }
342
343 pub fn set_flags(&mut self, flags: TriMeshFlags) -> Result<(), TopologyError> {
345 let mut result = Ok(());
346 let prev_indices_len = self.indices.len();
347
348 if !flags.contains(TriMeshFlags::HALF_EDGE_TOPOLOGY) {
349 self.topology = None;
350 }
351
352 #[cfg(feature = "dim3")]
353 if !flags.intersects(TriMeshFlags::ORIENTED | TriMeshFlags::FIX_INTERNAL_EDGES) {
354 self.pseudo_normals = None;
355 }
356
357 if !flags.contains(TriMeshFlags::CONNECTED_COMPONENTS) {
358 self.connected_components = None;
359 }
360
361 let difference = flags & !self.flags;
362
363 if difference.intersects(
364 TriMeshFlags::MERGE_DUPLICATE_VERTICES
365 | TriMeshFlags::DELETE_DEGENERATE_TRIANGLES
366 | TriMeshFlags::DELETE_DUPLICATE_TRIANGLES,
367 ) {
368 self.merge_duplicate_vertices(
369 flags.contains(TriMeshFlags::DELETE_DEGENERATE_TRIANGLES),
370 flags.contains(TriMeshFlags::DELETE_DUPLICATE_TRIANGLES),
371 )
372 }
373
374 if difference.intersects(
375 TriMeshFlags::HALF_EDGE_TOPOLOGY | TriMeshFlags::DELETE_BAD_TOPOLOGY_TRIANGLES,
376 ) {
377 result =
378 self.compute_topology(flags.contains(TriMeshFlags::DELETE_BAD_TOPOLOGY_TRIANGLES));
379 }
380
381 #[cfg(feature = "std")]
382 if difference.intersects(TriMeshFlags::CONNECTED_COMPONENTS) {
383 self.compute_connected_components();
384 }
385
386 #[cfg(feature = "dim3")]
387 if difference.intersects(TriMeshFlags::ORIENTED | TriMeshFlags::FIX_INTERNAL_EDGES) {
388 self.compute_pseudo_normals();
389 }
390
391 if prev_indices_len != self.indices.len() {
392 self.rebuild_qbvh();
393 }
394
395 self.flags = flags;
396 result
397 }
398
399 pub fn total_memory_size(&self) -> usize {
403 size_of::<Self>() + self.heap_memory_size()
404 }
405
406 pub fn heap_memory_size(&self) -> usize {
408 let Self {
410 qbvh,
411 vertices,
412 indices,
413 topology,
414 connected_components,
415 flags: _,
416 #[cfg(feature = "dim3")]
417 pseudo_normals,
418 } = self;
419 let sz_qbvh = qbvh.heap_memory_size();
420 let sz_vertices = vertices.capacity() * size_of::<Point<Real>>();
421 let sz_indices = indices.capacity() * size_of::<[u32; 3]>();
422 #[cfg(feature = "dim3")]
423 let sz_pseudo_normals = pseudo_normals
424 .as_ref()
425 .map(|pn| {
426 pn.vertices_pseudo_normal.capacity() * size_of::<Vector<Real>>()
427 + pn.edges_pseudo_normal.capacity() * size_of::<[Vector<Real>; 3]>()
428 })
429 .unwrap_or(0);
430 #[cfg(feature = "dim2")]
431 let sz_pseudo_normals = 0;
432 let sz_topology = topology
433 .as_ref()
434 .map(|t| {
435 t.vertices.capacity() * size_of::<TopoVertex>()
436 + t.faces.capacity() * size_of::<TopoFace>()
437 + t.half_edges.capacity() * size_of::<TopoHalfEdge>()
438 })
439 .unwrap_or(0);
440 let sz_connected_components = connected_components
441 .as_ref()
442 .map(|c| {
443 c.face_colors.capacity() * size_of::<u32>()
444 + c.grouped_faces.capacity() * size_of::<f32>()
445 + c.ranges.capacity() * size_of::<usize>()
446 })
447 .unwrap_or(0);
448
449 sz_qbvh
450 + sz_vertices
451 + sz_indices
452 + sz_pseudo_normals
453 + sz_topology
454 + sz_connected_components
455 }
456
457 pub fn transform_vertices(&mut self, transform: &Isometry<Real>) {
459 self.vertices
460 .iter_mut()
461 .for_each(|pt| *pt = transform * *pt);
462 self.rebuild_qbvh();
463
464 #[cfg(feature = "dim3")]
466 if let Some(pseudo_normals) = &mut self.pseudo_normals {
467 pseudo_normals
468 .vertices_pseudo_normal
469 .iter_mut()
470 .for_each(|n| *n = transform * *n);
471 pseudo_normals.edges_pseudo_normal.iter_mut().for_each(|n| {
472 n[0] = transform * n[0];
473 n[1] = transform * n[1];
474 n[2] = transform * n[2];
475 });
476 }
477 }
478
479 pub fn scaled(mut self, scale: &Vector<Real>) -> Self {
481 self.vertices
482 .iter_mut()
483 .for_each(|pt| pt.coords.component_mul_assign(scale));
484
485 #[cfg(feature = "dim3")]
486 if let Some(pn) = &mut self.pseudo_normals {
487 pn.vertices_pseudo_normal.iter_mut().for_each(|n| {
488 n.component_mul_assign(scale);
489 let _ = n.try_normalize_mut(0.0);
490 });
491 pn.edges_pseudo_normal.iter_mut().for_each(|n| {
492 n[0].component_mul_assign(scale);
493 n[1].component_mul_assign(scale);
494 n[2].component_mul_assign(scale);
495
496 let _ = n[0].try_normalize_mut(0.0);
497 let _ = n[1].try_normalize_mut(0.0);
498 let _ = n[2].try_normalize_mut(0.0);
499 });
500 }
501
502 Self {
503 qbvh: self.qbvh.scaled(scale),
504 vertices: self.vertices,
505 indices: self.indices,
506 #[cfg(feature = "dim3")]
507 pseudo_normals: self.pseudo_normals,
508 topology: self.topology,
509 connected_components: self.connected_components,
510 flags: self.flags,
511 }
512 }
513
514 pub fn append(&mut self, rhs: &TriMesh) {
516 let base_id = self.vertices.len() as u32;
517 self.vertices.extend_from_slice(rhs.vertices());
518 self.indices.extend(
519 rhs.indices()
520 .iter()
521 .map(|idx| [idx[0] + base_id, idx[1] + base_id, idx[2] + base_id]),
522 );
523
524 let vertices = core::mem::take(&mut self.vertices);
525 let indices = core::mem::take(&mut self.indices);
526 *self = TriMesh::with_flags(vertices, indices, self.flags).unwrap();
527 }
528
529 #[cfg(feature = "dim2")]
533 pub fn from_polygon(vertices: Vec<Point<Real>>) -> Option<Self> {
534 triangulate_ear_clipping(&vertices).map(|indices| Self::new(vertices, indices).unwrap())
535 }
536
537 pub fn flat_indices(&self) -> &[u32] {
539 unsafe {
540 let len = self.indices.len() * 3;
541 let data = self.indices.as_ptr() as *const u32;
542 core::slice::from_raw_parts(data, len)
543 }
544 }
545
546 fn rebuild_qbvh(&mut self) {
547 let data = self.indices.iter().enumerate().map(|(i, idx)| {
548 let aabb = Triangle::new(
549 self.vertices[idx[0] as usize],
550 self.vertices[idx[1] as usize],
551 self.vertices[idx[2] as usize],
552 )
553 .local_aabb();
554 (i as u32, aabb)
555 });
556
557 self.qbvh.clear_and_rebuild(data, 0.0);
560 }
561
562 pub fn reverse(&mut self) {
564 self.indices.iter_mut().for_each(|idx| idx.swap(0, 1));
565
566 #[cfg(feature = "dim3")]
571 if let Some(pseudo_normals) = &mut self.pseudo_normals {
572 for n in &mut pseudo_normals.vertices_pseudo_normal {
573 *n = -*n;
574 }
575
576 for n in pseudo_normals.edges_pseudo_normal.iter_mut() {
577 n[0] = -n[0];
578 n[1] = -n[1];
579 n[2] = -n[2];
580 }
581 }
582
583 if self.flags.contains(TriMeshFlags::HALF_EDGE_TOPOLOGY) {
584 let _ = self.compute_topology(false);
586 }
587 }
588
589 fn merge_duplicate_vertices(
598 &mut self,
599 delete_degenerate_triangles: bool,
600 delete_duplicate_triangles: bool,
601 ) {
602 let mut vtx_to_id = HashMap::default();
603 let mut new_vertices = Vec::with_capacity(self.vertices.len());
604 let mut new_indices = Vec::with_capacity(self.indices.len());
605 let mut triangle_set = HashSet::default();
606
607 fn resolve_coord_id(
608 coord: &Point<Real>,
609 vtx_to_id: &mut HashMap<HashablePartialEq<Point<Real>>, u32>,
610 new_vertices: &mut Vec<Point<Real>>,
611 ) -> u32 {
612 let key = HashablePartialEq::new(*coord);
613 let id = match vtx_to_id.entry(key) {
614 Entry::Occupied(entry) => entry.into_mut(),
615 Entry::Vacant(entry) => entry.insert(new_vertices.len() as u32),
616 };
617
618 if *id == new_vertices.len() as u32 {
619 new_vertices.push(*coord);
620 }
621
622 *id
623 }
624
625 for t in self.indices.iter() {
626 let va = resolve_coord_id(
627 &self.vertices[t[0] as usize],
628 &mut vtx_to_id,
629 &mut new_vertices,
630 );
631
632 let vb = resolve_coord_id(
633 &self.vertices[t[1] as usize],
634 &mut vtx_to_id,
635 &mut new_vertices,
636 );
637
638 let vc = resolve_coord_id(
639 &self.vertices[t[2] as usize],
640 &mut vtx_to_id,
641 &mut new_vertices,
642 );
643
644 let is_degenerate = va == vb || va == vc || vb == vc;
645
646 if !is_degenerate || !delete_degenerate_triangles {
647 if delete_duplicate_triangles {
648 let (c, b, a) = crate::utils::sort3(&va, &vb, &vc);
649 if triangle_set.insert((*a, *b, *c)) {
650 new_indices.push([va, vb, vc])
651 }
652 } else {
653 new_indices.push([va, vb, vc]);
654 }
655 }
656 }
657
658 new_vertices.shrink_to_fit();
659
660 self.vertices = new_vertices;
661 self.indices = new_indices;
662
663 #[cfg(feature = "dim3")]
665 if self.pseudo_normals.is_some() {
666 self.compute_pseudo_normals();
667 }
668
669 #[cfg(feature = "dim3")]
671 if self.topology.is_some() {
672 let _ = self.compute_topology(false);
673 }
674 }
675
676 #[cfg(feature = "dim3")]
677 fn compute_pseudo_normals(&mut self) {
695 let mut vertices_pseudo_normal = vec![Vector::zeros(); self.vertices().len()];
696 let mut edges_pseudo_normal = HashMap::default();
697 let mut edges_multiplicity = HashMap::default();
698
699 for idx in self.indices() {
700 let vtx = self.vertices();
701 let tri = Triangle::new(
702 vtx[idx[0] as usize],
703 vtx[idx[1] as usize],
704 vtx[idx[2] as usize],
705 );
706
707 if let Some(n) = tri.normal() {
708 let ang1 = (tri.b - tri.a).angle(&(tri.c - tri.a));
709 let ang2 = (tri.a - tri.b).angle(&(tri.c - tri.b));
710 let ang3 = (tri.b - tri.c).angle(&(tri.a - tri.c));
711
712 vertices_pseudo_normal[idx[0] as usize] += *n * ang1;
713 vertices_pseudo_normal[idx[1] as usize] += *n * ang2;
714 vertices_pseudo_normal[idx[2] as usize] += *n * ang3;
715
716 let edges = [
717 SortedPair::new(idx[0], idx[1]),
718 SortedPair::new(idx[0], idx[2]),
719 SortedPair::new(idx[1], idx[2]),
720 ];
721
722 for edge in &edges {
723 let edge_n = edges_pseudo_normal
724 .entry(*edge)
725 .or_insert_with(Vector::zeros);
726 *edge_n += *n; let edge_mult = edges_multiplicity.entry(*edge).or_insert(0);
728 *edge_mult += 1;
729 }
730 }
731 }
732
733 let edges_pseudo_normal = self
734 .indices()
735 .iter()
736 .map(|idx| {
737 let e0 = SortedPair::new(idx[0], idx[1]);
738 let e1 = SortedPair::new(idx[1], idx[2]);
739 let e2 = SortedPair::new(idx[2], idx[0]);
740 let default = Vector::zeros();
741 [
742 edges_pseudo_normal.get(&e0).copied().unwrap_or(default),
743 edges_pseudo_normal.get(&e1).copied().unwrap_or(default),
744 edges_pseudo_normal.get(&e2).copied().unwrap_or(default),
745 ]
746 })
747 .collect();
748
749 self.pseudo_normals = Some(TriMeshPseudoNormals {
750 vertices_pseudo_normal,
751 edges_pseudo_normal,
752 })
753 }
754
755 fn delete_bad_topology_triangles(&mut self) {
756 let mut half_edge_set = HashSet::default();
757 let mut deleted_any = false;
758
759 self.indices.retain(|idx| {
761 if idx[0] == idx[1] || idx[0] == idx[2] || idx[1] == idx[2] {
762 deleted_any = true;
763 return false;
764 }
765
766 for k in 0..3 {
767 let edge_key = (idx[k as usize], idx[(k as usize + 1) % 3]);
768 if half_edge_set.contains(&edge_key) {
769 deleted_any = true;
770 return false;
771 }
772 }
773
774 for k in 0..3 {
775 let edge_key = (idx[k as usize], idx[(k as usize + 1) % 3]);
776 let _ = half_edge_set.insert(edge_key);
777 }
778
779 true
780 });
781 }
782
783 fn compute_topology(&mut self, delete_bad_triangles: bool) -> Result<(), TopologyError> {
795 if delete_bad_triangles {
796 self.delete_bad_topology_triangles();
797 }
798
799 let mut topology = TriMeshTopology::default();
800 let mut half_edge_map = HashMap::default();
801
802 topology.vertices.resize(
803 self.vertices.len(),
804 TopoVertex {
805 half_edge: u32::MAX,
806 },
807 );
808
809 for (fid, idx) in self.indices.iter().enumerate() {
811 let half_edge_base_id = topology.half_edges.len() as u32;
812
813 if idx[0] == idx[1] || idx[0] == idx[2] || idx[1] == idx[2] {
814 return Err(TopologyError::BadTriangle(fid as u32));
815 }
816
817 for k in 0u32..3 {
818 let half_edge = TopoHalfEdge {
819 next: half_edge_base_id + (k + 1) % 3,
820 twin: u32::MAX,
825 vertex: idx[k as usize],
826 face: fid as u32,
827 };
828 topology.half_edges.push(half_edge);
829
830 let edge_key = (idx[k as usize], idx[(k as usize + 1) % 3]);
831
832 if let Some(existing) = half_edge_map.insert(edge_key, half_edge_base_id + k) {
833 return Err(TopologyError::BadAdjacentTrianglesOrientation {
836 edge: edge_key,
837 triangle1: topology.half_edges[existing as usize].face,
838 triangle2: fid as u32,
839 });
840 }
841
842 topology.vertices[idx[k as usize] as usize].half_edge = half_edge_base_id + k;
843 }
844
845 topology.faces.push(TopoFace {
846 half_edge: half_edge_base_id,
847 })
848 }
849
850 for (key, he1) in &half_edge_map {
852 if key.0 < key.1 {
853 if let Some(he2) = half_edge_map.get(&(key.1, key.0)) {
855 topology.half_edges[*he1 as usize].twin = *he2;
856 topology.half_edges[*he2 as usize].twin = *he1;
857 }
858 }
859 }
860
861 self.topology = Some(topology);
862
863 Ok(())
864 }
865
866 #[cfg(feature = "std")]
870 fn compute_connected_components(&mut self) {
871 use ena::unify::{InPlaceUnificationTable, UnifyKey};
872
873 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
874 struct IntKey(u32);
875
876 impl UnifyKey for IntKey {
877 type Value = ();
878 fn index(&self) -> u32 {
879 self.0
880 }
881 fn from_index(u: u32) -> IntKey {
882 IntKey(u)
883 }
884 fn tag() -> &'static str {
885 "IntKey"
886 }
887 }
888
889 let mut ufind: InPlaceUnificationTable<IntKey> = InPlaceUnificationTable::new();
890 let mut face_colors = vec![u32::MAX; self.indices.len()];
891 let mut ranges = vec![0];
892 let mut vertex_to_range = vec![u32::MAX; self.vertices.len()];
893 let mut grouped_faces = vec![u32::MAX; self.indices.len()];
894 let mut vertex_to_key = vec![IntKey(u32::MAX); self.vertices.len()];
895
896 let mut vertex_key = |id: u32, ufind: &mut InPlaceUnificationTable<IntKey>| {
897 if vertex_to_key[id as usize].0 == u32::MAX {
898 let new_key = ufind.new_key(());
899 vertex_to_key[id as usize] = new_key;
900 new_key
901 } else {
902 vertex_to_key[id as usize]
903 }
904 };
905
906 for idx in self.indices() {
907 let keys = idx.map(|i| vertex_key(i, &mut ufind));
908 ufind.union(keys[0], keys[1]);
909 ufind.union(keys[1], keys[2]);
910 ufind.union(keys[2], keys[0]);
911 }
912
913 for (idx, face_color) in self.indices().iter().zip(face_colors.iter_mut()) {
914 debug_assert_eq!(
915 ufind.find(vertex_to_key[idx[0] as usize]),
916 ufind.find(vertex_to_key[idx[1] as usize])
917 );
918 debug_assert_eq!(
919 ufind.find(vertex_to_key[idx[0] as usize]),
920 ufind.find(vertex_to_key[idx[2] as usize])
921 );
922
923 let group_index = ufind.find(vertex_to_key[idx[0] as usize]).0 as usize;
924
925 if vertex_to_range[group_index] == u32::MAX {
926 ranges.push(0);
928 vertex_to_range[group_index] = ranges.len() as u32 - 1;
929 }
930
931 let range_id = vertex_to_range[group_index];
932 ranges[range_id as usize] += 1;
933 *face_color = range_id - 1;
935 }
936
937 for i in 1..ranges.len() {
940 ranges[i] += ranges[i - 1];
941 }
942
943 debug_assert_eq!(*ranges.last().unwrap(), self.indices().len());
944
945 let mut insertion_in_range_index = ranges.clone();
947 for (face_id, face_color) in face_colors.iter().enumerate() {
948 let insertion_index = &mut insertion_in_range_index[*face_color as usize];
949 grouped_faces[*insertion_index] = face_id as u32;
950 *insertion_index += 1;
951 }
952
953 self.connected_components = Some(TriMeshConnectedComponents {
954 face_colors,
955 grouped_faces,
956 ranges,
957 })
958 }
959
960 #[allow(dead_code)] pub(crate) fn assert_half_edge_topology_is_valid(&self) {
962 let topo = self
963 .topology
964 .as_ref()
965 .expect("No topology information found.");
966 assert_eq!(self.vertices.len(), topo.vertices.len());
967 assert_eq!(self.indices.len(), topo.faces.len());
968
969 for (face_id, (face, idx)) in topo.faces.iter().zip(self.indices.iter()).enumerate() {
970 let he0 = topo.half_edges[face.half_edge as usize];
971 assert_eq!(he0.face, face_id as u32);
972 assert_eq!(he0.vertex, idx[0]);
973 let he1 = topo.half_edges[he0.next as usize];
974 assert_eq!(he1.face, face_id as u32);
975 assert_eq!(he1.vertex, idx[1]);
976 let he2 = topo.half_edges[he1.next as usize];
977 assert_eq!(he2.face, face_id as u32);
978 assert_eq!(he2.vertex, idx[2]);
979 assert_eq!(he2.next, face.half_edge);
980 }
981
982 for he in &topo.half_edges {
983 let idx = &self.indices[he.face as usize];
984 assert!(he.vertex == idx[0] || he.vertex == idx[1] || he.vertex == idx[2]);
985 }
986 }
987
988 pub fn triangles(&self) -> impl ExactSizeIterator<Item = Triangle> + '_ {
990 self.indices.iter().map(move |ids| {
991 Triangle::new(
992 self.vertices[ids[0] as usize],
993 self.vertices[ids[1] as usize],
994 self.vertices[ids[2] as usize],
995 )
996 })
997 }
998
999 #[cfg(feature = "dim3")]
1000 pub fn feature_normal(&self, feature: FeatureId) -> Option<Unit<Vector<Real>>> {
1002 match feature {
1003 FeatureId::Face(i) => self
1004 .triangle(i % self.num_triangles() as u32)
1005 .feature_normal(FeatureId::Face(0)),
1006 _ => None,
1007 }
1008 }
1009}
1010
1011impl TriMesh {
1012 pub fn flags(&self) -> TriMeshFlags {
1014 self.flags
1015 }
1016
1017 pub fn aabb(&self, pos: &Isometry<Real>) -> Aabb {
1019 self.qbvh.root_aabb().transform_by(pos)
1020 }
1021
1022 pub fn local_aabb(&self) -> &Aabb {
1024 self.qbvh.root_aabb()
1025 }
1026
1027 pub fn qbvh(&self) -> &Qbvh<u32> {
1029 &self.qbvh
1030 }
1031
1032 pub fn num_triangles(&self) -> usize {
1034 self.indices.len()
1035 }
1036
1037 pub fn is_backface(&self, feature: FeatureId) -> bool {
1039 if let FeatureId::Face(i) = feature {
1040 i >= self.indices.len() as u32
1041 } else {
1042 false
1043 }
1044 }
1045
1046 pub fn triangle(&self, i: u32) -> Triangle {
1048 let idx = self.indices[i as usize];
1049 Triangle::new(
1050 self.vertices[idx[0] as usize],
1051 self.vertices[idx[1] as usize],
1052 self.vertices[idx[2] as usize],
1053 )
1054 }
1055
1056 #[cfg(feature = "dim3")]
1062 pub fn triangle_normal_constraints(&self, i: u32) -> Option<TrianglePseudoNormals> {
1063 if self.flags.contains(TriMeshFlags::FIX_INTERNAL_EDGES) {
1064 let triangle = self.triangle(i);
1065 let pseudo_normals = self.pseudo_normals.as_ref()?;
1066 let edges_pseudo_normals = pseudo_normals.edges_pseudo_normal[i as usize];
1067
1068 Some(TrianglePseudoNormals {
1071 face: triangle.normal()?,
1072 edges: [
1073 Unit::try_new(edges_pseudo_normals[0], 1.0e-6)?,
1074 Unit::try_new(edges_pseudo_normals[1], 1.0e-6)?,
1075 Unit::try_new(edges_pseudo_normals[2], 1.0e-6)?,
1076 ],
1077 })
1078 } else {
1079 None
1080 }
1081 }
1082
1083 #[cfg(feature = "dim2")]
1084 #[doc(hidden)]
1085 pub fn triangle_normal_constraints(&self, _i: u32) -> Option<TrianglePseudoNormals> {
1086 None
1087 }
1088
1089 pub fn vertices(&self) -> &[Point<Real>] {
1091 &self.vertices
1092 }
1093
1094 pub fn indices(&self) -> &[[u32; 3]] {
1096 &self.indices
1097 }
1098
1099 pub fn topology(&self) -> Option<&TriMeshTopology> {
1101 self.topology.as_ref()
1102 }
1103
1104 pub fn connected_components(&self) -> Option<&TriMeshConnectedComponents> {
1106 self.connected_components.as_ref()
1107 }
1108
1109 pub fn connected_component_meshes(
1113 &self,
1114 flags: TriMeshFlags,
1115 ) -> Option<Vec<Result<TriMesh, TriMeshBuilderError>>> {
1116 self.connected_components()
1117 .map(|cc| cc.to_meshes(self, flags))
1118 }
1119
1120 #[cfg(feature = "dim3")]
1122 pub fn pseudo_normals(&self) -> Option<&TriMeshPseudoNormals> {
1123 self.pseudo_normals.as_ref()
1124 }
1125
1126 #[cfg(feature = "dim3")]
1129 pub fn pseudo_normals_if_oriented(&self) -> Option<&TriMeshPseudoNormals> {
1130 if self.flags.intersects(TriMeshFlags::ORIENTED) {
1131 self.pseudo_normals.as_ref()
1132 } else {
1133 None
1134 }
1135 }
1136}
1137
1138#[cfg(feature = "dim3")]
1139impl From<crate::shape::HeightField> for TriMesh {
1140 fn from(heightfield: crate::shape::HeightField) -> Self {
1141 let (vtx, idx) = heightfield.to_trimesh();
1142 TriMesh::new(vtx, idx).unwrap()
1143 }
1144}
1145
1146#[cfg(feature = "dim3")]
1147impl From<Cuboid> for TriMesh {
1148 fn from(cuboid: Cuboid) -> Self {
1149 let (vtx, idx) = cuboid.to_trimesh();
1150 TriMesh::new(vtx, idx).unwrap()
1151 }
1152}
1153
1154impl SimdCompositeShape for TriMesh {
1155 fn map_part_at(
1156 &self,
1157 i: u32,
1158 f: &mut dyn FnMut(Option<&Isometry<Real>>, &dyn Shape, Option<&dyn NormalConstraints>),
1159 ) {
1160 let tri = self.triangle(i);
1161 let normals = self.triangle_normal_constraints(i);
1162 f(
1163 None,
1164 &tri,
1165 normals.as_ref().map(|n| n as &dyn NormalConstraints),
1166 )
1167 }
1168
1169 fn qbvh(&self) -> &Qbvh<u32> {
1170 &self.qbvh
1171 }
1172}
1173
1174impl TypedSimdCompositeShape for TriMesh {
1175 type PartShape = Triangle;
1176 type PartNormalConstraints = TrianglePseudoNormals;
1177 type PartId = u32;
1178
1179 #[inline(always)]
1180 fn map_typed_part_at(
1181 &self,
1182 i: u32,
1183 mut f: impl FnMut(
1184 Option<&Isometry<Real>>,
1185 &Self::PartShape,
1186 Option<&Self::PartNormalConstraints>,
1187 ),
1188 ) {
1189 let tri = self.triangle(i);
1190 let pseudo_normals = self.triangle_normal_constraints(i);
1191 f(None, &tri, pseudo_normals.as_ref())
1192 }
1193
1194 #[inline(always)]
1195 fn map_untyped_part_at(
1196 &self,
1197 i: u32,
1198 mut f: impl FnMut(Option<&Isometry<Real>>, &dyn Shape, Option<&dyn NormalConstraints>),
1199 ) {
1200 let tri = self.triangle(i);
1201 let pseudo_normals = self.triangle_normal_constraints(i);
1202 f(
1203 None,
1204 &tri,
1205 pseudo_normals.as_ref().map(|n| n as &dyn NormalConstraints),
1206 )
1207 }
1208
1209 fn typed_qbvh(&self) -> &Qbvh<u32> {
1210 &self.qbvh
1211 }
1212}
1213
1214#[cfg(test)]
1215mod test {
1216 use crate::math::{Real, Vector};
1217 use crate::shape::{Cuboid, TriMesh, TriMeshFlags};
1218
1219 #[test]
1220 fn trimesh_error_empty_indices() {
1221 assert!(
1222 TriMesh::with_flags(vec![], vec![], TriMeshFlags::empty()).is_err(),
1223 "A triangle mesh with no triangles is invalid."
1224 );
1225 }
1226
1227 #[test]
1228 fn connected_components() {
1229 let (vtx, idx) = Cuboid::new(Vector::repeat(0.5)).to_trimesh();
1230
1231 let mut mesh = TriMesh::new(vtx.clone(), idx.clone()).unwrap();
1233
1234 for i in 1..10 {
1235 let cc_vtx = vtx
1236 .iter()
1237 .map(|pt| pt + Vector::repeat(2.0 * i as Real))
1238 .collect();
1239
1240 let to_append = TriMesh::new(cc_vtx, idx.clone()).unwrap();
1241 mesh.append(&to_append);
1242 }
1243
1244 mesh.set_flags(TriMeshFlags::CONNECTED_COMPONENTS).unwrap();
1245 let connected_components = mesh.connected_components().unwrap();
1246 assert_eq!(connected_components.num_connected_components(), 10);
1247
1248 let cc_meshes = connected_components.to_meshes(&mesh, TriMeshFlags::empty());
1249
1250 for cc in cc_meshes {
1251 let cc = cc.unwrap();
1252 assert_eq!(cc.vertices.len(), vtx.len());
1253 assert_eq!(cc.indices.len(), idx.len());
1254 }
1255 }
1256}