1use crate::bounding_volume::Aabb;
2use crate::math::{Isometry, Point, Real, Vector};
3use crate::partitioning::{Bvh, BvhBuildStrategy};
4use crate::shape::{FeatureId, Shape, Triangle, TrianglePseudoNormals, TypedCompositeShape};
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::CompositeShape,
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 bvh: Bvh,
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 bvh: Bvh::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.bvh.is_empty() {
336 result.rebuild_bvh();
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_bvh();
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 bvh,
411 vertices,
412 indices,
413 topology,
414 connected_components,
415 flags: _,
416 #[cfg(feature = "dim3")]
417 pseudo_normals,
418 } = self;
419 let sz_bvh = bvh.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_bvh
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_bvh();
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 let mut bvh = self.bvh.clone();
503 bvh.scale(scale);
504
505 Self {
506 bvh,
507 vertices: self.vertices,
508 indices: self.indices,
509 #[cfg(feature = "dim3")]
510 pseudo_normals: self.pseudo_normals,
511 topology: self.topology,
512 connected_components: self.connected_components,
513 flags: self.flags,
514 }
515 }
516
517 pub fn append(&mut self, rhs: &TriMesh) {
519 let base_id = self.vertices.len() as u32;
520 self.vertices.extend_from_slice(rhs.vertices());
521 self.indices.extend(
522 rhs.indices()
523 .iter()
524 .map(|idx| [idx[0] + base_id, idx[1] + base_id, idx[2] + base_id]),
525 );
526
527 let vertices = core::mem::take(&mut self.vertices);
528 let indices = core::mem::take(&mut self.indices);
529 *self = TriMesh::with_flags(vertices, indices, self.flags).unwrap();
530 }
531
532 #[cfg(feature = "dim2")]
536 pub fn from_polygon(vertices: Vec<Point<Real>>) -> Option<Self> {
537 triangulate_ear_clipping(&vertices).map(|indices| Self::new(vertices, indices).unwrap())
538 }
539
540 pub fn flat_indices(&self) -> &[u32] {
542 unsafe {
543 let len = self.indices.len() * 3;
544 let data = self.indices.as_ptr() as *const u32;
545 core::slice::from_raw_parts(data, len)
546 }
547 }
548
549 fn rebuild_bvh(&mut self) {
550 let leaves = self.indices.iter().enumerate().map(|(i, idx)| {
551 let aabb = Triangle::new(
552 self.vertices[idx[0] as usize],
553 self.vertices[idx[1] as usize],
554 self.vertices[idx[2] as usize],
555 )
556 .local_aabb();
557 (i, aabb)
558 });
559
560 self.bvh = Bvh::from_iter(BvhBuildStrategy::Binned, leaves)
561 }
562
563 pub fn reverse(&mut self) {
565 self.indices.iter_mut().for_each(|idx| idx.swap(0, 1));
566
567 #[cfg(feature = "dim3")]
572 if let Some(pseudo_normals) = &mut self.pseudo_normals {
573 for n in &mut pseudo_normals.vertices_pseudo_normal {
574 *n = -*n;
575 }
576
577 for n in pseudo_normals.edges_pseudo_normal.iter_mut() {
578 n[0] = -n[0];
579 n[1] = -n[1];
580 n[2] = -n[2];
581 }
582 }
583
584 if self.flags.contains(TriMeshFlags::HALF_EDGE_TOPOLOGY) {
585 let _ = self.compute_topology(false);
587 }
588 }
589
590 fn merge_duplicate_vertices(
599 &mut self,
600 delete_degenerate_triangles: bool,
601 delete_duplicate_triangles: bool,
602 ) {
603 let mut vtx_to_id = HashMap::default();
604 let mut new_vertices = Vec::with_capacity(self.vertices.len());
605 let mut new_indices = Vec::with_capacity(self.indices.len());
606 let mut triangle_set = HashSet::default();
607
608 fn resolve_coord_id(
609 coord: &Point<Real>,
610 vtx_to_id: &mut HashMap<HashablePartialEq<Point<Real>>, u32>,
611 new_vertices: &mut Vec<Point<Real>>,
612 ) -> u32 {
613 let key = HashablePartialEq::new(*coord);
614 let id = match vtx_to_id.entry(key) {
615 Entry::Occupied(entry) => entry.into_mut(),
616 Entry::Vacant(entry) => entry.insert(new_vertices.len() as u32),
617 };
618
619 if *id == new_vertices.len() as u32 {
620 new_vertices.push(*coord);
621 }
622
623 *id
624 }
625
626 for t in self.indices.iter() {
627 let va = resolve_coord_id(
628 &self.vertices[t[0] as usize],
629 &mut vtx_to_id,
630 &mut new_vertices,
631 );
632
633 let vb = resolve_coord_id(
634 &self.vertices[t[1] as usize],
635 &mut vtx_to_id,
636 &mut new_vertices,
637 );
638
639 let vc = resolve_coord_id(
640 &self.vertices[t[2] as usize],
641 &mut vtx_to_id,
642 &mut new_vertices,
643 );
644
645 let is_degenerate = va == vb || va == vc || vb == vc;
646
647 if !is_degenerate || !delete_degenerate_triangles {
648 if delete_duplicate_triangles {
649 let (c, b, a) = crate::utils::sort3(&va, &vb, &vc);
650 if triangle_set.insert((*a, *b, *c)) {
651 new_indices.push([va, vb, vc])
652 }
653 } else {
654 new_indices.push([va, vb, vc]);
655 }
656 }
657 }
658
659 new_vertices.shrink_to_fit();
660
661 self.vertices = new_vertices;
662 self.indices = new_indices;
663
664 #[cfg(feature = "dim3")]
666 if self.pseudo_normals.is_some() {
667 self.compute_pseudo_normals();
668 }
669
670 #[cfg(feature = "dim3")]
672 if self.topology.is_some() {
673 let _ = self.compute_topology(false);
674 }
675 }
676
677 #[cfg(feature = "dim3")]
678 fn compute_pseudo_normals(&mut self) {
696 let mut vertices_pseudo_normal = vec![Vector::zeros(); self.vertices().len()];
697 let mut edges_pseudo_normal = HashMap::default();
698 let mut edges_multiplicity = HashMap::default();
699
700 for idx in self.indices() {
701 let vtx = self.vertices();
702 let tri = Triangle::new(
703 vtx[idx[0] as usize],
704 vtx[idx[1] as usize],
705 vtx[idx[2] as usize],
706 );
707
708 if let Some(n) = tri.normal() {
709 let ang1 = (tri.b - tri.a).angle(&(tri.c - tri.a));
710 let ang2 = (tri.a - tri.b).angle(&(tri.c - tri.b));
711 let ang3 = (tri.b - tri.c).angle(&(tri.a - tri.c));
712
713 vertices_pseudo_normal[idx[0] as usize] += *n * ang1;
714 vertices_pseudo_normal[idx[1] as usize] += *n * ang2;
715 vertices_pseudo_normal[idx[2] as usize] += *n * ang3;
716
717 let edges = [
718 SortedPair::new(idx[0], idx[1]),
719 SortedPair::new(idx[0], idx[2]),
720 SortedPair::new(idx[1], idx[2]),
721 ];
722
723 for edge in &edges {
724 let edge_n = edges_pseudo_normal
725 .entry(*edge)
726 .or_insert_with(Vector::zeros);
727 *edge_n += *n; let edge_mult = edges_multiplicity.entry(*edge).or_insert(0);
729 *edge_mult += 1;
730 }
731 }
732 }
733
734 let edges_pseudo_normal = self
735 .indices()
736 .iter()
737 .map(|idx| {
738 let e0 = SortedPair::new(idx[0], idx[1]);
739 let e1 = SortedPair::new(idx[1], idx[2]);
740 let e2 = SortedPair::new(idx[2], idx[0]);
741 let default = Vector::zeros();
742 [
743 edges_pseudo_normal.get(&e0).copied().unwrap_or(default),
744 edges_pseudo_normal.get(&e1).copied().unwrap_or(default),
745 edges_pseudo_normal.get(&e2).copied().unwrap_or(default),
746 ]
747 })
748 .collect();
749
750 self.pseudo_normals = Some(TriMeshPseudoNormals {
751 vertices_pseudo_normal,
752 edges_pseudo_normal,
753 })
754 }
755
756 fn delete_bad_topology_triangles(&mut self) {
757 let mut half_edge_set = HashSet::default();
758 let mut deleted_any = false;
759
760 self.indices.retain(|idx| {
762 if idx[0] == idx[1] || idx[0] == idx[2] || idx[1] == idx[2] {
763 deleted_any = true;
764 return false;
765 }
766
767 for k in 0..3 {
768 let edge_key = (idx[k as usize], idx[(k as usize + 1) % 3]);
769 if half_edge_set.contains(&edge_key) {
770 deleted_any = true;
771 return false;
772 }
773 }
774
775 for k in 0..3 {
776 let edge_key = (idx[k as usize], idx[(k as usize + 1) % 3]);
777 let _ = half_edge_set.insert(edge_key);
778 }
779
780 true
781 });
782 }
783
784 fn compute_topology(&mut self, delete_bad_triangles: bool) -> Result<(), TopologyError> {
796 if delete_bad_triangles {
797 self.delete_bad_topology_triangles();
798 }
799
800 let mut topology = TriMeshTopology::default();
801 let mut half_edge_map = HashMap::default();
802
803 topology.vertices.resize(
804 self.vertices.len(),
805 TopoVertex {
806 half_edge: u32::MAX,
807 },
808 );
809
810 for (fid, idx) in self.indices.iter().enumerate() {
812 let half_edge_base_id = topology.half_edges.len() as u32;
813
814 if idx[0] == idx[1] || idx[0] == idx[2] || idx[1] == idx[2] {
815 return Err(TopologyError::BadTriangle(fid as u32));
816 }
817
818 for k in 0u32..3 {
819 let half_edge = TopoHalfEdge {
820 next: half_edge_base_id + (k + 1) % 3,
821 twin: u32::MAX,
826 vertex: idx[k as usize],
827 face: fid as u32,
828 };
829 topology.half_edges.push(half_edge);
830
831 let edge_key = (idx[k as usize], idx[(k as usize + 1) % 3]);
832
833 if let Some(existing) = half_edge_map.insert(edge_key, half_edge_base_id + k) {
834 return Err(TopologyError::BadAdjacentTrianglesOrientation {
837 edge: edge_key,
838 triangle1: topology.half_edges[existing as usize].face,
839 triangle2: fid as u32,
840 });
841 }
842
843 topology.vertices[idx[k as usize] as usize].half_edge = half_edge_base_id + k;
844 }
845
846 topology.faces.push(TopoFace {
847 half_edge: half_edge_base_id,
848 })
849 }
850
851 for (key, he1) in &half_edge_map {
853 if key.0 < key.1 {
854 if let Some(he2) = half_edge_map.get(&(key.1, key.0)) {
856 topology.half_edges[*he1 as usize].twin = *he2;
857 topology.half_edges[*he2 as usize].twin = *he1;
858 }
859 }
860 }
861
862 self.topology = Some(topology);
863
864 Ok(())
865 }
866
867 #[cfg(feature = "std")]
871 fn compute_connected_components(&mut self) {
872 use ena::unify::{InPlaceUnificationTable, UnifyKey};
873
874 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
875 struct IntKey(u32);
876
877 impl UnifyKey for IntKey {
878 type Value = ();
879 fn index(&self) -> u32 {
880 self.0
881 }
882 fn from_index(u: u32) -> IntKey {
883 IntKey(u)
884 }
885 fn tag() -> &'static str {
886 "IntKey"
887 }
888 }
889
890 let mut ufind: InPlaceUnificationTable<IntKey> = InPlaceUnificationTable::new();
891 let mut face_colors = vec![u32::MAX; self.indices.len()];
892 let mut ranges = vec![0];
893 let mut vertex_to_range = vec![u32::MAX; self.vertices.len()];
894 let mut grouped_faces = vec![u32::MAX; self.indices.len()];
895 let mut vertex_to_key = vec![IntKey(u32::MAX); self.vertices.len()];
896
897 let mut vertex_key = |id: u32, ufind: &mut InPlaceUnificationTable<IntKey>| {
898 if vertex_to_key[id as usize].0 == u32::MAX {
899 let new_key = ufind.new_key(());
900 vertex_to_key[id as usize] = new_key;
901 new_key
902 } else {
903 vertex_to_key[id as usize]
904 }
905 };
906
907 for idx in self.indices() {
908 let keys = idx.map(|i| vertex_key(i, &mut ufind));
909 ufind.union(keys[0], keys[1]);
910 ufind.union(keys[1], keys[2]);
911 ufind.union(keys[2], keys[0]);
912 }
913
914 for (idx, face_color) in self.indices().iter().zip(face_colors.iter_mut()) {
915 debug_assert_eq!(
916 ufind.find(vertex_to_key[idx[0] as usize]),
917 ufind.find(vertex_to_key[idx[1] as usize])
918 );
919 debug_assert_eq!(
920 ufind.find(vertex_to_key[idx[0] as usize]),
921 ufind.find(vertex_to_key[idx[2] as usize])
922 );
923
924 let group_index = ufind.find(vertex_to_key[idx[0] as usize]).0 as usize;
925
926 if vertex_to_range[group_index] == u32::MAX {
927 ranges.push(0);
929 vertex_to_range[group_index] = ranges.len() as u32 - 1;
930 }
931
932 let range_id = vertex_to_range[group_index];
933 ranges[range_id as usize] += 1;
934 *face_color = range_id - 1;
936 }
937
938 for i in 1..ranges.len() {
941 ranges[i] += ranges[i - 1];
942 }
943
944 debug_assert_eq!(*ranges.last().unwrap(), self.indices().len());
945
946 let mut insertion_in_range_index = ranges.clone();
948 for (face_id, face_color) in face_colors.iter().enumerate() {
949 let insertion_index = &mut insertion_in_range_index[*face_color as usize];
950 grouped_faces[*insertion_index] = face_id as u32;
951 *insertion_index += 1;
952 }
953
954 self.connected_components = Some(TriMeshConnectedComponents {
955 face_colors,
956 grouped_faces,
957 ranges,
958 })
959 }
960
961 #[allow(dead_code)] pub(crate) fn assert_half_edge_topology_is_valid(&self) {
963 let topo = self
964 .topology
965 .as_ref()
966 .expect("No topology information found.");
967 assert_eq!(self.vertices.len(), topo.vertices.len());
968 assert_eq!(self.indices.len(), topo.faces.len());
969
970 for (face_id, (face, idx)) in topo.faces.iter().zip(self.indices.iter()).enumerate() {
971 let he0 = topo.half_edges[face.half_edge as usize];
972 assert_eq!(he0.face, face_id as u32);
973 assert_eq!(he0.vertex, idx[0]);
974 let he1 = topo.half_edges[he0.next as usize];
975 assert_eq!(he1.face, face_id as u32);
976 assert_eq!(he1.vertex, idx[1]);
977 let he2 = topo.half_edges[he1.next as usize];
978 assert_eq!(he2.face, face_id as u32);
979 assert_eq!(he2.vertex, idx[2]);
980 assert_eq!(he2.next, face.half_edge);
981 }
982
983 for he in &topo.half_edges {
984 let idx = &self.indices[he.face as usize];
985 assert!(he.vertex == idx[0] || he.vertex == idx[1] || he.vertex == idx[2]);
986 }
987 }
988
989 pub fn triangles(&self) -> impl ExactSizeIterator<Item = Triangle> + '_ {
991 self.indices.iter().map(move |ids| {
992 Triangle::new(
993 self.vertices[ids[0] as usize],
994 self.vertices[ids[1] as usize],
995 self.vertices[ids[2] as usize],
996 )
997 })
998 }
999
1000 #[cfg(feature = "dim3")]
1001 pub fn feature_normal(&self, feature: FeatureId) -> Option<Unit<Vector<Real>>> {
1003 match feature {
1004 FeatureId::Face(i) => self
1005 .triangle(i % self.num_triangles() as u32)
1006 .feature_normal(FeatureId::Face(0)),
1007 _ => None,
1008 }
1009 }
1010}
1011
1012impl TriMesh {
1013 pub fn flags(&self) -> TriMeshFlags {
1015 self.flags
1016 }
1017
1018 pub fn aabb(&self, pos: &Isometry<Real>) -> Aabb {
1020 self.bvh.root_aabb().transform_by(pos)
1021 }
1022
1023 pub fn local_aabb(&self) -> Aabb {
1025 self.bvh.root_aabb()
1026 }
1027
1028 pub fn bvh(&self) -> &Bvh {
1030 &self.bvh
1031 }
1032
1033 pub fn num_triangles(&self) -> usize {
1035 self.indices.len()
1036 }
1037
1038 pub fn is_backface(&self, feature: FeatureId) -> bool {
1040 if let FeatureId::Face(i) = feature {
1041 i >= self.indices.len() as u32
1042 } else {
1043 false
1044 }
1045 }
1046
1047 pub fn triangle(&self, i: u32) -> Triangle {
1049 let idx = self.indices[i as usize];
1050 Triangle::new(
1051 self.vertices[idx[0] as usize],
1052 self.vertices[idx[1] as usize],
1053 self.vertices[idx[2] as usize],
1054 )
1055 }
1056
1057 #[cfg(feature = "dim3")]
1063 pub fn triangle_normal_constraints(&self, i: u32) -> Option<TrianglePseudoNormals> {
1064 if self.flags.contains(TriMeshFlags::FIX_INTERNAL_EDGES) {
1065 let triangle = self.triangle(i);
1066 let pseudo_normals = self.pseudo_normals.as_ref()?;
1067 let edges_pseudo_normals = pseudo_normals.edges_pseudo_normal[i as usize];
1068
1069 Some(TrianglePseudoNormals {
1072 face: triangle.normal()?,
1073 edges: [
1074 Unit::try_new(edges_pseudo_normals[0], 1.0e-6)?,
1075 Unit::try_new(edges_pseudo_normals[1], 1.0e-6)?,
1076 Unit::try_new(edges_pseudo_normals[2], 1.0e-6)?,
1077 ],
1078 })
1079 } else {
1080 None
1081 }
1082 }
1083
1084 #[cfg(feature = "dim2")]
1085 #[doc(hidden)]
1086 pub fn triangle_normal_constraints(&self, _i: u32) -> Option<TrianglePseudoNormals> {
1087 None
1088 }
1089
1090 pub fn vertices(&self) -> &[Point<Real>] {
1092 &self.vertices
1093 }
1094
1095 pub fn indices(&self) -> &[[u32; 3]] {
1097 &self.indices
1098 }
1099
1100 pub fn topology(&self) -> Option<&TriMeshTopology> {
1102 self.topology.as_ref()
1103 }
1104
1105 pub fn connected_components(&self) -> Option<&TriMeshConnectedComponents> {
1107 self.connected_components.as_ref()
1108 }
1109
1110 pub fn connected_component_meshes(
1114 &self,
1115 flags: TriMeshFlags,
1116 ) -> Option<Vec<Result<TriMesh, TriMeshBuilderError>>> {
1117 self.connected_components()
1118 .map(|cc| cc.to_meshes(self, flags))
1119 }
1120
1121 #[cfg(feature = "dim3")]
1123 pub fn pseudo_normals(&self) -> Option<&TriMeshPseudoNormals> {
1124 self.pseudo_normals.as_ref()
1125 }
1126
1127 #[cfg(feature = "dim3")]
1130 pub fn pseudo_normals_if_oriented(&self) -> Option<&TriMeshPseudoNormals> {
1131 if self.flags.intersects(TriMeshFlags::ORIENTED) {
1132 self.pseudo_normals.as_ref()
1133 } else {
1134 None
1135 }
1136 }
1137}
1138
1139#[cfg(feature = "dim3")]
1140impl From<crate::shape::HeightField> for TriMesh {
1141 fn from(heightfield: crate::shape::HeightField) -> Self {
1142 let (vtx, idx) = heightfield.to_trimesh();
1143 TriMesh::new(vtx, idx).unwrap()
1144 }
1145}
1146
1147#[cfg(feature = "dim3")]
1148impl From<Cuboid> for TriMesh {
1149 fn from(cuboid: Cuboid) -> Self {
1150 let (vtx, idx) = cuboid.to_trimesh();
1151 TriMesh::new(vtx, idx).unwrap()
1152 }
1153}
1154
1155impl CompositeShape for TriMesh {
1156 fn map_part_at(
1157 &self,
1158 i: u32,
1159 f: &mut dyn FnMut(Option<&Isometry<Real>>, &dyn Shape, Option<&dyn NormalConstraints>),
1160 ) {
1161 let tri = self.triangle(i);
1162 let normals = self.triangle_normal_constraints(i);
1163 f(
1164 None,
1165 &tri,
1166 normals.as_ref().map(|n| n as &dyn NormalConstraints),
1167 )
1168 }
1169
1170 fn bvh(&self) -> &Bvh {
1171 &self.bvh
1172 }
1173}
1174
1175impl TypedCompositeShape for TriMesh {
1176 type PartShape = Triangle;
1177 type PartNormalConstraints = TrianglePseudoNormals;
1178
1179 #[inline(always)]
1180 fn map_typed_part_at<T>(
1181 &self,
1182 i: u32,
1183 mut f: impl FnMut(
1184 Option<&Isometry<Real>>,
1185 &Self::PartShape,
1186 Option<&Self::PartNormalConstraints>,
1187 ) -> T,
1188 ) -> Option<T> {
1189 let tri = self.triangle(i);
1190 let pseudo_normals = self.triangle_normal_constraints(i);
1191 Some(f(None, &tri, pseudo_normals.as_ref()))
1192 }
1193
1194 #[inline(always)]
1195 fn map_untyped_part_at<T>(
1196 &self,
1197 i: u32,
1198 mut f: impl FnMut(Option<&Isometry<Real>>, &dyn Shape, Option<&dyn NormalConstraints>) -> T,
1199 ) -> Option<T> {
1200 let tri = self.triangle(i);
1201 let pseudo_normals = self.triangle_normal_constraints(i);
1202 Some(f(
1203 None,
1204 &tri,
1205 pseudo_normals.as_ref().map(|n| n as &dyn NormalConstraints),
1206 ))
1207 }
1208}
1209
1210#[cfg(test)]
1211mod test {
1212 use crate::math::{Real, Vector};
1213 use crate::shape::{Cuboid, TriMesh, TriMeshFlags};
1214
1215 #[test]
1216 fn trimesh_error_empty_indices() {
1217 assert!(
1218 TriMesh::with_flags(vec![], vec![], TriMeshFlags::empty()).is_err(),
1219 "A triangle mesh with no triangles is invalid."
1220 );
1221 }
1222
1223 #[test]
1224 fn connected_components() {
1225 let (vtx, idx) = Cuboid::new(Vector::repeat(0.5)).to_trimesh();
1226
1227 let mut mesh = TriMesh::new(vtx.clone(), idx.clone()).unwrap();
1229
1230 for i in 1..10 {
1231 let cc_vtx = vtx
1232 .iter()
1233 .map(|pt| pt + Vector::repeat(2.0 * i as Real))
1234 .collect();
1235
1236 let to_append = TriMesh::new(cc_vtx, idx.clone()).unwrap();
1237 mesh.append(&to_append);
1238 }
1239
1240 mesh.set_flags(TriMeshFlags::CONNECTED_COMPONENTS).unwrap();
1241 let connected_components = mesh.connected_components().unwrap();
1242 assert_eq!(connected_components.num_connected_components(), 10);
1243
1244 let cc_meshes = connected_components.to_meshes(&mesh, TriMeshFlags::empty());
1245
1246 for cc in cc_meshes {
1247 let cc = cc.unwrap();
1248 assert_eq!(cc.vertices.len(), vtx.len());
1249 assert_eq!(cc.indices.len(), idx.len());
1250 }
1251 }
1252}