Internal refactor (as part of subdiv) in parametric_mesh
This commit is contained in:
parent
fe31de5af3
commit
6c7b9695af
48
src/dcel.rs
48
src/dcel.rs
@ -484,31 +484,33 @@ impl<V: Copy + std::fmt::Debug> DCELMesh<V> {
|
|||||||
|
|
||||||
(f_n, [e_n, e_n+1, e_n+2])
|
(f_n, [e_n, e_n+1, e_n+2])
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn convert_mesh(m: &DCELMesh<Vertex>) -> Mesh {
|
pub fn convert_mesh<F>(&self, f: F) -> Mesh
|
||||||
let n = m.faces.len();
|
where F: Fn(V) -> Vertex,
|
||||||
let mut faces: Vec<usize> = vec![0; 3 * n];
|
{
|
||||||
|
let n = self.faces.len();
|
||||||
|
let mut faces: Vec<usize> = vec![0; 3 * n];
|
||||||
|
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
|
|
||||||
let e0 = m.faces[i].halfedge;
|
let e0 = self.faces[i].halfedge;
|
||||||
let h0 = &m.halfedges[e0];
|
let h0 = &self.halfedges[e0];
|
||||||
faces[3*i + 0] = h0.vert;
|
faces[3*i + 0] = h0.vert;
|
||||||
let e1 = h0.next_halfedge;
|
let e1 = h0.next_halfedge;
|
||||||
let h1 = &m.halfedges[e1];
|
let h1 = &self.halfedges[e1];
|
||||||
faces[3*i + 1] = h1.vert;
|
faces[3*i + 1] = h1.vert;
|
||||||
let e2 = h1.next_halfedge;
|
let e2 = h1.next_halfedge;
|
||||||
let h2 = &m.halfedges[e2];
|
let h2 = &self.halfedges[e2];
|
||||||
faces[3*i + 2] = h2.vert;
|
faces[3*i + 2] = h2.vert;
|
||||||
if h2.next_halfedge != e0 {
|
if h2.next_halfedge != e0 {
|
||||||
panic!(format!("Face {}: half-edges {},{},{} return to {}, not {}",
|
panic!(format!("Face {}: half-edges {},{},{} return to {}, not {}",
|
||||||
i, e0, e1, e2, h2.next_halfedge, e0));
|
i, e0, e1, e2, h2.next_halfedge, e0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Mesh {
|
||||||
|
verts: self.verts.iter().map(|e| f(e.v)).collect(),
|
||||||
|
faces: faces,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Mesh {
|
|
||||||
verts: m.verts.iter().map(|e| e.v).collect(),
|
|
||||||
faces: faces,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1327,7 +1327,7 @@ pub fn test_dcel(fname: &str) {
|
|||||||
|
|
||||||
println!("DCEL mesh = {}", mesh);
|
println!("DCEL mesh = {}", mesh);
|
||||||
|
|
||||||
let mesh_conv = dcel::convert_mesh(&mesh);
|
let mesh_conv = mesh.convert_mesh(|i| i);
|
||||||
|
|
||||||
println!("Mesh = {:?}", mesh_conv);
|
println!("Mesh = {:?}", mesh_conv);
|
||||||
|
|
||||||
|
|||||||
113
src/rule.rs
113
src/rule.rs
@ -366,10 +366,8 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
panic!("frame must have at least 3 vertices");
|
panic!("frame must have at least 3 vertices");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut mesh: DCELMesh<Vertex> = DCELMesh::new();
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
struct VertexTrajectory {
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
struct frontierVert {
|
|
||||||
// Vertex position
|
// Vertex position
|
||||||
vert: Vertex,
|
vert: Vertex,
|
||||||
// Parameter value; f(t) should equal vert
|
// Parameter value; f(t) should equal vert
|
||||||
@ -377,13 +375,20 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
// "Starting" vertex position, i.e. at f(t0). Always either a frame
|
// "Starting" vertex position, i.e. at f(t0). Always either a frame
|
||||||
// vertex, or a linear combination of two neighboring ones.
|
// vertex, or a linear combination of two neighboring ones.
|
||||||
frame_vert: Vertex,
|
frame_vert: Vertex,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut mesh: DCELMesh<VertexTrajectory> = DCELMesh::new();
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct frontierVert {
|
||||||
|
traj: VertexTrajectory,
|
||||||
// If the boundaries on either side of this vertex lie on a face
|
// If the boundaries on either side of this vertex lie on a face
|
||||||
// (which is the case for all vertices *except* the initial ones),
|
// (which is the case for all vertices *except* the initial ones),
|
||||||
// then this gives the halfedges of those boundaries. halfedges[0]
|
// then this gives the halfedges of those boundaries. halfedges[0]
|
||||||
// connects the 'prior' vertex on the frontier to this, and
|
// connects the 'prior' vertex on the frontier to this, and
|
||||||
// halfedges[1] connect this to the 'next' vertex on the fronter.
|
// halfedges[1] connect this to the 'next' vertex on the fronter.
|
||||||
// (Direction matters. If halfedges[0] is given, it must *end* at
|
// (Direction matters. If halfedges[0] is given, it must *end* at
|
||||||
// 'vert'. If halfedges[1] is given, it must *begin* at 'vert'.)
|
// 'traj.vert'. If halfedges[1] is given, it must *begin* at 'traj.vert'.)
|
||||||
halfedges: [Option<usize>; 2],
|
halfedges: [Option<usize>; 2],
|
||||||
// If this vertex is already in 'mesh', its vertex index there:
|
// If this vertex is already in 'mesh', its vertex index there:
|
||||||
vert_idx: Option<usize>,
|
vert_idx: Option<usize>,
|
||||||
@ -391,9 +396,11 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
|
|
||||||
// Init 'frontier' with each 'frame' vertex, and start it at t=t0.
|
// Init 'frontier' with each 'frame' vertex, and start it at t=t0.
|
||||||
let mut frontier: Vec<frontierVert> = frame.iter().enumerate().map(|(i,v)| frontierVert {
|
let mut frontier: Vec<frontierVert> = frame.iter().enumerate().map(|(i,v)| frontierVert {
|
||||||
vert: *v,
|
traj: VertexTrajectory {
|
||||||
t: t0,
|
vert: *v,
|
||||||
frame_vert: *v,
|
t: t0,
|
||||||
|
frame_vert: *v,
|
||||||
|
},
|
||||||
halfedges: [None; 2],
|
halfedges: [None; 2],
|
||||||
vert_idx: None,
|
vert_idx: None,
|
||||||
}).collect();
|
}).collect();
|
||||||
@ -443,11 +450,11 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
let mut all_done = true;
|
let mut all_done = true;
|
||||||
|
|
||||||
for (i, v) in frontier.iter().enumerate() {
|
for (i, v) in frontier.iter().enumerate() {
|
||||||
if v.t < t_min {
|
if v.traj.t < t_min {
|
||||||
i_min = i;
|
i_min = i;
|
||||||
t_min = v.t;
|
t_min = v.traj.t;
|
||||||
}
|
}
|
||||||
all_done &= v.t >= t1;
|
all_done &= v.traj.t >= t1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no vertex can be advanced, we're done:
|
// If no vertex can be advanced, we're done:
|
||||||
@ -462,15 +469,16 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
let i_prev = (i + n - 1) % n;
|
let i_prev = (i + n - 1) % n;
|
||||||
let i_next = (i + 1) % n;
|
let i_next = (i + 1) % n;
|
||||||
|
|
||||||
println!("DEBUG: Moving frontier vertex {}, {:?} (t={}, frame_vert={:?})", i, v.vert, v.t, v.frame_vert);
|
println!("DEBUG: Moving frontier vertex {}, {:?} (t={}, frame_vert={:?})", i, v.traj.vert, v.traj.t, v.traj.frame_vert);
|
||||||
|
|
||||||
// Move this vertex further along, i.e. t + dt. (dt is set by
|
// Move this vertex further along, i.e. t + dt. (dt is set by
|
||||||
// the furthest we can go while remaining within 'err', i.e. when we
|
// the furthest we can go while remaining within 'err', i.e. when we
|
||||||
// make our connections we look at how far points on the *edges*
|
// make our connections we look at how far points on the *edges*
|
||||||
// diverge from the trajectory of the continuous transformation).
|
// diverge from the trajectory of the continuous transformation).
|
||||||
let dt_max = t1 - v.t;
|
let vf = v.traj.frame_vert;
|
||||||
|
let vt = v.traj.t;
|
||||||
|
let dt_max = t1 - vt;
|
||||||
let mut dt = ((t1 - t0) / 100.0).min(dt_max);
|
let mut dt = ((t1 - t0) / 100.0).min(dt_max);
|
||||||
let vf = v.frame_vert;
|
|
||||||
for iter in 0..100 {
|
for iter in 0..100 {
|
||||||
// Consider an edge from f(v.t)*vf to f(v.t + dt)*vf.
|
// Consider an edge from f(v.t)*vf to f(v.t + dt)*vf.
|
||||||
// These two endpoints have zero error from the trajectory
|
// These two endpoints have zero error from the trajectory
|
||||||
@ -478,9 +486,9 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
//
|
//
|
||||||
// If we assume some continuity in f, then we can guess that
|
// If we assume some continuity in f, then we can guess that
|
||||||
// the worst error occurs at the midpoint of the edge:
|
// the worst error occurs at the midpoint of the edge:
|
||||||
let edge_mid = 0.5 * (f(v.t).mtx + f(v.t + dt).mtx) * vf;
|
let edge_mid = 0.5 * (f(vt).mtx + f(vt + dt).mtx) * vf;
|
||||||
// ...relative to the trajectory midpoint:
|
// ...relative to the trajectory midpoint:
|
||||||
let traj_mid = f(v.t + dt / 2.0).mtx * vf;
|
let traj_mid = f(vt + dt / 2.0).mtx * vf;
|
||||||
let err = (edge_mid - traj_mid).norm();
|
let err = (edge_mid - traj_mid).norm();
|
||||||
|
|
||||||
//println!("DEBUG iter {}: dt={}, edge_mid={:?}, traj_mid={:?}, err={}", iter, dt, edge_mid, traj_mid, err);
|
//println!("DEBUG iter {}: dt={}, edge_mid={:?}, traj_mid={:?}, err={}", iter, dt, edge_mid, traj_mid, err);
|
||||||
@ -503,8 +511,12 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
// to do this directly given an analytical form of the
|
// to do this directly given an analytical form of the
|
||||||
// curvature of f at some starting point)
|
// curvature of f at some starting point)
|
||||||
|
|
||||||
let t = (v.t + dt).min(t1);
|
let t = (vt + dt).min(t1);
|
||||||
let v_next = f(t).mtx * vf;
|
let v_next = VertexTrajectory {
|
||||||
|
vert: f(t).mtx * vf,
|
||||||
|
t: t,
|
||||||
|
frame_vert: vf,
|
||||||
|
};
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
/*
|
/*
|
||||||
@ -532,11 +544,11 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
let (f1, edges) = mesh.add_face([
|
let (f1, edges) = mesh.add_face([
|
||||||
VertSpec::New(v_next), // edges[0]: v_next -> v
|
VertSpec::New(v_next), // edges[0]: v_next -> v
|
||||||
match v.vert_idx {
|
match v.vert_idx {
|
||||||
None => VertSpec::New(v.vert),
|
None => VertSpec::New(v.traj),
|
||||||
Some(idx) => VertSpec::Idx(idx),
|
Some(idx) => VertSpec::Idx(idx),
|
||||||
}, // edges[1]: v -> neighbor
|
}, // edges[1]: v -> neighbor
|
||||||
match neighbor.vert_idx {
|
match neighbor.vert_idx {
|
||||||
None => VertSpec::New(neighbor.vert),
|
None => VertSpec::New(neighbor.traj),
|
||||||
Some(idx) => VertSpec::Idx(idx),
|
Some(idx) => VertSpec::Idx(idx),
|
||||||
}, // edges[2]: neighbor -> v_next
|
}, // edges[2]: neighbor -> v_next
|
||||||
]);
|
]);
|
||||||
@ -580,9 +592,9 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
|
|
||||||
let (f2, edges) = match neighbor.vert_idx {
|
let (f2, edges) = match neighbor.vert_idx {
|
||||||
None => {
|
None => {
|
||||||
let v = neighbor.vert;
|
//let v = neighbor.traj.vert;
|
||||||
println!("DEBUG: add_face_twin1({}, ({},{},{}))", edge_v_next, v.x, v.y, v.z);
|
//println!("DEBUG: add_face_twin1({}, ({},{},{}))", edge_v_next, v.x, v.y, v.z);
|
||||||
let (f2, edges) = mesh.add_face_twin1(edge_v_next, neighbor.vert);
|
let (f2, edges) = mesh.add_face_twin1(edge_v_next, neighbor.traj);
|
||||||
// Reasoning here is identical to "If neighbor.vert_idx
|
// Reasoning here is identical to "If neighbor.vert_idx
|
||||||
// is None..." above:
|
// is None..." above:
|
||||||
frontier[i_next].vert_idx = Some(mesh.halfedges[edges[2]].vert);
|
frontier[i_next].vert_idx = Some(mesh.halfedges[edges[2]].vert);
|
||||||
@ -590,7 +602,7 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
(f2, edges)
|
(f2, edges)
|
||||||
},
|
},
|
||||||
Some(vert_idx) => {
|
Some(vert_idx) => {
|
||||||
println!("DEBUG: add_face_twin1_ref({}, {})", edge_v_next, vert_idx);
|
//println!("DEBUG: add_face_twin1_ref({}, {})", edge_v_next, vert_idx);
|
||||||
mesh.add_face_twin1_ref(edge_v_next, vert_idx)
|
mesh.add_face_twin1_ref(edge_v_next, vert_idx)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -630,9 +642,11 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
|
|
||||||
// Replace this vertex in the frontier:
|
// Replace this vertex in the frontier:
|
||||||
frontier[i] = frontierVert {
|
frontier[i] = frontierVert {
|
||||||
vert: v_next,
|
traj: VertexTrajectory {
|
||||||
frame_vert: vf,
|
vert: v_next.vert,
|
||||||
t: t,
|
frame_vert: vf,
|
||||||
|
t: t,
|
||||||
|
},
|
||||||
halfedges: [Some(edge1), Some(edge2)],
|
halfedges: [Some(edge1), Some(edge2)],
|
||||||
vert_idx: Some(mesh.halfedges[edge_v_next].vert),
|
vert_idx: Some(mesh.halfedges[edge_v_next].vert),
|
||||||
};
|
};
|
||||||
@ -642,38 +656,22 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
frontier[i_next].halfedges[0] = Some(edge2);
|
frontier[i_next].halfedges[0] = Some(edge2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A face that is still undergoing subdivision. This is used for a
|
|
||||||
// stack in the loop below.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
struct tempFace {
|
|
||||||
// The parameter values corresponding to 'verts':
|
|
||||||
ts: [f32; 3],
|
|
||||||
// The 'frame' vertices (i.e. vertex at f(t0)) corresponding
|
|
||||||
// to 'verts':
|
|
||||||
frame_verts: [Vertex; 3],
|
|
||||||
// Index into 'mesh.faces':
|
|
||||||
idx: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// A stack of face indices for faces in 'mesh' that are still
|
// A stack of face indices for faces in 'mesh' that are still
|
||||||
// undergoing subdivision
|
// undergoing subdivision
|
||||||
let mut stack: Vec<tempFace> = (0..mesh.num_faces).map(|i| tempFace {
|
let mut stack: Vec<usize> = (0..mesh.num_faces).collect();
|
||||||
idx: i,
|
|
||||||
}).collect();
|
|
||||||
// TODO: Must I populate in the main loop?
|
|
||||||
|
|
||||||
while !stack.is_empty() {
|
while !stack.is_empty() {
|
||||||
let face = stack.pop().unwrap();
|
let face = stack.pop().unwrap();
|
||||||
println!("DEBUG: Examining face: {:?}", face.idx);
|
println!("DEBUG: Examining face: {:?}", face);
|
||||||
|
|
||||||
let v_idx = mesh.face_to_verts(face.idx);
|
let v_idx = mesh.face_to_verts(face);
|
||||||
if v_idx.len() != 3 {
|
if v_idx.len() != 3 {
|
||||||
panic!(format!("Face {} has {} vertices, not 3?", face.idx, v_idx.len()));
|
panic!(format!("Face {} has {} vertices, not 3?", face, v_idx.len()));
|
||||||
}
|
}
|
||||||
let v0 = mesh.verts[v_idx[0]].v;
|
let tr = [mesh.verts[v_idx[0]].v,
|
||||||
let v1 = mesh.verts[v_idx[1]].v;
|
mesh.verts[v_idx[1]].v,
|
||||||
let v2 = mesh.verts[v_idx[2]].v;
|
mesh.verts[v_idx[2]].v];
|
||||||
|
let (v0, v1, v2) = (tr[0].vert, tr[1].vert, tr[2].vert);
|
||||||
let d01 = (v0 - v1).norm();
|
let d01 = (v0 - v1).norm();
|
||||||
let d02 = (v0 - v2).norm();
|
let d02 = (v0 - v2).norm();
|
||||||
let d12 = (v1 - v2).norm();
|
let d12 = (v1 - v2).norm();
|
||||||
@ -699,8 +697,8 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
let normal = a.cross(&b).normalize();
|
let normal = a.cross(&b).normalize();
|
||||||
// Make a new point that is on the surface, but roughly a
|
// Make a new point that is on the surface, but roughly a
|
||||||
// midpoint in parameter space. Exact location isn't crucial.
|
// midpoint in parameter space. Exact location isn't crucial.
|
||||||
let t_mid = (face.ts[0] + face.ts[1] + face.ts[2]) / 3.0;
|
let t_mid = (tr[0].t + tr[1].t + tr[2].t) / 3.0;
|
||||||
let v_mid = (face.frame_verts[0] + face.frame_verts[1] + face.frame_verts[2]) / 3.0;
|
let v_mid = (tr[0].frame_vert + tr[1].frame_vert + tr[2].frame_vert) / 3.0;
|
||||||
let p = f(t_mid).mtx * v_mid;
|
let p = f(t_mid).mtx * v_mid;
|
||||||
|
|
||||||
let d = p.xyz().dot(&normal);
|
let d = p.xyz().dot(&normal);
|
||||||
@ -730,9 +728,9 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
|
|
||||||
// This split is done in 'parameter' space:
|
// This split is done in 'parameter' space:
|
||||||
let pairs = [(0,1), (1,2), (0,2)];
|
let pairs = [(0,1), (1,2), (0,2)];
|
||||||
let mut mids = pairs.iter().map(|(i,j)| {
|
let mut mids: Vec<Vertex> = pairs.iter().map(|(i,j)| {
|
||||||
let t = (face.ts[*i] + face.ts[*j]) / 2.0;
|
let t = (tr[*i].t + tr[*j].t) / 2.0;
|
||||||
let v = (face.frame_verts[*i] + face.frame_verts[*j]) / 2.0;
|
let v = (tr[*i].frame_vert + tr[*j].frame_vert) / 2.0;
|
||||||
f(t).mtx * v
|
f(t).mtx * v
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
@ -752,7 +750,6 @@ pub fn parametric_mesh<F>(frame: Vec<Vertex>, f: F, t0: f32, t1: f32, max_err: f
|
|||||||
]);
|
]);
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
return dcel::convert_mesh(&mesh);
|
return mesh.convert_mesh(|i| i.vert );
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user