Finally got this bloody subdivision method working. I think.

This commit is contained in:
Chris Hodapp 2020-06-12 23:42:03 -04:00
parent 6c7b9695af
commit 701b1df915
3 changed files with 245 additions and 8 deletions

View File

@ -380,8 +380,8 @@ impl<V: Copy + std::fmt::Debug> DCELMesh<V> {
});
// 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<V: Copy + std::fmt::Debug> DCELMesh<V> {
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<V: Copy + std::fmt::Debug> DCELMesh<V> {
(f_n, [e_n, e_n+1, e_n+2])
}
pub fn split_face(&mut self, face: usize, verts: Vec<V>) {
// '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<usize> = (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<F>(&self, f: F) -> Mesh
where F: Fn(V) -> Vertex,
{
@ -503,8 +729,8 @@ impl<V: Copy + std::fmt::Debug> DCELMesh<V> {
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);
}
}

View File

@ -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);

View File

@ -666,7 +666,7 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, 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,