From 701b1df915a9c57bc02568930b4a1e72cc1a2687 Mon Sep 17 00:00:00 2001 From: Chris Hodapp Date: Fri, 12 Jun 2020 23:42:03 -0400 Subject: [PATCH] Finally got this bloody subdivision method working. I think. --- src/dcel.rs | 238 ++++++++++++++++++++++++++++++++++++++++++++++-- src/examples.rs | 13 ++- src/rule.rs | 2 +- 3 files changed, 245 insertions(+), 8 deletions(-) diff --git a/src/dcel.rs b/src/dcel.rs index 0c66e61..2ae7800 100644 --- a/src/dcel.rs +++ b/src/dcel.rs @@ -380,8 +380,8 @@ impl DCELMesh { }); // DEBUG if self.halfedges[twin].has_twin { - panic!(format!("Trying to add twin to {}, which already has twin ({})", - twin, self.halfedges[twin].twin_halfedge)); + panic!("Trying to add twin to {}, which already has twin ({})", + twin, self.halfedges[twin].twin_halfedge); } self.halfedges[twin].has_twin = true; self.halfedges[twin].twin_halfedge = e_n; @@ -440,8 +440,8 @@ impl DCELMesh { let v3 = twin2.vert; if v1 != self.halfedges[twin2.next_halfedge].vert { - panic!(format!("twin2 ({}) must end where twin1 ({}) begins, but does not (vertex {} vs. {})", - twin2_idx, twin1_idx, self.halfedges[twin2.next_halfedge].vert, v1)); + panic!("twin2 ({}) must end where twin1 ({}) begins, but does not (vertex {} vs. {})", + twin2_idx, twin1_idx, self.halfedges[twin2.next_halfedge].vert, v1); } // twin1 is: v1 -> v2, twin2 is: v3 -> v1. @@ -485,6 +485,232 @@ impl DCELMesh { (f_n, [e_n, e_n+1, e_n+2]) } + pub fn split_face(&mut self, face: usize, verts: Vec) { + // 'verts' maps 1:1 to vertices for 'face' (i.e. face_to_verts). + + let mut edge_idx = self.faces[face].halfedge; + let n = verts.len(); + + // + let new_edges: Vec<(usize, usize)> = verts.iter().map(|v| { + + println!("DEBUG: halfedge 3: {:?}", self.halfedges[3]); + println!("DEBUG: halfedge {}: {:?}", self.halfedges[3].next_halfedge, self.halfedges[self.halfedges[3].next_halfedge]); + + // As we iterate over every vertex, we walk the half-edges: + let mut edge = self.halfedges[edge_idx].clone(); + if !edge.has_twin { + panic!("Halfedge {} has no twin, and split_face (for now) requires twins", edge_idx); + } + // TODO: Remove the above limitation and just don't try to split + // nonexistent twins. I think all logic works the same way. + + let next_idx = edge.next_halfedge; + let twin_idx = edge.twin_halfedge; + let mut twin = self.halfedges[twin_idx].clone(); + + // This half-edge, and its twin, are both split (at this + // vertex). Half-edges i & j will be the new ones created. + let i_edge = self.num_halfedges; + let j_edge = i_edge + 1; + // Half of edge_idx is split into j_edge. + // Half of twin_idx (its twin) is split into i_edge. + + println!("DEBUG: edge_idx={} next_idx={} twin_idx={} i_edge={} j_edge={}", edge_idx, next_idx, twin_idx, i_edge, j_edge); + // This is where the vertex will be inserted: + let v_idx = self.num_verts; + println!("DEBUG: adding v_idx={}", v_idx); + self.verts.push(DCELVertex { + v: *v, + halfedge: i_edge, // j_edge is also fine + }); + self.num_verts += 1; + + edge.twin_halfedge = i_edge; + let j_next = edge.next_halfedge; + + twin.twin_halfedge = j_edge; + let i_next = twin.next_halfedge; + println!("DEBUG: new twin of {} = {}; new twin of {} = {}", edge_idx, i_edge, twin_idx, j_edge); + + self.halfedges.push(DCELHalfEdge { + vert: v_idx, + face: 0, // This is set properly in the next loop + has_twin: true, + twin_halfedge: edge_idx, + next_halfedge: i_next, + prev_halfedge: twin_idx, + }); // i_edge + println!("DEBUG: edge {}: vert {} twin {} next {} prev {} (ends at vertex {})", i_edge, v_idx, edge_idx, i_next, twin_idx, self.halfedges[self.halfedges[twin_idx].next_halfedge].vert); + + self.halfedges.push(DCELHalfEdge { + vert: v_idx, + face: 0, // This is set properly in the next loop + has_twin: true, + twin_halfedge: twin_idx, + next_halfedge: j_next, + prev_halfedge: edge_idx, + }); // j_edge + println!("DEBUG: edge {}: vert {} twin {} next {} prev {} (ends at vertex {})", j_edge, v_idx, twin_idx, j_next, edge_idx, self.halfedges[self.halfedges[edge_idx].next_halfedge].vert); + + self.num_halfedges += 2; + + self.halfedges[edge_idx] = edge; + self.halfedges[twin_idx] = twin; + + let r = (edge_idx, j_edge); + + edge_idx = next_idx; + + r + }).collect(); + + println!("DEBUG: {:?}", new_edges); + + // We then must connect some edges up 'across' vertices + // in order to form the smaller face at each vertex. + // + // This is outside the loop because we need one iteration's + // value (any iteration, doesn't matter) to reassign a face: + let mut e_twin_idx = 0; + let twin_edges: Vec = (0..n).map(|i0| { + let i1 = (i0 + 1) % n; + + let (_, ep_idx) = new_edges[i0]; + let (en_idx, _) = new_edges[i1]; + + // Halfedges will be inserted here: + let e_cross_idx = self.num_halfedges; + e_twin_idx = e_cross_idx + 1; + // And the face here: + let face_new = self.num_faces; + + println!("DEBUG: i0={} i1={} ep_idx={} en_idx={} e_cross_idx={} e_twin_idx={} face_new={}", + i0, i1, ep_idx, en_idx, e_cross_idx, e_twin_idx, face_new); + + // So, the vertex for i0 had two halfedges (one pointing in, + // one pointing out). We split both those half-edges earlier. + // en_idx & ep_idx are the halves that are nearest the + // vertex. The point of below is to form a smaller triangle + // (which includes this vertex, and the point at which both + // edges were split). This requires a half-edge from ep_idx + // (which *starts* where the other was split) to en_idx (which + // *ends* where one edge was split). + self.halfedges.push(DCELHalfEdge { + vert: self.halfedges[self.halfedges[en_idx].twin_halfedge].vert, + face: face_new, + has_twin: true, + twin_halfedge: e_twin_idx, + next_halfedge: ep_idx, + prev_halfedge: en_idx, + }); // e_cross_idx + println!("DEBUG: edge {}: vert {} twin {} next {} prev {} (ends at vertex {})", e_cross_idx, self.halfedges[en_idx].vert, e_twin_idx, ep_idx, en_idx, self.halfedges[self.halfedges[e_cross_idx].next_halfedge].vert); + + // It also requires a twin half-edge. These all form a single + // central face with each edge sharing a boundary with the + // 'cross' edge we just created. + self.halfedges.push(DCELHalfEdge { + vert: self.halfedges[ep_idx].vert, + face: face, // Reuse index for the smaller *central* face + has_twin: true, + twin_halfedge: e_cross_idx, + next_halfedge: 0, // TODO + prev_halfedge: 0, // TODO + }); // e_twin_idx + println!("DEBUG: edge {}: vert {} twin {} next/prev incorrect", e_twin_idx, self.halfedges[ep_idx].vert, e_cross_idx); + + self.num_halfedges += 2; + + // en/ep also need directed to 'new' edges and each other + self.halfedges[en_idx].prev_halfedge = ep_idx; + self.halfedges[en_idx].next_halfedge = e_cross_idx; + println!("DEBUG: edge {}: now next {} prev {} ends at vert {}", en_idx, e_cross_idx, ep_idx, self.halfedges[self.halfedges[en_idx].next_halfedge].vert); + + self.halfedges[ep_idx].next_halfedge = en_idx; + self.halfedges[ep_idx].prev_halfedge = e_cross_idx; + println!("DEBUG: edge {}: now next {} prev {} ends at vert {}", ep_idx, en_idx, e_cross_idx, self.halfedges[self.halfedges[ep_idx].next_halfedge].vert); + + self.halfedges[ep_idx].face = face_new; + + self.faces.push(DCELFace { + halfedge: e_cross_idx, // en_idx or ep_idx is fine too + }); + self.num_faces += 1; + + // We also need to split the opposite side to make the two + // 'side' triangles (which means two new half-edges). + // First, we have to find the halfedge that starts the + // 'opposite' vertex (outer2): + let base1 = self.halfedges[en_idx].twin_halfedge; + let base2 = self.halfedges[base1].prev_halfedge; + let outer1 = self.halfedges[base1].next_halfedge; + let outer2 = self.halfedges[outer1].next_halfedge; + let v_opp = self.halfedges[outer2].vert; + // One face will reuse the old index: + let face1 = self.halfedges[outer2].face; + // Another will be inserted at this index: + let face2 = self.num_faces; + // Half-edges will be inserted here: + let edge_side1 = self.num_halfedges; + let edge_side2 = edge_side1 + 1; + self.halfedges.push(DCELHalfEdge { + vert: v_opp, + face: face1, + has_twin: true, + twin_halfedge: edge_side2, + next_halfedge: base1, + prev_halfedge: outer1, + }); // edge_side1 + self.halfedges.push(DCELHalfEdge { + vert: self.halfedges[base1].vert, + face: face2, + has_twin: true, + twin_halfedge: edge_side1, + next_halfedge: outer2, + prev_halfedge: base2, + }); // edge_side2 + self.num_halfedges += 2; + + self.faces.push(DCELFace { + halfedge: outer2, // base2 or edge_side2 is fine too + }); + self.num_faces += 1; + self.faces[face1].halfedge = outer1; // base1 or edge_side1 is fine too + + self.halfedges[outer1].next_halfedge = edge_side1; + self.halfedges[outer1].prev_halfedge = base1; + self.halfedges[outer1].face = face1; + self.halfedges[base1].face = face1; + self.halfedges[base1].prev_halfedge = edge_side1; + self.halfedges[base1].next_halfedge = outer1; + + self.halfedges[outer2].next_halfedge = base2; + self.halfedges[outer2].prev_halfedge = edge_side2; + self.halfedges[outer2].face = face2; + self.halfedges[base2].face = face2; + self.halfedges[base2].prev_halfedge = outer2; + self.halfedges[base2].next_halfedge = edge_side2; + + println!("DEBUG: base1={} base2={} outer1={} outer2={} face1={} face2={} edge_side1={} edge_side2={}", + base1, base2, outer1, outer2, face1, face2, edge_side1, edge_side2); + e_twin_idx + }).collect(); + + println!("DEBUG: cross_edges={:?}", twin_edges); + + for i0 in 0..n { + let i1 = (i0 + 1) % n; + + self.halfedges[twin_edges[i0]].next_halfedge = twin_edges[i1]; + self.halfedges[twin_edges[i1]].prev_halfedge = twin_edges[i0]; + } + + // We split up original 'face' completely and created four new faces, + // We need something at this index, and the other three already have + // indices, so reuse it for the smaller central face: + self.faces[face].halfedge = e_twin_idx; + } + pub fn convert_mesh(&self, f: F) -> Mesh where F: Fn(V) -> Vertex, { @@ -503,8 +729,8 @@ impl DCELMesh { let h2 = &self.halfedges[e2]; faces[3*i + 2] = h2.vert; if h2.next_halfedge != e0 { - panic!(format!("Face {}: half-edges {},{},{} return to {}, not {}", - i, e0, e1, e2, h2.next_halfedge, e0)); + panic!("Face {}: half-edges {},{},{} return to {}, not {}", + i, e0, e1, e2, h2.next_halfedge, e0); } } diff --git a/src/examples.rs b/src/examples.rs index 6d6be77..260fc21 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -1325,7 +1325,18 @@ pub fn test_dcel(fname: &str) { println!("f3 verts: {:?}", mesh.face_to_verts(f3)); println!("f4 verts: {:?}", mesh.face_to_verts(f4)); - println!("DCEL mesh = {}", mesh); + println!("DCEL mesh: "); + mesh.print(); + + mesh.split_face(f1, vec![ + vertex(-0.5, 0.0, 0.0), + vertex(0.0, 0.5, 0.0), + vertex(0.0, 0.0, 0.0), + ]); + + println!("DCEL mesh after subdiv"); + mesh.check(); + mesh.print(); let mesh_conv = mesh.convert_mesh(|i| i); diff --git a/src/rule.rs b/src/rule.rs index e41bddf..c50c3c5 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -666,7 +666,7 @@ pub fn parametric_mesh(frame: Vec, f: F, t0: f32, t1: f32, max_err: f let v_idx = mesh.face_to_verts(face); if v_idx.len() != 3 { - panic!(format!("Face {} has {} vertices, not 3?", face, v_idx.len())); + panic!("Face {} has {} vertices, not 3?", face, v_idx.len()); } let tr = [mesh.verts[v_idx[0]].v, mesh.verts[v_idx[1]].v,