From 687b40fb006ce5bb8f7fe343081d77102ff848b7 Mon Sep 17 00:00:00 2001 From: jimy-byerley Date: Sun, 24 Nov 2019 14:16:20 +0100 Subject: [PATCH 01/14] add bevel for contiguous lines --- src/mesh.rs | 57 ++++++++++------- src/mesh/connectivity_info.rs | 9 +++ src/mesh/edit.rs | 115 +++++++++++++++++++++++++++++++++- 3 files changed, 157 insertions(+), 24 deletions(-) diff --git a/src/mesh.rs b/src/mesh.rs index cfa85f5..dc78da3 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -109,12 +109,6 @@ impl Mesh for i in 0..no_vertices { mesh.create_vertex(vec3(positions[i*3], positions[i*3+1], positions[i*3+2])); } - - let mut twins = HashMap::<(VertexID,VertexID), HalfEdgeID>::new(); - fn sort(a: VertexID, b: VertexID) -> (VertexID,VertexID) { - if a < b {(a,b)} - else {(b,a)} - } // Create faces and twin connectivity for face in 0..no_faces { @@ -122,30 +116,47 @@ impl Mesh let v1 = indices[face * 3 + 1]; let v2 = indices[face * 3 + 2]; - let face = mesh.connectivity_info.create_face(VertexID::new(v0), VertexID::new(v1), VertexID::new(v2)); - - // mark twin halfedges - let mut walker = mesh.walker_from_face(face); + mesh.connectivity_info.create_face(VertexID::new(v0), VertexID::new(v1), VertexID::new(v2)); + } + mesh.twin_alones(); + + mesh + } + + + /// twin edges that share the same vertices + pub fn twin_alones(&mut self) { + // dictionnary for twining + let mut twins = HashMap::<(VertexID, VertexID), HalfEdgeID>::new(); + fn sort(a: VertexID, b: VertexID) -> (VertexID,VertexID) { + if a < b {(a,b)} + else {(b,a)} + } + + // get halfedges ids and begin twining + for face in self.face_iter() { + let mut walker = self.walker_from_face(face); for _ in 0..3 { let vertex_id = walker.vertex_id().unwrap(); walker.as_next(); - let key = sort(vertex_id, walker.vertex_id().unwrap()); - if let Some(twin) = twins.get(&key) { - mesh.connectivity_info.set_halfedge_twin(walker.halfedge_id().unwrap(), *twin); - } - else { - twins.insert(key, walker.halfedge_id().unwrap()); + if walker.twin_id().is_none() { + let key = sort(vertex_id, walker.vertex_id().unwrap()); + if let Some(twin) = twins.get(&key) { + self.connectivity_info.set_halfedge_twin(walker.halfedge_id().unwrap(), *twin); + } + else { + twins.insert(key, walker.halfedge_id().unwrap()); + } } } } - for halfedge in mesh.connectivity_info.halfedge_iterator() { - if mesh.connectivity_info.halfedge(halfedge).unwrap().twin.is_none() { - let vertex = mesh.walker_from_halfedge(halfedge).as_previous().vertex_id().unwrap(); - mesh.connectivity_info.set_halfedge_twin(halfedge, mesh.connectivity_info.new_halfedge(Some(vertex), None, None)); - } + // finish twining, and put empty twins to edges that are connected to only 1 face + for halfedge in self.halfedge_iter() { + if self.connectivity_info.halfedge(halfedge).unwrap().twin.is_none() { + let vertex = self.walker_from_halfedge(halfedge).as_previous().vertex_id().unwrap(); + self.connectivity_info.set_halfedge_twin(halfedge, self.connectivity_info.new_halfedge(Some(vertex), None, None)); + } } - - mesh } fn new_internal(connectivity_info: ConnectivityInfo) -> Mesh diff --git a/src/mesh/connectivity_info.rs b/src/mesh/connectivity_info.rs index 234b2cf..c5e01ad 100644 --- a/src/mesh/connectivity_info.rs +++ b/src/mesh/connectivity_info.rs @@ -109,6 +109,15 @@ impl ConnectivityInfo { } halfedges.remove(halfedge_id); } + + pub fn remove_halfedge_twin(&self, id: HalfEdgeID) + { + let mut halfedges = self.halfedges.borrow_mut(); + if let Some(twin) = halfedges.get(id).unwrap().twin { + halfedges.get_mut(twin).unwrap().twin = None; + } + halfedges.get_mut(id).unwrap().twin = None; + } pub fn remove_face(&self, face_id: FaceID) { diff --git a/src/mesh/edit.rs b/src/mesh/edit.rs index 0929cd7..9a89c48 100644 --- a/src/mesh/edit.rs +++ b/src/mesh/edit.rs @@ -65,6 +65,38 @@ impl Mesh Ok(()) } + + /// split a vertex in two vertices, along the edges `start` and `end`, returning the created point. + /// - `start` and `end` must point to the same vertex. + /// - the two points remains in the same initial location. + /// - the point created becomes the vertex pointed by `start` + /// ``` + /// + + + /// | / \ + /// ------+------- --> ----+ +---- + /// | \ / + /// + + + /// ``` + pub fn split_vertex(&mut self, start: HalfEdgeID, end: HalfEdgeID) -> VertexID { + assert_eq!( + self.walker_from_halfedge(start).vertex_id().unwrap(), + self.walker_from_halfedge(end).vertex_id().unwrap(), + ); + + // duplicate the vertex + let newvert = self.connectivity_info.new_vertex(self.vertex_position(self.walker_from_halfedge(start).vertex_id().unwrap())); + // cut at start and at end + self.connectivity_info.remove_halfedge_twin(start); + self.connectivity_info.remove_halfedge_twin(end); + // change refs to old vertex between these two halfedges + let mut walker = self.walker_from_halfedge(start); + while let Some(he) = walker.halfedge_id() { + self.connectivity_info.set_halfedge_vertex(he, newvert); + walker.as_next().as_twin(); + } + + newvert + } /// Split the given edge into two. /// Returns the id of the new vertex positioned at the given position. @@ -334,8 +366,89 @@ impl Mesh self.connectivity_info.remove_face(face_id); } + + + /// Create a bevel on the given edges, these must be contiguous and ordered (ie. `edge[i]` starts from `edge[i-1]`) + /// This function is not a realistic chamfer, it can displace the edges that are cutted by the bevel. + /// + pub fn bevel_curve(&mut self, edge: &[VertexID], amount: f64) + { + assert!(edge.len() >= 2, "`edge` must be at least two points"); + + let err_continuous = "edge must be a list of contiguous vertices"; + let err_border = "edge must not be on a border of the mesh"; + + let mut next = self.connecting_edge(edge[0], edge[1]) .expect(err_continuous); + // get the start halfedge (before the first vertex of the edge) + let mut last = next_forward(self, self.walker_from_halfedge(next).as_twin().halfedge_id().unwrap()) .expect(err_border); + let startvert = self.walker_from_halfedge(last).vertex_id().unwrap(); + last = self.walker_from_halfedge(last).as_twin().halfedge_id().unwrap(); + + let mut facing = Vec::new(); + + for i in 0 .. edge.len() { + if i < edge.len()-1 { next = self.connecting_edge(edge[i+1], edge[i]) .expect(err_continuous); } + // get the end halfedge (after the last vertex of the edge) + else { next = self.walker_from_halfedge(next_forward(self, last).unwrap()).as_twin().halfedge_id() .expect(err_border); } + + let d1 = ( self.face_normal(self.walker_from_halfedge(last).face_id().unwrap()) .cross(self.halfedge_direction(last)) + - self.face_normal(self.walker_from_halfedge(next).as_twin().face_id().unwrap()) .cross(self.halfedge_direction(next)) + ).normalize() * amount; + + let d2 = ( self.face_normal(self.walker_from_halfedge(last).as_twin().face_id().unwrap()) .cross(self.halfedge_direction(last)) + + self.face_normal(self.walker_from_halfedge(next).face_id().unwrap()) .cross(self.halfedge_direction(next)) + ) .normalize() * amount; + + // separate the vertex in two vertices + let vert1 = edge[i]; + let vert2 = self.split_vertex(last, next); + facing.push([vert1, vert2]); + // displace points + self.connectivity_info.set_position(vert2, self.vertex_position(vert2) + d2); + self.connectivity_info.set_position(vert1, self.vertex_position(vert1) + d1); + + last = next; + } + let lastvert = self.walker_from_halfedge(next).vertex_id().unwrap(); + + // create start and end face + self.connectivity_info.create_face(startvert, facing[0].0, facing[0].1); + self.connectivity_info.create_face(lastvert, facing.last().1, facing.last().0); + // create all faces + for confront in facing.windows(2) { + self.connectivity_info.create_face(confront[0][0], confront[0][1], confront[1][1]); + self.connectivity_info.create_face(confront[1][1], confront[1][0], confront[0][0]); + } + self.twin_alones(); + } } +/// normalized vector representing the direction in which the halfedge points +fn halfedge_direction(mesh: &Mesh, edge: HalfEdgeID) -> Vec3 { + let (src,dst) = mesh.edge_position(edge); + (dst-src).normalize() +} + +/// return the halfedge starting from `he`'s vertex, that has the closest direction to `he` +fn next_forward(mesh: &Mesh, he: HalfEdgeID) -> Option { + // nominal direction, the direction of he + let nominal = mesh.halfedge_direction(he); + let mut score = -1.; + let mut next = None; + let mut walker = mesh.halfedge_walker(he).into_next(); + // find the maximum projection of halfedges directions over the nominal ones, for the halfedges starting from he's vertex + while walker.halfedge_id().is_some() && walker.halfedge_id().unwrap() != he { + let s = mesh.direction(walker.halfedge_id().unwrap()); + if s > score { + next = walker.halfedge_id(); + score = s; + } + walker.as_twin().as_next(); + } + next +} + + #[cfg(test)] mod tests { @@ -646,4 +759,4 @@ mod tests { assert_eq!(2, mesh.no_faces()); mesh.is_valid().unwrap(); } -} \ No newline at end of file +} From cae1aa973a14c3225719b532f940525b05a5bd5e Mon Sep 17 00:00:00 2001 From: jimy byerley Date: Sun, 24 Nov 2019 14:36:24 +0100 Subject: [PATCH 02/14] fix compilation issues --- src/mesh/edge_measures.rs | 11 ++++++++++- src/mesh/edit.rs | 23 +++++++++-------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/mesh/edge_measures.rs b/src/mesh/edge_measures.rs index 782531e..f0b8bd3 100644 --- a/src/mesh/edge_measures.rs +++ b/src/mesh/edge_measures.rs @@ -33,4 +33,13 @@ impl Mesh let (p0, p1) = self.edge_positions(halfedge_id); (p0 - p1).magnitude2() } -} \ No newline at end of file + + /// + /// Normalized vector representing the direction in which the halfedge points + /// + pub fn edge_direction(&self, edge: HalfEdgeID) -> Vec3 + { + let (src,dst) = self.edge_positions(edge); + (dst-src).normalize() + } +} diff --git a/src/mesh/edit.rs b/src/mesh/edit.rs index 9a89c48..1b12868 100644 --- a/src/mesh/edit.rs +++ b/src/mesh/edit.rs @@ -391,12 +391,12 @@ impl Mesh // get the end halfedge (after the last vertex of the edge) else { next = self.walker_from_halfedge(next_forward(self, last).unwrap()).as_twin().halfedge_id() .expect(err_border); } - let d1 = ( self.face_normal(self.walker_from_halfedge(last).face_id().unwrap()) .cross(self.halfedge_direction(last)) - - self.face_normal(self.walker_from_halfedge(next).as_twin().face_id().unwrap()) .cross(self.halfedge_direction(next)) + let d1 = ( self.face_normal(self.walker_from_halfedge(last).face_id().unwrap()) .cross(self.edge_direction(last)) + - self.face_normal(self.walker_from_halfedge(next).as_twin().face_id().unwrap()) .cross(self.edge_direction(next)) ).normalize() * amount; - let d2 = ( self.face_normal(self.walker_from_halfedge(last).as_twin().face_id().unwrap()) .cross(self.halfedge_direction(last)) - + self.face_normal(self.walker_from_halfedge(next).face_id().unwrap()) .cross(self.halfedge_direction(next)) + let d2 = ( self.face_normal(self.walker_from_halfedge(last).as_twin().face_id().unwrap()) .cross(self.edge_direction(last)) + + self.face_normal(self.walker_from_halfedge(next).face_id().unwrap()) .cross(self.edge_direction(next)) ) .normalize() * amount; // separate the vertex in two vertices @@ -412,8 +412,8 @@ impl Mesh let lastvert = self.walker_from_halfedge(next).vertex_id().unwrap(); // create start and end face - self.connectivity_info.create_face(startvert, facing[0].0, facing[0].1); - self.connectivity_info.create_face(lastvert, facing.last().1, facing.last().0); + self.connectivity_info.create_face(startvert, facing[0][0], facing[0][1]); + self.connectivity_info.create_face(lastvert, facing.last().unwrap()[1], facing.last().unwrap()[0]); // create all faces for confront in facing.windows(2) { self.connectivity_info.create_face(confront[0][0], confront[0][1], confront[1][1]); @@ -423,22 +423,17 @@ impl Mesh } } -/// normalized vector representing the direction in which the halfedge points -fn halfedge_direction(mesh: &Mesh, edge: HalfEdgeID) -> Vec3 { - let (src,dst) = mesh.edge_position(edge); - (dst-src).normalize() -} /// return the halfedge starting from `he`'s vertex, that has the closest direction to `he` fn next_forward(mesh: &Mesh, he: HalfEdgeID) -> Option { // nominal direction, the direction of he - let nominal = mesh.halfedge_direction(he); + let nominal = mesh.edge_direction(he); let mut score = -1.; let mut next = None; - let mut walker = mesh.halfedge_walker(he).into_next(); + let mut walker = mesh.walker_from_halfedge(he).into_next(); // find the maximum projection of halfedges directions over the nominal ones, for the halfedges starting from he's vertex while walker.halfedge_id().is_some() && walker.halfedge_id().unwrap() != he { - let s = mesh.direction(walker.halfedge_id().unwrap()); + let s = mesh.edge_direction(walker.halfedge_id().unwrap()) .dot(nominal); if s > score { next = walker.halfedge_id(); score = s; From d61778b74e0b3a8c133cb1bfa2ad6ac451dfec7d Mon Sep 17 00:00:00 2001 From: jimy byerley Date: Sun, 24 Nov 2019 15:51:09 +0100 Subject: [PATCH 03/14] add test for split_vertex --- src/mesh/edit.rs | 57 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/src/mesh/edit.rs b/src/mesh/edit.rs index 1b12868..d702f1f 100644 --- a/src/mesh/edit.rs +++ b/src/mesh/edit.rs @@ -78,6 +78,26 @@ impl Mesh /// + + /// ``` pub fn split_vertex(&mut self, start: HalfEdgeID, end: HalfEdgeID) -> VertexID { + let (vstart, rstart) = { + let walker = self.walker_from_halfedge(start).into_twin(); + (walker.vertex_id().unwrap(), walker.halfedge_id().unwrap()) + }; + let (vend, rend) = { + let walker = self.walker_from_halfedge(end).into_twin(); + (walker.vertex_id().unwrap(), walker.halfedge_id().unwrap()) + }; + + let old = self.walker_from_halfedge(start).vertex_id().unwrap(); + let created = self.split_vertex_unfinished(start, end); + + let conn = &mut self.connectivity_info; + conn.set_halfedge_twin(start, conn.new_halfedge(Some(vstart), None, None)); + conn.set_halfedge_twin(rstart, conn.new_halfedge(Some(old), None, None)); + conn.set_halfedge_twin(end, conn.new_halfedge(Some(vend), None, None)); + conn.set_halfedge_twin(rend, conn.new_halfedge(Some(created), None, None)); + created + } + fn split_vertex_unfinished(&mut self, start: HalfEdgeID, end: HalfEdgeID) -> VertexID { assert_eq!( self.walker_from_halfedge(start).vertex_id().unwrap(), self.walker_from_halfedge(end).vertex_id().unwrap(), @@ -85,6 +105,7 @@ impl Mesh // duplicate the vertex let newvert = self.connectivity_info.new_vertex(self.vertex_position(self.walker_from_halfedge(start).vertex_id().unwrap())); + self.connectivity_info.set_vertex_halfedge(newvert, self.walker_from_halfedge(end).as_twin().halfedge_id()); // cut at start and at end self.connectivity_info.remove_halfedge_twin(start); self.connectivity_info.remove_halfedge_twin(end); @@ -401,7 +422,7 @@ impl Mesh // separate the vertex in two vertices let vert1 = edge[i]; - let vert2 = self.split_vertex(last, next); + let vert2 = self.split_vertex_unfinished(last, next); facing.push([vert1, vert2]); // displace points self.connectivity_info.set_position(vert2, self.vertex_position(vert2) + d2); @@ -425,20 +446,18 @@ impl Mesh /// return the halfedge starting from `he`'s vertex, that has the closest direction to `he` -fn next_forward(mesh: &Mesh, he: HalfEdgeID) -> Option { +fn next_forward(mesh: &Mesh, start: HalfEdgeID) -> Option { // nominal direction, the direction of he - let nominal = mesh.edge_direction(he); + let nominal = mesh.edge_direction(start); let mut score = -1.; let mut next = None; - let mut walker = mesh.walker_from_halfedge(he).into_next(); - // find the maximum projection of halfedges directions over the nominal ones, for the halfedges starting from he's vertex - while walker.halfedge_id().is_some() && walker.halfedge_id().unwrap() != he { - let s = mesh.edge_direction(walker.halfedge_id().unwrap()) .dot(nominal); + + for he in mesh.vertex_halfedge_iter(mesh.walker_from_halfedge(start).vertex_id().unwrap()) { + let s = mesh.edge_direction(he) .dot(nominal); if s > score { - next = walker.halfedge_id(); + next = Some(he); score = s; } - walker.as_twin().as_next(); } next } @@ -754,4 +773,24 @@ mod tests { assert_eq!(2, mesh.no_faces()); mesh.is_valid().unwrap(); } + + #[test] + fn test_split_vertex() { + let mut mesh = MeshBuilder::new().icosahedron().build().unwrap(); + let no_faces = mesh.no_faces(); + let no_halfedges = mesh.no_halfedges(); + + let vert = mesh.vertex_iter().next().unwrap(); + let mut walker = mesh.walker_from_vertex(vert); + let start = walker.halfedge_id().unwrap(); + let end = walker.as_next().as_twin().as_next().as_twin().halfedge_id().unwrap(); + + mesh.split_vertex(start, end); + + assert_eq!(13, mesh.no_vertices()); + assert_eq!(no_faces, mesh.no_faces()); + assert_eq!(no_halfedges+4, mesh.no_halfedges()); + mesh.is_valid().unwrap(); + } + } From 1e9d0e4d3ef59441d5a921abdb8a6a1a533d7bc8 Mon Sep 17 00:00:00 2001 From: jimy byerley Date: Sun, 24 Nov 2019 17:27:43 +0100 Subject: [PATCH 04/14] add test for bevel_curve --- src/mesh/edit.rs | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/mesh/edit.rs b/src/mesh/edit.rs index d702f1f..26bde48 100644 --- a/src/mesh/edit.rs +++ b/src/mesh/edit.rs @@ -78,6 +78,7 @@ impl Mesh /// + + /// ``` pub fn split_vertex(&mut self, start: HalfEdgeID, end: HalfEdgeID) -> VertexID { + // get start vertex of `start` and `end` and their twin let (vstart, rstart) = { let walker = self.walker_from_halfedge(start).into_twin(); (walker.vertex_id().unwrap(), walker.halfedge_id().unwrap()) @@ -86,10 +87,11 @@ impl Mesh let walker = self.walker_from_halfedge(end).into_twin(); (walker.vertex_id().unwrap(), walker.halfedge_id().unwrap()) }; - + // splited vertex let old = self.walker_from_halfedge(start).vertex_id().unwrap(); let created = self.split_vertex_unfinished(start, end); + // create twins for the separated halfedges let conn = &mut self.connectivity_info; conn.set_halfedge_twin(start, conn.new_halfedge(Some(vstart), None, None)); conn.set_halfedge_twin(rstart, conn.new_halfedge(Some(old), None, None)); @@ -405,19 +407,24 @@ impl Mesh let startvert = self.walker_from_halfedge(last).vertex_id().unwrap(); last = self.walker_from_halfedge(last).as_twin().halfedge_id().unwrap(); - let mut facing = Vec::new(); + let mut facing = Vec::with_capacity(edge.len()); for i in 0 .. edge.len() { + // get the next edge to bevel else the ending one if i < edge.len()-1 { next = self.connecting_edge(edge[i+1], edge[i]) .expect(err_continuous); } // get the end halfedge (after the last vertex of the edge) else { next = self.walker_from_halfedge(next_forward(self, last).unwrap()).as_twin().halfedge_id() .expect(err_border); } - let d1 = ( self.face_normal(self.walker_from_halfedge(last).face_id().unwrap()) .cross(self.edge_direction(last)) - - self.face_normal(self.walker_from_halfedge(next).as_twin().face_id().unwrap()) .cross(self.edge_direction(next)) + let d1 = ( self.face_normal(self.walker_from_halfedge(last).face_id().unwrap()) + .cross(self.edge_direction(last)) + - self.face_normal(self.walker_from_halfedge(next).as_twin().face_id().unwrap()) + .cross(self.edge_direction(next)) ).normalize() * amount; - let d2 = ( self.face_normal(self.walker_from_halfedge(last).as_twin().face_id().unwrap()) .cross(self.edge_direction(last)) - + self.face_normal(self.walker_from_halfedge(next).face_id().unwrap()) .cross(self.edge_direction(next)) + let d2 = ( self.face_normal(self.walker_from_halfedge(last).as_twin().face_id().unwrap()) + .cross(self.edge_direction(last)) + + self.face_normal(self.walker_from_halfedge(next).face_id().unwrap()) + .cross(self.edge_direction(next)) ) .normalize() * amount; // separate the vertex in two vertices @@ -793,4 +800,16 @@ mod tests { mesh.is_valid().unwrap(); } + use std::iter::FromIterator; + + #[test] + fn test_bevel_curve() { + let mut mesh = MeshBuilder::new().icosahedron().build().unwrap(); + mesh.bevel_curve(&Vec::from_iter([0,1,4].iter().cloned().map(VertexID::new)), 0.1); + mesh.is_valid(); + + mesh = MeshBuilder::new().icosahedron().build().unwrap(); + mesh.bevel_curve(&Vec::from_iter([0,4,5,3,7,6].iter().cloned().map(VertexID::new)), 0.2); + mesh.is_valid(); + } } From 12752cc0e8764124d3181b23f32b0aa7dda05c78 Mon Sep 17 00:00:00 2001 From: jimy byerley Date: Sun, 24 Nov 2019 22:59:48 +0100 Subject: [PATCH 05/14] issue because the mesh is not repaired as we interrogate it --- src/mesh/edit.rs | 53 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/src/mesh/edit.rs b/src/mesh/edit.rs index 26bde48..2cc2afc 100644 --- a/src/mesh/edit.rs +++ b/src/mesh/edit.rs @@ -103,7 +103,7 @@ impl Mesh assert_eq!( self.walker_from_halfedge(start).vertex_id().unwrap(), self.walker_from_halfedge(end).vertex_id().unwrap(), - ); + "spliting halfedges doesn't point to the same vertex"); // duplicate the vertex let newvert = self.connectivity_info.new_vertex(self.vertex_position(self.walker_from_halfedge(start).vertex_id().unwrap())); @@ -401,47 +401,64 @@ impl Mesh let err_continuous = "edge must be a list of contiguous vertices"; let err_border = "edge must not be on a border of the mesh"; - let mut next = self.connecting_edge(edge[0], edge[1]) .expect(err_continuous); // get the start halfedge (before the first vertex of the edge) - let mut last = next_forward(self, self.walker_from_halfedge(next).as_twin().halfedge_id().unwrap()) .expect(err_border); - let startvert = self.walker_from_halfedge(last).vertex_id().unwrap(); - last = self.walker_from_halfedge(last).as_twin().halfedge_id().unwrap(); + let rfirst = next_forward(self, self.connecting_edge(edge[1], edge[0]) .expect(err_continuous)) .expect(err_border); + let startvert = self.walker_from_halfedge(rfirst).vertex_id().unwrap(); + let first = self.walker_from_halfedge(rfirst).as_twin().halfedge_id().unwrap(); + // get the end halfedge (after the last vertex of the edge) + let last = next_forward(self, self.connecting_edge(edge[edge.len()-2], edge[edge.len()-1]) .expect(err_continuous)) .expect(err_border); + let endvert = self.walker_from_halfedge(last).vertex_id().unwrap(); - let mut facing = Vec::with_capacity(edge.len()); + // get all the informations for the operation, since while modifying the mesh, the halfedge functions doesn't work + let mut infos = Vec::with_capacity(edge.len()); + let mut previous = first; + let mut next = first; for i in 0 .. edge.len() { // get the next edge to bevel else the ending one if i < edge.len()-1 { next = self.connecting_edge(edge[i+1], edge[i]) .expect(err_continuous); } - // get the end halfedge (after the last vertex of the edge) - else { next = self.walker_from_halfedge(next_forward(self, last).unwrap()).as_twin().halfedge_id() .expect(err_border); } + else { next = last; } - let d1 = ( self.face_normal(self.walker_from_halfedge(last).face_id().unwrap()) - .cross(self.edge_direction(last)) + let d1 = ( self.face_normal(self.walker_from_halfedge(previous).face_id().unwrap()) + .cross(self.edge_direction(previous)) - self.face_normal(self.walker_from_halfedge(next).as_twin().face_id().unwrap()) .cross(self.edge_direction(next)) ).normalize() * amount; - let d2 = ( self.face_normal(self.walker_from_halfedge(last).as_twin().face_id().unwrap()) - .cross(self.edge_direction(last)) + let d2 = ( self.face_normal(self.walker_from_halfedge(previous).as_twin().face_id().unwrap()) + .cross(self.edge_direction(previous)) + self.face_normal(self.walker_from_halfedge(next).face_id().unwrap()) .cross(self.edge_direction(next)) ) .normalize() * amount; + infos.push(([d1, d2], [last,next])); + + previous = next; + } + + let mut facing = Vec::with_capacity(edge.len()); + + previous = first; + next = first; + for i in 0 .. edge.len() { + // get the next edge to bevel else the ending one + if i < edge.len()-1 { next = self.connecting_edge(edge[i+1], edge[i]) .expect(err_continuous); } + else { next = last; } + // separate the vertex in two vertices let vert1 = edge[i]; - let vert2 = self.split_vertex_unfinished(last, next); + let vert2 = self.split_vertex_unfinished(last, self.walker_from_halfedge(next).as_twin().halfedge_id().unwrap()); facing.push([vert1, vert2]); // displace points - self.connectivity_info.set_position(vert2, self.vertex_position(vert2) + d2); - self.connectivity_info.set_position(vert1, self.vertex_position(vert1) + d1); + self.connectivity_info.set_position(vert1, self.vertex_position(vert1) + infos[i].0[0]); + self.connectivity_info.set_position(vert2, self.vertex_position(vert2) + infos[i].0[1]); - last = next; + previous = next; } - let lastvert = self.walker_from_halfedge(next).vertex_id().unwrap(); // create start and end face self.connectivity_info.create_face(startvert, facing[0][0], facing[0][1]); - self.connectivity_info.create_face(lastvert, facing.last().unwrap()[1], facing.last().unwrap()[0]); + self.connectivity_info.create_face(endvert, facing.last().unwrap()[1], facing.last().unwrap()[0]); // create all faces for confront in facing.windows(2) { self.connectivity_info.create_face(confront[0][0], confront[0][1], confront[1][1]); From b4c0a2206b9d14deb163525e4aa4ca2090904e54 Mon Sep 17 00:00:00 2001 From: jimy byerley Date: Mon, 25 Nov 2019 17:10:21 +0100 Subject: [PATCH 06/14] twin_alones twin also halfedges that already have an empty twin --- src/mesh.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/mesh.rs b/src/mesh.rs index dc78da3..223b700 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -139,10 +139,20 @@ impl Mesh for _ in 0..3 { let vertex_id = walker.vertex_id().unwrap(); walker.as_next(); - if walker.twin_id().is_none() { + if walker.twin_id().is_none() || walker.clone().as_twin().face_id().is_none() { let key = sort(vertex_id, walker.vertex_id().unwrap()); - if let Some(twin) = twins.get(&key) { - self.connectivity_info.set_halfedge_twin(walker.halfedge_id().unwrap(), *twin); + if let Some(&twin) = twins.get(&key) { + // if there was an empty halfedge already twined to the edge, remove it + let oldtwin = self.walker_from_halfedge(twin).into_twin(); + if oldtwin.halfedge_id().is_some() && oldtwin.face_id().is_none() { + self.connectivity_info.remove_halfedge(oldtwin.halfedge_id().unwrap()); + } + let myoldtwin = walker.clone().into_twin(); + if myoldtwin.halfedge_id().is_some() && myoldtwin.face_id().is_none() { + self.connectivity_info.remove_halfedge(myoldtwin.halfedge_id().unwrap()); + } + // twin halfedges + self.connectivity_info.set_halfedge_twin(walker.halfedge_id().unwrap(), twin); } else { twins.insert(key, walker.halfedge_id().unwrap()); From ab3e1cceb733924d0f72ad164c067e8b66ee365e Mon Sep 17 00:00:00 2001 From: jimy byerley Date: Mon, 25 Nov 2019 17:45:26 +0100 Subject: [PATCH 07/14] try to fix bevel_curve issue --- src/mesh/edit.rs | 47 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/src/mesh/edit.rs b/src/mesh/edit.rs index 2cc2afc..4c244ac 100644 --- a/src/mesh/edit.rs +++ b/src/mesh/edit.rs @@ -408,52 +408,37 @@ impl Mesh // get the end halfedge (after the last vertex of the edge) let last = next_forward(self, self.connecting_edge(edge[edge.len()-2], edge[edge.len()-1]) .expect(err_continuous)) .expect(err_border); let endvert = self.walker_from_halfedge(last).vertex_id().unwrap(); - - // get all the informations for the operation, since while modifying the mesh, the halfedge functions doesn't work - let mut infos = Vec::with_capacity(edge.len()); + + let mut facing = Vec::with_capacity(edge.len()); let mut previous = first; let mut next = first; + let dir_prev = self.edge_direction(previous); + let mut results_prev = ( self.face_normal(self.walker_from_halfedge(previous).face_id().unwrap()) .cross(dir_prev), + self.face_normal(self.walker_from_halfedge(previous).as_twin().face_id().unwrap()) .cross(dir_prev), + ); for i in 0 .. edge.len() { // get the next edge to bevel else the ending one if i < edge.len()-1 { next = self.connecting_edge(edge[i+1], edge[i]) .expect(err_continuous); } else { next = last; } - let d1 = ( self.face_normal(self.walker_from_halfedge(previous).face_id().unwrap()) - .cross(self.edge_direction(previous)) - - self.face_normal(self.walker_from_halfedge(next).as_twin().face_id().unwrap()) - .cross(self.edge_direction(next)) - ).normalize() * amount; - - let d2 = ( self.face_normal(self.walker_from_halfedge(previous).as_twin().face_id().unwrap()) - .cross(self.edge_direction(previous)) - + self.face_normal(self.walker_from_halfedge(next).face_id().unwrap()) - .cross(self.edge_direction(next)) - ) .normalize() * amount; - - infos.push(([d1, d2], [last,next])); - - previous = next; - } - - let mut facing = Vec::with_capacity(edge.len()); - - previous = first; - next = first; - for i in 0 .. edge.len() { - // get the next edge to bevel else the ending one - if i < edge.len()-1 { next = self.connecting_edge(edge[i+1], edge[i]) .expect(err_continuous); } - else { next = last; } + let dir_next = self.edge_direction(next); + let results_next = ( self.face_normal(self.walker_from_halfedge(next).face_id().unwrap()) .cross(dir_next), + self.face_normal(self.walker_from_halfedge(next).as_twin().face_id().unwrap()) .cross(dir_next), + ); + let d1 = (results_next.0 + results_prev.0).normalize() * amount; + let d2 = (results_next.1 + results_prev.1).normalize() * amount; // separate the vertex in two vertices let vert1 = edge[i]; - let vert2 = self.split_vertex_unfinished(last, self.walker_from_halfedge(next).as_twin().halfedge_id().unwrap()); + let vert2 = self.split_vertex(last, self.walker_from_halfedge(next).as_twin().halfedge_id().unwrap()); facing.push([vert1, vert2]); // displace points - self.connectivity_info.set_position(vert1, self.vertex_position(vert1) + infos[i].0[0]); - self.connectivity_info.set_position(vert2, self.vertex_position(vert2) + infos[i].0[1]); + self.connectivity_info.set_position(vert1, self.vertex_position(vert1) + d1); + self.connectivity_info.set_position(vert2, self.vertex_position(vert2) + d2); previous = next; + results_prev = results_next; } // create start and end face From 53f9f69b5ecc379ce2b18dc86056c0696ae7f209 Mon Sep 17 00:00:00 2001 From: jimy byerley Date: Mon, 25 Nov 2019 17:57:50 +0100 Subject: [PATCH 08/14] fixed issue of bevel_curve caused by walking through the mesh during operation --- src/mesh/edit.rs | 53 ++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/src/mesh/edit.rs b/src/mesh/edit.rs index 4c244ac..54b6206 100644 --- a/src/mesh/edit.rs +++ b/src/mesh/edit.rs @@ -409,36 +409,45 @@ impl Mesh let last = next_forward(self, self.connecting_edge(edge[edge.len()-2], edge[edge.len()-1]) .expect(err_continuous)) .expect(err_border); let endvert = self.walker_from_halfedge(last).vertex_id().unwrap(); + let displts = { + let mut displts = Vec::with_capacity(edge.len()); + + let mut prev = first; + let mut next = first; + let dir_prev = self.edge_direction(prev); + let mut results_prev = ( self.face_normal(self.walker_from_halfedge(prev).face_id().unwrap()) .cross(dir_prev), + self.face_normal(self.walker_from_halfedge(prev).as_twin().face_id().unwrap()) .cross(dir_prev), + ); + for i in 0 .. edge.len() { + // get the next edge to bevel else the ending one + if i < edge.len()-1 { next = self.connecting_edge(edge[i], edge[i+1]) .expect(err_continuous); } + else { next = last; } + + let dir_next = self.edge_direction(next); + let results_next = ( self.face_normal(self.walker_from_halfedge(next).face_id().unwrap()) .cross(dir_next), + self.face_normal(self.walker_from_halfedge(next).as_twin().face_id().unwrap()) .cross(dir_next), + ); + let d1 = (results_next.0 + results_prev.0).normalize() * amount; + let d2 = (results_next.1 + results_prev.1).normalize() * amount; + + displts.push((prev, self.walker_from_halfedge(next).as_twin().halfedge_id().unwrap(), d1, d2)); + + prev = next; + results_prev = results_next; + } + displts + }; + let mut facing = Vec::with_capacity(edge.len()); - let mut previous = first; - let mut next = first; - let dir_prev = self.edge_direction(previous); - let mut results_prev = ( self.face_normal(self.walker_from_halfedge(previous).face_id().unwrap()) .cross(dir_prev), - self.face_normal(self.walker_from_halfedge(previous).as_twin().face_id().unwrap()) .cross(dir_prev), - ); - for i in 0 .. edge.len() { - // get the next edge to bevel else the ending one - if i < edge.len()-1 { next = self.connecting_edge(edge[i+1], edge[i]) .expect(err_continuous); } - else { next = last; } - - let dir_next = self.edge_direction(next); - let results_next = ( self.face_normal(self.walker_from_halfedge(next).face_id().unwrap()) .cross(dir_next), - self.face_normal(self.walker_from_halfedge(next).as_twin().face_id().unwrap()) .cross(dir_next), - ); - let d1 = (results_next.0 + results_prev.0).normalize() * amount; - let d2 = (results_next.1 + results_prev.1).normalize() * amount; - + for (i, &(prev, next, d1, d2)) in displts.iter().enumerate() { // separate the vertex in two vertices let vert1 = edge[i]; - let vert2 = self.split_vertex(last, self.walker_from_halfedge(next).as_twin().halfedge_id().unwrap()); + let vert2 = self.split_vertex_unfinished(prev, next); facing.push([vert1, vert2]); // displace points self.connectivity_info.set_position(vert1, self.vertex_position(vert1) + d1); self.connectivity_info.set_position(vert2, self.vertex_position(vert2) + d2); - - previous = next; - results_prev = results_next; } // create start and end face From e3d21cf5a61f420611e04f9209a92ab402db864b Mon Sep 17 00:00:00 2001 From: jimy byerley Date: Thu, 28 Nov 2019 22:37:57 +0100 Subject: [PATCH 09/14] fix issue of the halfedge direction that sometimes goes in the opposite direction --- src/mesh/edge_measures.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/edge_measures.rs b/src/mesh/edge_measures.rs index f0b8bd3..29529e4 100644 --- a/src/mesh/edge_measures.rs +++ b/src/mesh/edge_measures.rs @@ -39,7 +39,7 @@ impl Mesh /// pub fn edge_direction(&self, edge: HalfEdgeID) -> Vec3 { - let (src,dst) = self.edge_positions(edge); - (dst-src).normalize() + let (dst,src) = self.edge_vertices(edge); + (self.vertex_position(dst)-self.vertex_position(src)).normalize() } } From 663b0d392369a425d908891168d1cec3d93c7435 Mon Sep 17 00:00:00 2001 From: jimy byerley Date: Thu, 28 Nov 2019 22:45:23 +0100 Subject: [PATCH 10/14] fixed destruction of immediate proximity during bevel_curve + debug info --- src/mesh/edit.rs | 83 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 16 deletions(-) diff --git a/src/mesh/edit.rs b/src/mesh/edit.rs index 54b6206..17b849a 100644 --- a/src/mesh/edit.rs +++ b/src/mesh/edit.rs @@ -99,23 +99,31 @@ impl Mesh conn.set_halfedge_twin(rend, conn.new_halfedge(Some(created), None, None)); created } + /// variant of split_vertex, that doesn't create empty twin halfedges for the hole fn split_vertex_unfinished(&mut self, start: HalfEdgeID, end: HalfEdgeID) -> VertexID { assert_eq!( self.walker_from_halfedge(start).vertex_id().unwrap(), self.walker_from_halfedge(end).vertex_id().unwrap(), "spliting halfedges doesn't point to the same vertex"); - // duplicate the vertex - let newvert = self.connectivity_info.new_vertex(self.vertex_position(self.walker_from_halfedge(start).vertex_id().unwrap())); - self.connectivity_info.set_vertex_halfedge(newvert, self.walker_from_halfedge(end).as_twin().halfedge_id()); + let oldvert = self.walker_from_halfedge(start).vertex_id().unwrap(); + let newvert = self.connectivity_info.new_vertex(self.vertex_position(oldvert)); + println!("splitting across {} {:?} {:?}", oldvert, start, end); // cut at start and at end self.connectivity_info.remove_halfedge_twin(start); self.connectivity_info.remove_halfedge_twin(end); + self.connectivity_info.set_vertex_halfedge(newvert, self.walker_from_halfedge(start).as_next().halfedge_id()); + self.connectivity_info.set_vertex_halfedge(oldvert, self.walker_from_halfedge(end ).as_next().halfedge_id()); +// println!("set {:?} to {:?}", newvert, self.walker_from_halfedge(start).as_next().halfedge_id()); +// println!("set {:?} to {:?}", oldvert, self.walker_from_halfedge(end ).as_next().halfedge_id()); // change refs to old vertex between these two halfedges let mut walker = self.walker_from_halfedge(start); while let Some(he) = walker.halfedge_id() { + println!("set {:?} vertex from {} to {}", he, self.connectivity_info.halfedge(he).unwrap().vertex.unwrap(), newvert); self.connectivity_info.set_halfedge_vertex(he, newvert); walker.as_next().as_twin(); + if walker.halfedge_id() == Some(start) {println!("reached start");} + if walker.halfedge_id() == Some(end) {println!("reached end");} } newvert @@ -398,38 +406,45 @@ impl Mesh { assert!(edge.len() >= 2, "`edge` must be at least two points"); + println!("operate on a mesh of {} vertices\t{} halfedges", self.no_vertices(), self.no_halfedges()); + let err_continuous = "edge must be a list of contiguous vertices"; let err_border = "edge must not be on a border of the mesh"; // get the start halfedge (before the first vertex of the edge) - let rfirst = next_forward(self, self.connecting_edge(edge[1], edge[0]) .expect(err_continuous)) .expect(err_border); + let rfirst = self.connecting_edge(edge[0], edge[edge.len()-1]) + .or_else(|| next_forward(self, self.connecting_edge(edge[1], edge[0]) .expect(err_continuous))) + .expect(err_border); let startvert = self.walker_from_halfedge(rfirst).vertex_id().unwrap(); let first = self.walker_from_halfedge(rfirst).as_twin().halfedge_id().unwrap(); // get the end halfedge (after the last vertex of the edge) - let last = next_forward(self, self.connecting_edge(edge[edge.len()-2], edge[edge.len()-1]) .expect(err_continuous)) .expect(err_border); - let endvert = self.walker_from_halfedge(last).vertex_id().unwrap(); - + let last = self.connecting_edge(edge[edge.len()-1], edge[0]) + .or_else(|| next_forward(self, self.connecting_edge(edge[edge.len()-2], edge[edge.len()-1]) .expect(err_continuous))) + .expect(err_border); + let mut endvert = if last == first {None} + else {Some(self.walker_from_halfedge(last).vertex_id().unwrap())}; + let displts = { let mut displts = Vec::with_capacity(edge.len()); let mut prev = first; - let mut next = first; + let mut next; let dir_prev = self.edge_direction(prev); let mut results_prev = ( self.face_normal(self.walker_from_halfedge(prev).face_id().unwrap()) .cross(dir_prev), - self.face_normal(self.walker_from_halfedge(prev).as_twin().face_id().unwrap()) .cross(dir_prev), + self.face_normal(self.walker_from_halfedge(prev).as_twin().face_id().unwrap()) .cross(-dir_prev), ); for i in 0 .. edge.len() { // get the next edge to bevel else the ending one if i < edge.len()-1 { next = self.connecting_edge(edge[i], edge[i+1]) .expect(err_continuous); } else { next = last; } + assert_ne!(prev, self.walker_from_halfedge(next).as_twin().halfedge_id().unwrap()); let dir_next = self.edge_direction(next); let results_next = ( self.face_normal(self.walker_from_halfedge(next).face_id().unwrap()) .cross(dir_next), - self.face_normal(self.walker_from_halfedge(next).as_twin().face_id().unwrap()) .cross(dir_next), + self.face_normal(self.walker_from_halfedge(next).as_twin().face_id().unwrap()) .cross(-dir_next), ); let d1 = (results_next.0 + results_prev.0).normalize() * amount; let d2 = (results_next.1 + results_prev.1).normalize() * amount; - displts.push((prev, self.walker_from_halfedge(next).as_twin().halfedge_id().unwrap(), d1, d2)); prev = next; @@ -450,13 +465,26 @@ impl Mesh self.connectivity_info.set_position(vert2, self.vertex_position(vert2) + d2); } + if endvert.is_none() {endvert = Some(facing[0][1]);} + + println!("facing: {:#?}", facing); + // create start and end face + for face in self.face_iter() { + println!("has face {:?}", self.face_vertices(face)); + } self.connectivity_info.create_face(startvert, facing[0][0], facing[0][1]); - self.connectivity_info.create_face(endvert, facing.last().unwrap()[1], facing.last().unwrap()[0]); + self.connectivity_info.create_face(endvert.unwrap(), facing[facing.len()-1][1], facing[facing.len()-1][0]); // create all faces for confront in facing.windows(2) { - self.connectivity_info.create_face(confront[0][0], confront[0][1], confront[1][1]); - self.connectivity_info.create_face(confront[1][1], confront[1][0], confront[0][0]); + self.connectivity_info.create_face(confront[0][1], confront[0][0], confront[1][1]); + self.connectivity_info.create_face(confront[1][0], confront[1][1], confront[0][0]); + println!("create face {} {} {}", confront[0][1], confront[0][0], confront[1][1]); + println!("create face {} {} {}", confront[1][0], confront[1][1], confront[0][0]); + } + println!("halfedges:"); + for (i,he) in self.halfedge_iter().enumerate() { + println!("he {}\t{}\t{:?}", i, he, self.connectivity_info.halfedge(he).unwrap()); } self.twin_alones(); } @@ -477,6 +505,8 @@ fn next_forward(mesh: &Mesh, start: HalfEdgeID) -> Option { score = s; } } + println!("next_forward is {:?} with score {}", next, score); + if let Some(vert) = next { assert_ne!(vert, start); } next } @@ -816,11 +846,32 @@ mod tests { #[test] fn test_bevel_curve() { let mut mesh = MeshBuilder::new().icosahedron().build().unwrap(); + let nominal_no_vertices = mesh.no_vertices(); + let nominal_no_halfedges = mesh.no_halfedges(); + let nominal_no_faces = mesh.no_faces(); + + println!("faces:"); + for face in mesh.face_iter() { + println!("{:?}", mesh.face_vertices(face)); + } + mesh.bevel_curve(&Vec::from_iter([0,4,5].iter().cloned().map(VertexID::new)), 0.1); +// println!("halfedges:"); +// for (i,he) in mesh.halfedge_iter().enumerate() { +// println!("he {}\t{}\t{:?}", i, he, mesh.connectivity_info.halfedge(he).unwrap()); +// } + assert_eq!(nominal_no_vertices+3, mesh.no_vertices()); + assert_eq!(nominal_no_halfedges+18, mesh.no_halfedges()); + assert_eq!(nominal_no_faces+6, mesh.no_faces()); + mesh.is_valid().unwrap(); + mesh.bevel_curve(&Vec::from_iter([0,1,4].iter().cloned().map(VertexID::new)), 0.1); - mesh.is_valid(); + assert_eq!(nominal_no_vertices+3, mesh.no_vertices()); + assert_eq!(nominal_no_halfedges+18, mesh.no_halfedges()); + assert_eq!(nominal_no_faces+6, mesh.no_faces()); + mesh.is_valid().unwrap(); mesh = MeshBuilder::new().icosahedron().build().unwrap(); mesh.bevel_curve(&Vec::from_iter([0,4,5,3,7,6].iter().cloned().map(VertexID::new)), 0.2); - mesh.is_valid(); + mesh.is_valid().unwrap(); } } From 74d10629c2d3febcd2e223f2a52ad7f84d8c189e Mon Sep 17 00:00:00 2001 From: jimy-byerley Date: Fri, 29 Nov 2019 08:49:15 +0100 Subject: [PATCH 11/14] fixed bevel_curve --- src/mesh/edit.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/mesh/edit.rs b/src/mesh/edit.rs index 17b849a..404b287 100644 --- a/src/mesh/edit.rs +++ b/src/mesh/edit.rs @@ -108,7 +108,7 @@ impl Mesh // duplicate the vertex let oldvert = self.walker_from_halfedge(start).vertex_id().unwrap(); let newvert = self.connectivity_info.new_vertex(self.vertex_position(oldvert)); - println!("splitting across {} {:?} {:?}", oldvert, start, end); + println!("splitting across {} {:?} {:?} {}", oldvert, start, end, newvert); // cut at start and at end self.connectivity_info.remove_halfedge_twin(start); self.connectivity_info.remove_halfedge_twin(end); @@ -119,11 +119,11 @@ impl Mesh // change refs to old vertex between these two halfedges let mut walker = self.walker_from_halfedge(start); while let Some(he) = walker.halfedge_id() { - println!("set {:?} vertex from {} to {}", he, self.connectivity_info.halfedge(he).unwrap().vertex.unwrap(), newvert); +// println!("set {:?} vertex from {} to {}", he, self.connectivity_info.halfedge(he).unwrap().vertex.unwrap(), newvert); self.connectivity_info.set_halfedge_vertex(he, newvert); walker.as_next().as_twin(); - if walker.halfedge_id() == Some(start) {println!("reached start");} - if walker.halfedge_id() == Some(end) {println!("reached end");} +// if walker.halfedge_id() == Some(start) {println!("reached start");} +// if walker.halfedge_id() == Some(end) {println!("reached end");} } newvert @@ -482,10 +482,10 @@ impl Mesh println!("create face {} {} {}", confront[0][1], confront[0][0], confront[1][1]); println!("create face {} {} {}", confront[1][0], confront[1][1], confront[0][0]); } - println!("halfedges:"); - for (i,he) in self.halfedge_iter().enumerate() { - println!("he {}\t{}\t{:?}", i, he, self.connectivity_info.halfedge(he).unwrap()); - } +// println!("halfedges:"); +// for (i,he) in self.halfedge_iter().enumerate() { +// println!("he {}\t{}\t{:?}", i, he, self.connectivity_info.halfedge(he).unwrap()); +// } self.twin_alones(); } } @@ -854,22 +854,26 @@ mod tests { for face in mesh.face_iter() { println!("{:?}", mesh.face_vertices(face)); } - mesh.bevel_curve(&Vec::from_iter([0,4,5].iter().cloned().map(VertexID::new)), 0.1); // println!("halfedges:"); // for (i,he) in mesh.halfedge_iter().enumerate() { // println!("he {}\t{}\t{:?}", i, he, mesh.connectivity_info.halfedge(he).unwrap()); // } + // non-looped + mesh.bevel_curve(&Vec::from_iter([0,4,5].iter().cloned().map(VertexID::new)), 0.1); assert_eq!(nominal_no_vertices+3, mesh.no_vertices()); assert_eq!(nominal_no_halfedges+18, mesh.no_halfedges()); assert_eq!(nominal_no_faces+6, mesh.no_faces()); mesh.is_valid().unwrap(); + // looped over a face + mesh = MeshBuilder::new().icosahedron().build().unwrap(); mesh.bevel_curve(&Vec::from_iter([0,1,4].iter().cloned().map(VertexID::new)), 0.1); assert_eq!(nominal_no_vertices+3, mesh.no_vertices()); assert_eq!(nominal_no_halfedges+18, mesh.no_halfedges()); assert_eq!(nominal_no_faces+6, mesh.no_faces()); mesh.is_valid().unwrap(); + // loop over the whole mesh mesh = MeshBuilder::new().icosahedron().build().unwrap(); mesh.bevel_curve(&Vec::from_iter([0,4,5,3,7,6].iter().cloned().map(VertexID::new)), 0.2); mesh.is_valid().unwrap(); From e2937bb90dbc76b36d17e42ad4d798990f5240a6 Mon Sep 17 00:00:00 2001 From: jimy-byerley Date: Fri, 29 Nov 2019 09:01:37 +0100 Subject: [PATCH 12/14] removed debug infos printed, fix doc generation --- src/mesh/edit.rs | 36 ++++-------------------------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/src/mesh/edit.rs b/src/mesh/edit.rs index 404b287..9238158 100644 --- a/src/mesh/edit.rs +++ b/src/mesh/edit.rs @@ -70,7 +70,8 @@ impl Mesh /// - `start` and `end` must point to the same vertex. /// - the two points remains in the same initial location. /// - the point created becomes the vertex pointed by `start` - /// ``` + /// + /// ```text /// + + /// | / \ /// ------+------- --> ----+ +---- @@ -99,31 +100,26 @@ impl Mesh conn.set_halfedge_twin(rend, conn.new_halfedge(Some(created), None, None)); created } - /// variant of split_vertex, that doesn't create empty twin halfedges for the hole + /// variant of split_vertex, that doesn't create empty twin halfedges for the hole (makes it easier to fill it with faces) fn split_vertex_unfinished(&mut self, start: HalfEdgeID, end: HalfEdgeID) -> VertexID { assert_eq!( self.walker_from_halfedge(start).vertex_id().unwrap(), self.walker_from_halfedge(end).vertex_id().unwrap(), "spliting halfedges doesn't point to the same vertex"); + // duplicate the vertex let oldvert = self.walker_from_halfedge(start).vertex_id().unwrap(); let newvert = self.connectivity_info.new_vertex(self.vertex_position(oldvert)); - println!("splitting across {} {:?} {:?} {}", oldvert, start, end, newvert); // cut at start and at end self.connectivity_info.remove_halfedge_twin(start); self.connectivity_info.remove_halfedge_twin(end); self.connectivity_info.set_vertex_halfedge(newvert, self.walker_from_halfedge(start).as_next().halfedge_id()); self.connectivity_info.set_vertex_halfedge(oldvert, self.walker_from_halfedge(end ).as_next().halfedge_id()); -// println!("set {:?} to {:?}", newvert, self.walker_from_halfedge(start).as_next().halfedge_id()); -// println!("set {:?} to {:?}", oldvert, self.walker_from_halfedge(end ).as_next().halfedge_id()); // change refs to old vertex between these two halfedges let mut walker = self.walker_from_halfedge(start); while let Some(he) = walker.halfedge_id() { -// println!("set {:?} vertex from {} to {}", he, self.connectivity_info.halfedge(he).unwrap().vertex.unwrap(), newvert); self.connectivity_info.set_halfedge_vertex(he, newvert); walker.as_next().as_twin(); -// if walker.halfedge_id() == Some(start) {println!("reached start");} -// if walker.halfedge_id() == Some(end) {println!("reached end");} } newvert @@ -406,8 +402,6 @@ impl Mesh { assert!(edge.len() >= 2, "`edge` must be at least two points"); - println!("operate on a mesh of {} vertices\t{} halfedges", self.no_vertices(), self.no_halfedges()); - let err_continuous = "edge must be a list of contiguous vertices"; let err_border = "edge must not be on a border of the mesh"; @@ -437,7 +431,6 @@ impl Mesh // get the next edge to bevel else the ending one if i < edge.len()-1 { next = self.connecting_edge(edge[i], edge[i+1]) .expect(err_continuous); } else { next = last; } - assert_ne!(prev, self.walker_from_halfedge(next).as_twin().halfedge_id().unwrap()); let dir_next = self.edge_direction(next); let results_next = ( self.face_normal(self.walker_from_halfedge(next).face_id().unwrap()) .cross(dir_next), @@ -467,25 +460,14 @@ impl Mesh if endvert.is_none() {endvert = Some(facing[0][1]);} - println!("facing: {:#?}", facing); - // create start and end face - for face in self.face_iter() { - println!("has face {:?}", self.face_vertices(face)); - } self.connectivity_info.create_face(startvert, facing[0][0], facing[0][1]); self.connectivity_info.create_face(endvert.unwrap(), facing[facing.len()-1][1], facing[facing.len()-1][0]); // create all faces for confront in facing.windows(2) { self.connectivity_info.create_face(confront[0][1], confront[0][0], confront[1][1]); self.connectivity_info.create_face(confront[1][0], confront[1][1], confront[0][0]); - println!("create face {} {} {}", confront[0][1], confront[0][0], confront[1][1]); - println!("create face {} {} {}", confront[1][0], confront[1][1], confront[0][0]); } -// println!("halfedges:"); -// for (i,he) in self.halfedge_iter().enumerate() { -// println!("he {}\t{}\t{:?}", i, he, self.connectivity_info.halfedge(he).unwrap()); -// } self.twin_alones(); } } @@ -505,8 +487,6 @@ fn next_forward(mesh: &Mesh, start: HalfEdgeID) -> Option { score = s; } } - println!("next_forward is {:?} with score {}", next, score); - if let Some(vert) = next { assert_ne!(vert, start); } next } @@ -850,14 +830,6 @@ mod tests { let nominal_no_halfedges = mesh.no_halfedges(); let nominal_no_faces = mesh.no_faces(); - println!("faces:"); - for face in mesh.face_iter() { - println!("{:?}", mesh.face_vertices(face)); - } -// println!("halfedges:"); -// for (i,he) in mesh.halfedge_iter().enumerate() { -// println!("he {}\t{}\t{:?}", i, he, mesh.connectivity_info.halfedge(he).unwrap()); -// } // non-looped mesh.bevel_curve(&Vec::from_iter([0,4,5].iter().cloned().map(VertexID::new)), 0.1); assert_eq!(nominal_no_vertices+3, mesh.no_vertices()); From 657d1c2b5a0a89db87d29fb05e8c3ca80cba6784 Mon Sep 17 00:00:00 2001 From: jimy byerley Date: Fri, 29 Nov 2019 19:20:51 +0100 Subject: [PATCH 13/14] added and fixed remove_vertex() and Walker.stop() --- src/mesh/edit.rs | 56 +++++++++++++++++++++++++++++++++++++++++++ src/mesh/traversal.rs | 5 ++++ 2 files changed, 61 insertions(+) diff --git a/src/mesh/edit.rs b/src/mesh/edit.rs index 9238158..1f75a71 100644 --- a/src/mesh/edit.rs +++ b/src/mesh/edit.rs @@ -394,6 +394,54 @@ impl Mesh self.connectivity_info.remove_face(face_id); } + pub fn remove_vertex(&mut self, vertex: VertexID) + { + let conn = &self.connectivity_info; + let mut walker = self.walker_from_vertex(vertex).into_twin(); + + while let Some(h1) = walker.halfedge_id() { + walker.as_next(); + if let Some(h2) = walker.halfedge_id() { + if let Some(face) = walker.face_id() { + + walker.as_twin(); + + let mut wlk = self.walker_from_halfedge(h2).into_next(); + let h3 = wlk.halfedge_id().unwrap(); + wlk.as_twin(); + if wlk.face_id().is_some() { + conn.set_halfedge_face(h3, None); + conn.set_halfedge_next(h3, None); + } + else { + conn.remove_halfedge(h3); + if let Some(twin) = wlk.halfedge_id() { conn.remove_halfedge(twin); } + } + + conn.remove_face(face); + } + else { walker.stop(); } + conn.remove_halfedge(h2); + } + conn.remove_halfedge(h1); + + } + conn.remove_vertex(vertex); + } + + /* + /// cut a corner by a plane defined by its normal + pub fn bevel_vertex(&mut self, vertex: &VertexID, distance: f64, normal: Vec3) + { + let pos = self.vertex_position(vertex); + for he in self.vertex_halfedge_iter() { + let edgedir = self.edge_direction(he); + let cut = edgedir * (distance / edgedir.dot(normal)); + self.split_edge(pos + cut); + } + self.remove_vertex(vertex); + } + */ /// Create a bevel on the given edges, these must be contiguous and ordered (ie. `edge[i]` starts from `edge[i-1]`) /// This function is not a realistic chamfer, it can displace the edges that are cutted by the bevel. @@ -850,4 +898,12 @@ mod tests { mesh.bevel_curve(&Vec::from_iter([0,4,5,3,7,6].iter().cloned().map(VertexID::new)), 0.2); mesh.is_valid().unwrap(); } + + #[test] + fn test_remove_vertex() { + let mut mesh = MeshBuilder::new().cube().build().unwrap(); + mesh.remove_vertex(mesh.vertex_iter().next().unwrap()); + assert_eq!(7, mesh.no_vertices()); + mesh.is_valid().unwrap(); + } } diff --git a/src/mesh/traversal.rs b/src/mesh/traversal.rs index ef2c20f..34de739 100644 --- a/src/mesh/traversal.rs +++ b/src/mesh/traversal.rs @@ -224,6 +224,11 @@ impl<'a> Walker<'a> self.set_current(halfedge_id); self } + + pub fn stop(&mut self) + { + self.set_current(None); + } /// Returns the id of the vertex pointed to by the current half-edge or `None` if the walker has walked outside of the mesh at some point. pub fn vertex_id(&self) -> Option From 4e5c95acdef7df77adf5261f3cba4472bd7e1a05 Mon Sep 17 00:00:00 2001 From: jimy byerley Date: Fri, 29 Nov 2019 19:29:07 +0100 Subject: [PATCH 14/14] added bevel_vertex, not yet finished --- src/mesh/edit.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/mesh/edit.rs b/src/mesh/edit.rs index 1f75a71..9d1eac2 100644 --- a/src/mesh/edit.rs +++ b/src/mesh/edit.rs @@ -3,6 +3,7 @@ use crate::mesh::*; use crate::mesh::math::*; use crate::mesh::ids::*; +use std::iter::FromIterator; /// # Edit impl Mesh @@ -429,19 +430,24 @@ impl Mesh conn.remove_vertex(vertex); } - /* + /// cut a corner by a plane defined by its normal - pub fn bevel_vertex(&mut self, vertex: &VertexID, distance: f64, normal: Vec3) + pub fn bevel_vertex(&mut self, vertex: VertexID, distance: f64, normal: Vec3) { + let mut tocut = Vec::from_iter(self.vertex_halfedge_iter(vertex)); + let mut cuts = Vec::with_capacity(tocut.len()); let pos = self.vertex_position(vertex); - for he in self.vertex_halfedge_iter() { + for he in tocut { let edgedir = self.edge_direction(he); let cut = edgedir * (distance / edgedir.dot(normal)); - self.split_edge(pos + cut); + cuts.push(self.split_edge(he, pos + cut)); } self.remove_vertex(vertex); + + // triangulate the cuts + unimplemented!(); } - */ + /// Create a bevel on the given edges, these must be contiguous and ordered (ie. `edge[i]` starts from `edge[i-1]`) /// This function is not a realistic chamfer, it can displace the edges that are cutted by the bevel.