diff --git a/src/constructors.rs b/src/constructors.rs index 4de79ef..81d78bc 100644 --- a/src/constructors.rs +++ b/src/constructors.rs @@ -1,6 +1,8 @@ use crate::MeshBool; use crate::common::{Polygons, Quality, SimplePolygon, cosd, sind}; +use crate::disjoint_sets::DisjointSets; use crate::meshboolimpl::{MeshBoolImpl, Shape}; +use crate::parallel::{copy_if, gather}; use crate::polygon::{PolyVert, PolygonsIdx, SimplePolygonIdx, triangulate_idx}; use nalgebra::{Matrix2, Matrix3x4, Point2, Point3, Vector2, Vector3}; @@ -246,4 +248,62 @@ impl MeshBool { meshbool_impl.mark_coplanar(); Self::from(meshbool_impl) } + + // + // This operation returns a vector of Manifolds that are topologically + // disconnected. If everything is connected, the vector is length one, + // containing a copy of the original. It is the inverse operation of Compose(). + // + pub fn decompose(&self) -> Vec { + let uf = DisjointSets::new(self.num_vert() as u32); + // Graph graph; + let p_impl = &self.meshbool_impl; + for halfedge in p_impl.halfedge.iter() { + if halfedge.is_forward() { + uf.unite(halfedge.start_vert as u32, halfedge.end_vert as u32); + } + } + let mut component_indices: Vec = vec![]; + let num_components = uf.connected_components(&mut component_indices); + + if num_components == 1 { + return vec![self.clone()]; + } + let vert_label: Vec = component_indices; + + let num_vert = self.num_vert(); + let mut meshes: Vec = vec![]; + for i in 0..num_components { + let mut meshbool_impl = MeshBoolImpl::default(); + // inherit original object's precision + meshbool_impl.epsilon = p_impl.epsilon; + meshbool_impl.tolerance = p_impl.tolerance; + + let mut vert_new2old: Vec = vec![0; num_vert]; + let n_vert = copy_if(0..num_vert as i32, &mut vert_new2old, |v| { + vert_label[v as usize] == i as i32 + }); + meshbool_impl.vert_pos.resize(n_vert, Default::default()); + vert_new2old.resize(n_vert, Default::default()); + gather(&vert_new2old, &p_impl.vert_pos, &mut meshbool_impl.vert_pos); + + let mut face_new2old: Vec = vec![0; self.num_tri()]; + let halfedge = &p_impl.halfedge; + let n_face = copy_if(0..self.num_tri() as i32, &mut face_new2old, |face| { + vert_label[halfedge[3 * face as usize].start_vert as usize] == i as i32 + }); + + if n_face == 0 { + continue; + } + face_new2old.resize(n_face, Default::default()); + + meshbool_impl.gather_faces_with_old(p_impl, &face_new2old); + meshbool_impl.reindex_verts(&vert_new2old, p_impl.num_vert()); + meshbool_impl.finish(); + + meshes.push(Self::from(meshbool_impl)); + } + return meshes; + } } diff --git a/src/sort.rs b/src/sort.rs index 03492c0..6b2bcad 100644 --- a/src/sort.rs +++ b/src/sort.rs @@ -4,7 +4,8 @@ use crate::collider::Collider; use crate::common::{AABB, LossyFrom}; use crate::disjoint_sets::DisjointSets; use crate::meshboolimpl::MeshBoolImpl; -use crate::parallel::{inclusive_scan, scatter}; +use crate::parallel::{gather, inclusive_scan, scatter}; +use crate::shared::Halfedge; use crate::utils::{K_PRECISION, permute}; use crate::vec::{vec_resize, vec_resize_nofill, vec_uninit}; use nalgebra::{Point3, Vector3}; @@ -160,6 +161,33 @@ where return true; } +struct ReindexFace<'a> { + halfedge: &'a mut [Halfedge], + // halfedge_tangent: &'a mut [Vector4], + old_halfedge: &'a [Halfedge], + // old_halfedge_tangent: &'a [Vector4], + face_new2old: &'a [i32], + face_old2new: &'a [i32], +} + +impl ReindexFace<'_> { + fn call(&mut self, new_face: u32) { + let old_face = self.face_new2old[new_face as usize]; + for i in 0..3 { + let old_edge = 3 * old_face + i; + let mut edge = self.old_halfedge[old_edge as usize]; + let paired_face = edge.paired_halfedge / 3; + let offset = edge.paired_halfedge - 3 * paired_face; + edge.paired_halfedge = 3 * self.face_old2new[paired_face as usize] + offset; + let new_edge = 3 * new_face + i as u32; + self.halfedge[new_edge as usize] = edge; + // if !self.old_halfedge_tangent.is_empty() { + // self.halfedge_tangent[new_edge] = self.old_halfedge_tangent[old_edge]; + // } + } + } +} + impl MeshBoolImpl { ///Once halfedge_ has been filled in, this function can be called to create the ///rest of the internal data structures. This function also removes the verts @@ -236,7 +264,7 @@ impl MeshBoolImpl { ///Updates the halfedges to point to new vert indices based on a mapping, ///vertNew2Old. This may be a subset, so the total number of original verts is ///also given. - fn reindex_verts(&mut self, vert_new2old: &[i32], old_num_vert: usize) { + pub fn reindex_verts(&mut self, vert_new2old: &[i32], old_num_vert: usize) { let mut vert_old2new: Vec = unsafe { vec_uninit(old_num_vert) }; scatter(0..self.num_vert() as i32, vert_new2old, &mut vert_old2new); let has_prop = self.num_prop() > 0; @@ -341,7 +369,7 @@ impl MeshBoolImpl { ///Creates the halfedge_ vector for this manifold by copying a set of faces from ///another manifold, given by oldHalfedge. Input faceNew2Old defines the old ///faces to gather into this. - fn gather_faces(&mut self, face_new2old: &[i32]) { + pub fn gather_faces(&mut self, face_new2old: &[i32]) { let num_tri = face_new2old.len(); if self.mesh_relation.tri_ref.len() == self.num_tri() { permute(&mut self.mesh_relation.tri_ref, face_new2old); @@ -354,21 +382,71 @@ impl MeshBoolImpl { let mut old_halfedge = unsafe { vec_uninit(3 * num_tri) }; mem::swap(&mut old_halfedge, &mut self.halfedge); + // let mut old_halfedge_tangent = unsafe { vec_uninit(3 * num_tri) }; + // mem::swap(&mut old_halfedge_tangent, &mut self.halfedge_tangent); + let mut face_old2new = unsafe { vec_uninit(old_halfedge.len() / 3) }; scatter(0..num_tri as i32, face_new2old, &mut face_old2new); + let mut reindex_face = ReindexFace { + halfedge: &mut self.halfedge, + // halfedge_tangent: &mut self.halfedge_tangent, + old_halfedge: &old_halfedge, + // old_halfedge_tangent: &old_halfedge_tangent, + face_new2old: &face_new2old, + face_old2new: &face_old2new, + }; for new_face in 0..num_tri { - let new_face = new_face as i32; - let old_face = face_new2old[new_face as usize]; - for i in 0..3 { - let old_edge = 3 * old_face + i; - let mut edge = old_halfedge[old_edge as usize]; - let paired_face = edge.paired_halfedge / 3; - let offset = edge.paired_halfedge - 3 * paired_face; - edge.paired_halfedge = 3 * face_old2new[paired_face as usize] + offset; - let new_edge = 3 * new_face + i; - self.halfedge[new_edge as usize] = edge; + reindex_face.call(new_face as u32); + } + } + + pub fn gather_faces_with_old(&mut self, old: &Self, face_new2old: &[i32]) { + let num_tri = face_new2old.len(); + + unsafe { vec_resize_nofill(&mut self.mesh_relation.tri_ref, num_tri) }; + + gather( + face_new2old, + &old.mesh_relation.tri_ref, + &mut self.mesh_relation.tri_ref, + ); + + for pair in old.mesh_relation.mesh_id_transform.iter() { + self.mesh_relation + .mesh_id_transform + .insert(*pair.0, pair.1.clone()); + } + + if old.num_prop() > 0 { + self.num_prop = old.num_prop; + self.properties = old.properties.clone(); + } + + if old.face_normal.len() == old.num_tri() { + unsafe { + vec_resize_nofill(&mut self.face_normal, num_tri); } + gather(face_new2old, &old.face_normal, &mut self.face_normal); + } + + let mut face_old2new = unsafe { vec_uninit(old.num_tri()) }; + scatter(0..num_tri as i32, face_new2old, &mut face_old2new); + + unsafe { vec_resize_nofill(&mut self.halfedge, 3 * num_tri) }; + // if old.halfedge_tangent.len() != 0 { + // halfedgeTangent_.resize_nofill(3 * numTri); + // } + let mut reindex_face = ReindexFace { + halfedge: &mut self.halfedge, + // halfedge_tangent: &mut self.halfedge_tangent, + old_halfedge: &old.halfedge, + // old_halfedge_tangent: &old.halfedge_tangent, + face_new2old: &face_new2old, + face_old2new: &face_old2new, + }; + for new_face in 0..num_tri { + reindex_face.call(new_face as u32); } } }