Mesh stuff ugly-refactored but untested

This commit is contained in:
Chris Hodapp 2020-05-12 15:46:03 -04:00
parent 0ad03ac77d
commit 7626f1a089
6 changed files with 306 additions and 225 deletions

View File

@ -1,14 +1,15 @@
use std::rc::Rc; use std::rc::Rc;
use nalgebra::*; use nalgebra::*;
use rand::Rng; use rand::Rng;
//pub mod examples;
use crate::openmesh::{OpenMesh, Tag}; use crate::util;
use crate::xform::{Transform, vertex, Mat4}; use crate::mesh::{Mesh, MeshTemplate};
use crate::xform::{Transform, Vertex, vertex, Mat4};
use crate::rule::{Rule, RuleFn, RuleEval, Child}; use crate::rule::{Rule, RuleFn, RuleEval, Child};
use crate::prim; use crate::prim;
use crate::util;
/*
pub fn cube_thing() -> Rule<()> { pub fn cube_thing() -> Rule<()> {
// Quarter-turn in radians: // Quarter-turn in radians:
@ -47,11 +48,12 @@ pub fn cube_thing() -> Rule<()> {
pub fn barbs() -> Rule<()> { pub fn barbs() -> Rule<()> {
let base_verts = vec![ let (a0, a1);
vertex(-0.5, -0.5, 0.0), let base_verts: Vec<Vertex> = vec_indexed![
@a0: vertex(-0.5, -0.5, 0.0),
vertex(-0.5, 0.5, 0.0), vertex(-0.5, 0.5, 0.0),
vertex( 0.5, 0.5, 0.0), vertex( 0.5, 0.5, 0.0),
vertex( 0.5, -0.5, 0.0), @a1: vertex( 0.5, -0.5, 0.0),
]; ];
let n = base_verts.len(); let n = base_verts.len();
@ -64,10 +66,11 @@ pub fn barbs() -> Rule<()> {
let barb = move |self_: Rc<Rule<()>>| -> RuleEval<()> { let barb = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
let next_verts = incr.transform(&b); let next_verts = incr.transform(&b);
let geom = Rc::new(util::zigzag_to_parent(next_verts.clone(), n)); let geom = Rc::new(util::zigzag_to_parent(next_verts.clone(), a0..a1));
let (vc, faces) = util::connect_convex(&next_verts, true); let (vc, faces) = util::connect_convex(&next_verts, true);
let final_geom = Rc::new(OpenMesh { let final_geom = Rc::new(OpenMesh {
verts: vec![vc], verts: vec![vc],
alias_verts: vec![],
faces: faces, faces: faces,
}); });
@ -93,6 +96,7 @@ pub fn barbs() -> Rule<()> {
let (vc, faces) = util::connect_convex(&next_verts, true); let (vc, faces) = util::connect_convex(&next_verts, true);
let final_geom = Rc::new(OpenMesh { let final_geom = Rc::new(OpenMesh {
verts: vec![vc], verts: vec![vc],
alias_verts: vec![],
faces: faces, faces: faces,
}); });
@ -114,9 +118,10 @@ pub fn barbs() -> Rule<()> {
RuleEval { RuleEval {
geom: Rc::new(OpenMesh { geom: Rc::new(OpenMesh {
verts: base_verts.clone(), verts: base_verts.clone(),
alias_verts: vec![],
faces: vec![ faces: vec![
Tag::Body(0), Tag::Body(1), Tag::Body(2), 0, 1, 2,
Tag::Body(0), Tag::Body(2), Tag::Body(3), 0, 1, 3,
], ],
}), }),
final_geom: Rc::new(prim::empty_mesh()), final_geom: Rc::new(prim::empty_mesh()),
@ -173,6 +178,7 @@ pub fn twist(f: f32, subdiv: usize) -> Rule<()> {
let (vc, faces) = util::connect_convex(&seed_next, true); let (vc, faces) = util::connect_convex(&seed_next, true);
let final_geom = Rc::new(OpenMesh { let final_geom = Rc::new(OpenMesh {
verts: vec![vc], verts: vec![vc],
alias_verts: vec![],
faces: faces, faces: faces,
}); });
@ -212,7 +218,7 @@ pub fn twist(f: f32, subdiv: usize) -> Rule<()> {
// and in the process, generate faces for these seeds: // and in the process, generate faces for these seeds:
let (centroid, f) = util::connect_convex(&vs, false); let (centroid, f) = util::connect_convex(&vs, false);
vs.push(centroid); vs.push(centroid);
(OpenMesh { verts: vs, faces: f }, c) (OpenMesh { verts: vs, faces: f, alias_verts: vec![] }, c)
}; };
// Generate 'count' children, shifted/rotated differently: // Generate 'count' children, shifted/rotated differently:
@ -247,6 +253,7 @@ pub fn nest_spiral_2() -> Rule<NestSpiral2Ctxt> {
let (vc, faces) = util::connect_convex(&seed, true); let (vc, faces) = util::connect_convex(&seed, true);
let final_geom = Rc::new(OpenMesh { let final_geom = Rc::new(OpenMesh {
verts: vec![vc], verts: vec![vc],
alias_verts: vec![],
faces: faces, faces: faces,
}); });
@ -276,7 +283,7 @@ pub fn nest_spiral_2() -> Rule<NestSpiral2Ctxt> {
let (centroid, f) = util::connect_convex(&s2, false); let (centroid, f) = util::connect_convex(&s2, false);
s2.push(centroid); s2.push(centroid);
let n2 = s2.len(); let n2 = s2.len();
let g = OpenMesh { verts: s2, faces: f }; let g = OpenMesh { verts: s2, faces: f, alias_verts: vec![] };
RuleEval { RuleEval {
geom: Rc::new(g.transform(&xf)), geom: Rc::new(g.transform(&xf)),
final_geom: Rc::new(prim::empty_mesh()), final_geom: Rc::new(prim::empty_mesh()),
@ -369,6 +376,7 @@ pub fn twisty_torus() -> Rule<TorusCtxt> {
let (vc, faces) = util::connect_convex(&seed, true); let (vc, faces) = util::connect_convex(&seed, true);
let final_geom = Rc::new(OpenMesh { let final_geom = Rc::new(OpenMesh {
verts: vec![vc], verts: vec![vc],
alias_verts: (0..(n+1)).collect(),
faces: faces, faces: faces,
}); });
@ -404,7 +412,7 @@ pub fn twisty_torus() -> Rule<TorusCtxt> {
let (centroid, f) = util::connect_convex(&s2, false); let (centroid, f) = util::connect_convex(&s2, false);
s2.push(centroid); s2.push(centroid);
let n2 = s2.len(); let n2 = s2.len();
let g = OpenMesh { verts: s2, faces: f }; let g = OpenMesh { verts: s2, faces: f, alias_verts: vec![] };
RuleEval { RuleEval {
geom: Rc::new(g.transform(&xf)), geom: Rc::new(g.transform(&xf)),
final_geom: Rc::new(prim::empty_mesh()), final_geom: Rc::new(prim::empty_mesh()),
@ -469,6 +477,7 @@ pub fn twisty_torus_hardcode() -> Rule<()> {
let (vc, faces) = util::connect_convex(&next, true); let (vc, faces) = util::connect_convex(&next, true);
let final_geom = Rc::new(OpenMesh { let final_geom = Rc::new(OpenMesh {
verts: vec![vc], verts: vec![vc],
alias_verts: (0..(n+1)).collect(), // TODO: Fix parent/connect_convex
faces: faces, faces: faces,
}); });
@ -497,7 +506,7 @@ pub fn twisty_torus_hardcode() -> Rule<()> {
let (centroid, f) = util::connect_convex(&s2, false); let (centroid, f) = util::connect_convex(&s2, false);
s2.push(centroid); s2.push(centroid);
let n2 = s2.len(); let n2 = s2.len();
let g = OpenMesh { verts: s2, faces: f }; let g = OpenMesh { verts: s2, faces: f, alias_verts: vec![] };
RuleEval { RuleEval {
geom: Rc::new(g.transform(&xf)), geom: Rc::new(g.transform(&xf)),
final_geom: Rc::new(prim::empty_mesh()), final_geom: Rc::new(prim::empty_mesh()),
@ -540,6 +549,7 @@ pub fn wind_chime_mistake_thing() -> Rule<WindChimeCtxt> {
let (vc, faces) = util::connect_convex(&seed, true); let (vc, faces) = util::connect_convex(&seed, true);
let final_geom = Rc::new(OpenMesh { let final_geom = Rc::new(OpenMesh {
verts: vec![vc], verts: vec![vc],
alias_verts: (0..(n + 1)).collect(), // TODO: Check with parents (zigzag/connect_convex)
faces: faces, faces: faces,
}); });
@ -572,7 +582,7 @@ pub fn wind_chime_mistake_thing() -> Rule<WindChimeCtxt> {
let (centroid, f) = util::connect_convex(&s2, false); let (centroid, f) = util::connect_convex(&s2, false);
s2.push(centroid); s2.push(centroid);
let n2 = s2.len(); let n2 = s2.len();
let g = OpenMesh { verts: s2, faces: f }; let g = OpenMesh { verts: s2, faces: f, alias_verts: vec![] };
RuleEval { RuleEval {
geom: Rc::new(g.transform(&xf)), geom: Rc::new(g.transform(&xf)),
final_geom: Rc::new(prim::empty_mesh()), final_geom: Rc::new(prim::empty_mesh()),
@ -629,23 +639,25 @@ pub fn ramhorn() -> Rule<()> {
]; ];
let next = incr.transform(&seed); let next = incr.transform(&seed);
let geom = Rc::new(OpenMesh { let geom = Rc::new(OpenMesh {
alias_verts: vec![0, 1, 2, 3],
verts: next, verts: next,
faces: vec![ faces: vec![
Tag::Body(1), Tag::Parent(0), Tag::Body(0), 5, 0, 4,
Tag::Parent(1), Tag::Parent(0), Tag::Body(1), 1, 0, 5,
Tag::Body(2), Tag::Parent(1), Tag::Body(1), 6, 1, 5,
Tag::Parent(2), Tag::Parent(1), Tag::Body(2), 2, 1, 6,
Tag::Body(3), Tag::Parent(2), Tag::Body(2), 7, 2, 6,
Tag::Parent(3), Tag::Parent(2), Tag::Body(3), 3, 2, 7,
Tag::Body(0), Tag::Parent(3), Tag::Body(3), 4, 3, 7,
Tag::Parent(0), Tag::Parent(3), Tag::Body(0), 0, 3, 4,
], ],
}); });
let final_geom = Rc::new(OpenMesh { let final_geom = Rc::new(OpenMesh {
verts: vec![], verts: vec![],
alias_verts: vec![0, 1, 2, 3],
faces: vec![ faces: vec![
Tag::Parent(0), Tag::Parent(2), Tag::Parent(1), 0, 2, 1,
Tag::Parent(0), Tag::Parent(3), Tag::Parent(2), 0, 3, 2,
], ],
}); });
@ -695,27 +707,28 @@ pub fn ramhorn() -> Rule<()> {
vertex( 0.5, 0.5, 0.0), // 11 vertex( 0.5, 0.5, 0.0), // 11
vertex( 0.5, -0.5, 0.0), // 12 vertex( 0.5, -0.5, 0.0), // 12
], ],
alias_verts: vec![],
faces: vec![ faces: vec![
// bottom face: // bottom face:
Tag::Body(9), Tag::Body(10), Tag::Body(11), 9, 10, 11,
Tag::Body(9), Tag::Body(11), Tag::Body(12), 9, 11, 12,
// two faces straddling edge from vertex 0: // two faces straddling edge from vertex 0:
Tag::Body(9), Tag::Body(0), Tag::Body(4), 9, 0, 4,
Tag::Body(9), Tag::Body(7), Tag::Body(0), 9, 7, 0,
// two faces straddling edge from vertex 1: // two faces straddling edge from vertex 1:
Tag::Body(10), Tag::Body(1), Tag::Body(5), 10, 1, 5,
Tag::Body(10), Tag::Body(4), Tag::Body(1), 10, 4, 1,
// two faces straddling edge from vertex 2: // two faces straddling edge from vertex 2:
Tag::Body(11), Tag::Body(2), Tag::Body(6), 11, 2, 6,
Tag::Body(11), Tag::Body(5), Tag::Body(2), 11, 5, 2,
// two faces straddling edge from vertex 3: // two faces straddling edge from vertex 3:
Tag::Body(12), Tag::Body(3), Tag::Body(7), 12, 3, 7,
Tag::Body(12), Tag::Body(6), Tag::Body(3), 12, 6, 3,
// four faces from edge (0,1), (1,2), (2,3), (3,0): // four faces from edge (0,1, (1,2, (2,3, (3,0):
Tag::Body(9), Tag::Body(4), Tag::Body(10), 9, 4, 10,
Tag::Body(10), Tag::Body(5), Tag::Body(11), 10, 5, 11,
Tag::Body(11), Tag::Body(6), Tag::Body(12), 11, 6, 12,
Tag::Body(12), Tag::Body(7), Tag::Body(9), 12, 7, 9,
], ],
}), }),
final_geom: Rc::new(prim::empty_mesh()), final_geom: Rc::new(prim::empty_mesh()),
@ -772,13 +785,16 @@ pub fn ramhorn_branch(depth: usize, f: f32) -> Rule<RamHornCtxt> {
let next = incr.transform(&seed); let next = incr.transform(&seed);
let geom = Rc::new(OpenMesh { let geom = Rc::new(OpenMesh {
verts: next, verts: next,
alias_verts: vec![],
faces: util::parallel_zigzag_faces(4), faces: util::parallel_zigzag_faces(4),
// TODO: Fix this (parallel_zigzag_faces has parents)
}); });
let final_geom = Rc::new(OpenMesh { let final_geom = Rc::new(OpenMesh {
verts: vec![], verts: vec![],
alias_verts: vec![0, 1, 2, 3],
faces: vec![ faces: vec![
Tag::Parent(0), Tag::Parent(2), Tag::Parent(1), 0, 2, 1,
Tag::Parent(0), Tag::Parent(3), Tag::Parent(2), 0, 3, 2,
], ],
}); });
@ -807,24 +823,25 @@ pub fn ramhorn_branch(depth: usize, f: f32) -> Rule<RamHornCtxt> {
]; ];
let trans_faces = vec![ let trans_faces = vec![
// two faces straddling edge from vertex 0: // two faces straddling edge from vertex 0:
Tag::Parent(0), Tag::Body(0), Tag::Body(4), 0, 4, 8,
Tag::Parent(0), Tag::Body(7), Tag::Body(0), 0, 11, 4,
// two faces straddling edge from vertex 1: // two faces straddling edge from vertex 1:
Tag::Parent(1), Tag::Body(1), Tag::Body(5), 1, 5, 9,
Tag::Parent(1), Tag::Body(4), Tag::Body(1), 1, 8, 5,
// two faces straddling edge from vertex 2: // two faces straddling edge from vertex 2:
Tag::Parent(2), Tag::Body(2), Tag::Body(6), 2, 6, 10,
Tag::Parent(2), Tag::Body(5), Tag::Body(2), 2, 9, 6,
// two faces straddling edge from vertex 3: // two faces straddling edge from vertex 3:
Tag::Parent(3), Tag::Body(3), Tag::Body(7), 3, 7, 11,
Tag::Parent(3), Tag::Body(6), Tag::Body(3), 3, 10, 7,
// four faces from edge (0,1), (1,2), (2,3), (3,0): // four faces from edge (0,1), (1,2), (2,3), (3,0):
Tag::Parent(0), Tag::Body(4), Tag::Parent(1), 0, 8, 1,
Tag::Parent(1), Tag::Body(5), Tag::Parent(2), 1, 9, 2,
Tag::Parent(2), Tag::Body(6), Tag::Parent(3), 2, 10, 3,
Tag::Parent(3), Tag::Body(7), Tag::Parent(0), 3, 11, 0,
]; ];
let trans_geom = Rc::new(OpenMesh { let trans_geom = Rc::new(OpenMesh {
alias_verts: vec![0, 1, 2, 3],
verts: trans_verts.clone(), verts: trans_verts.clone(),
faces: trans_faces.clone(), faces: trans_faces.clone(),
}); });
@ -899,9 +916,10 @@ pub fn ramhorn_branch(depth: usize, f: f32) -> Rule<RamHornCtxt> {
RuleEval { RuleEval {
geom: Rc::new(OpenMesh { geom: Rc::new(OpenMesh {
verts: Transform::new().translate(0.0, 0.0, -0.5).transform(&seed), verts: Transform::new().translate(0.0, 0.0, -0.5).transform(&seed),
alias_verts: vec![],
faces: vec![ faces: vec![
Tag::Body(0), Tag::Body(1), Tag::Body(2), 0, 1, 2,
Tag::Body(0), Tag::Body(2), Tag::Body(3), 0, 2, 3,
], ],
}), }),
final_geom: Rc::new(prim::empty_mesh()), final_geom: Rc::new(prim::empty_mesh()),
@ -941,12 +959,15 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule<RamHornCtxt2> {
let geom = Rc::new(OpenMesh { let geom = Rc::new(OpenMesh {
verts: next, verts: next,
faces: util::parallel_zigzag_faces(4), faces: util::parallel_zigzag_faces(4),
alias_verts: vec![],
// TODO: Fix parents with parallel_zigzag
}); });
let final_geom = Rc::new(OpenMesh { let final_geom = Rc::new(OpenMesh {
verts: vec![], verts: vec![],
alias_verts: vec![0, 1, 2, 3],
faces: vec![ faces: vec![
Tag::Parent(0), Tag::Parent(2), Tag::Parent(1), 0, 2, 1,
Tag::Parent(0), Tag::Parent(3), Tag::Parent(2), 0, 3, 2,
], ],
}); });
@ -975,24 +996,25 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule<RamHornCtxt2> {
]; ];
let trans_faces = vec![ let trans_faces = vec![
// two faces straddling edge from vertex 0: // two faces straddling edge from vertex 0:
Tag::Parent(0), Tag::Body(0), Tag::Body(4), 0, 4, 8,
Tag::Parent(0), Tag::Body(7), Tag::Body(0), 0, 11, 4,
// two faces straddling edge from vertex 1: // two faces straddling edge from vertex 1:
Tag::Parent(1), Tag::Body(1), Tag::Body(5), 1, 5, 9,
Tag::Parent(1), Tag::Body(4), Tag::Body(1), 1, 8, 5,
// two faces straddling edge from vertex 2: // two faces straddling edge from vertex 2:
Tag::Parent(2), Tag::Body(2), Tag::Body(6), 2, 6, 10,
Tag::Parent(2), Tag::Body(5), Tag::Body(2), 2, 9, 6,
// two faces straddling edge from vertex 3: // two faces straddling edge from vertex 3:
Tag::Parent(3), Tag::Body(3), Tag::Body(7), 3, 7, 11,
Tag::Parent(3), Tag::Body(6), Tag::Body(3), 3, 10, 7,
// four faces from edge (0,1), (1,2), (2,3), (3,0): // four faces from edge (0,1), (1,2), (2,3), (3,0):
Tag::Parent(0), Tag::Body(4), Tag::Parent(1), 0, 8, 1,
Tag::Parent(1), Tag::Body(5), Tag::Parent(2), 1, 9, 2,
Tag::Parent(2), Tag::Body(6), Tag::Parent(3), 2, 10, 3,
Tag::Parent(3), Tag::Body(7), Tag::Parent(0), 3, 11, 0,
]; ];
let trans_geom = Rc::new(OpenMesh { let trans_geom = Rc::new(OpenMesh {
alias_verts: vec![0, 1, 2, 3],
verts: trans_verts.clone(), verts: trans_verts.clone(),
faces: trans_faces.clone(), faces: trans_faces.clone(),
}); });
@ -1068,9 +1090,10 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule<RamHornCtxt2> {
RuleEval { RuleEval {
geom: Rc::new(OpenMesh { geom: Rc::new(OpenMesh {
verts: Transform::new().translate(0.0, 0.0, -0.5).transform(&seed), verts: Transform::new().translate(0.0, 0.0, -0.5).transform(&seed),
alias_verts: vec![],
faces: vec![ faces: vec![
Tag::Body(0), Tag::Body(1), Tag::Body(2), 0, 1, 2,
Tag::Body(0), Tag::Body(2), Tag::Body(3), 0, 2, 3,
], ],
}), }),
final_geom: Rc::new(prim::empty_mesh()), final_geom: Rc::new(prim::empty_mesh()),
@ -1086,6 +1109,7 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule<RamHornCtxt2> {
Rule { eval: Rc::new(start), ctxt: RamHornCtxt2 { depth } } Rule { eval: Rc::new(start), ctxt: RamHornCtxt2 { depth } }
} }
*/
/* /*
#[derive(Copy, Clone)] #[derive(Copy, Clone)]

View File

@ -1,9 +1,10 @@
pub mod examples; pub mod mesh;
pub mod openmesh;
pub mod rule; pub mod rule;
pub mod prim; pub mod prim;
#[macro_use]
pub mod util; pub mod util;
pub mod xform; pub mod xform;
pub mod examples;
//pub use crate::examples; //pub use crate::examples;
//pub use crate::openmesh::test_thing; //pub use crate::openmesh::test_thing;
@ -63,6 +64,7 @@ mod tests {
geom.transform(&xf1).write_stl_file("xform_trans_rot.stl").unwrap(); geom.transform(&xf1).write_stl_file("xform_trans_rot.stl").unwrap();
} }
/*
// TODO: These tests don't test any conditions, so this is useful // TODO: These tests don't test any conditions, so this is useful
// short-hand to run, but not very meaningful as a test. // short-hand to run, but not very meaningful as a test.
#[test] #[test]
@ -127,6 +129,7 @@ mod tests {
fn ramhorn_branch_random() { fn ramhorn_branch_random() {
run_test(examples::ramhorn_branch_random(24, 0.25), 32, "ram_horn_branch_random", false); run_test(examples::ramhorn_branch_random(24, 0.25), 32, "ram_horn_branch_random", false);
} }
*/
} }
// need this for now: // need this for now:
// cargo test -- --nocapture // cargo test -- --nocapture

View File

@ -4,69 +4,18 @@ use std::borrow::Borrow;
use crate::xform::{Vertex, Transform}; use crate::xform::{Vertex, Transform};
/// A type for a 'tagged' vertex index referring either to an index of /// Basic face-vertex mesh. `faces` contains indices of `verts` and is
/// a mesh, or of its parent. /// taken in groups of 3 for each triangle.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Tag { pub struct Mesh {
Body(usize),
Parent(usize),
}
// TODO: This is clumsy. Can I do this some other way, or at least
// phrase it better?
/// A face-vertex mesh whose faces indices can refer either to its own
/// vertices, or to some 'parent' mesh.
#[derive(Clone, Debug)]
pub struct OpenMesh {
/// Vertices of mesh
pub verts: Vec<Vertex>, pub verts: Vec<Vertex>,
/// Indices of triangles (taken as every 3 values). `Tag::Body` pub faces: Vec<usize>,
/// indices correspond to `verts`, while `Tag::Parent` indices
/// correspond to some parent mesh that must eventually be given
/// to complete this mesh.
pub faces: Vec<Tag>,
} }
impl OpenMesh { impl Mesh {
/// Returns a new `Mesh` whose vertices have been transformed.
/// Appends any number of meshes together. Returns both a single pub fn transform(&self, xfm: &Transform) -> Mesh {
/// mesh, and a vector which gives the offset by which each Mesh {
/// corresponding input mesh was shifted. That is, for the i'th
/// index in `meshes`, all of its triangle indices were shifted by
/// the i'th offset in the resultant mesh.
pub fn append<T, U>(meshes: T) -> (OpenMesh, Vec<usize>)
where U: Borrow<OpenMesh>,
T: IntoIterator<Item = U>
{
let mut offsets: Vec<usize> = vec![];
let mut v: Vec<Vertex> = vec![];
let mut f: Vec<Tag> = vec![];
for mesh_ in meshes {
let mesh = mesh_.borrow();
// Position in 'verts' at which we're appending
// mesh.verts, which we need to know to shift indices:
let offset = v.len();
offsets.push(offset);
// Copy all vertices:
v.append(&mut mesh.verts.clone());
// Append its faces, applying offset:
f.extend(mesh.faces.iter().map(|t| {
match t {
Tag::Body(n) => Tag::Body(n + offset),
Tag::Parent(_) => panic!("Cannot append() if mesh has parent references!"),
// TODO: Handle the above
}
}));
}
(OpenMesh { verts: v, faces: f }, offsets)
}
/// Returns a new `OpenMesh` whose vertices have been transformed.
pub fn transform(&self, xfm: &Transform) -> OpenMesh {
OpenMesh {
verts: xfm.transform(&self.verts), verts: xfm.transform(&self.verts),
// TODO: Is the above faster if I pack vectors into a // TODO: Is the above faster if I pack vectors into a
// bigger matrix, and transform that? // bigger matrix, and transform that?
@ -91,19 +40,11 @@ impl OpenMesh {
vertices: [[0.0; 3]; 3], vertices: [[0.0; 3]; 3],
}; num_faces]; }; num_faces];
let get_vert = |j| {
match self.faces[j] {
Tag::Body(n) => self.verts[n].xyz(),
Tag::Parent(_) => panic!("Cannot write_stl() if mesh has parent references!"),
}
};
// TODO: Handle this behavior
// Turn every face into an stl_io::Triangle: // Turn every face into an stl_io::Triangle:
for i in 0..num_faces { for i in 0..num_faces {
let v0 = get_vert(3*i + 0); let v0 = self.verts[3*i + 0].xyz();
let v1 = get_vert(3*i + 1); let v1 = self.verts[3*i + 1].xyz();
let v2 = get_vert(3*i + 2); let v2 = self.verts[3*i + 2].xyz();
let normal = (v1-v0).cross(&(v2-v0)); let normal = (v1-v0).cross(&(v2-v0));
@ -121,6 +62,86 @@ impl OpenMesh {
stl_io::write_stl(writer, triangles.iter()) stl_io::write_stl(writer, triangles.iter())
} }
fn to_template(&self) -> MeshTemplate {
MeshTemplate {
faces: self.faces.clone(),
verts: self.verts.iter().map(|v| VertexUnion::Vertex(*v)).collect(),
}
}
}
#[derive(Clone, Debug)]
pub enum VertexUnion {
/// A concrete vertex
Vertex(Vertex),
/// An alias to some other vertex (by index)
Alias(usize),
}
/// A face-vertex mesh whose vertices can either be concrete values
/// (as in `Mesh`) or aliases (indices to other vertices of some
/// hypothetical mesh). This can be turned to `mesh` only if those
/// aliases are resolved to concrete vertices with a call like
/// `connect()`.
#[derive(Clone, Debug)]
pub struct MeshTemplate {
//
pub verts: Vec<VertexUnion>,
/// Indices of triangles (taken as every 3 values). Indices begin
/// with `alias_verts`, and then continue into `verts` - that is,
/// from `0..alias_verts.len()` they refer to `alias_verts`, and from
/// `alias_verts.len()..(alias_verts.len()+verts.len())` they refer to
/// `verts`.
pub faces: Vec<usize>,
}
impl MeshTemplate {
/// Returns a new `MeshTemplate` whose concrete vertices have
/// been transformed. Note that alias vertices are left untouched.
pub fn transform(&self, xfm: &Transform) -> MeshTemplate {
let v = self.verts.iter().map(|v| {
match v {
VertexUnion::Vertex(v) => VertexUnion::Vertex(xfm.mtx * v),
a@_ => a.clone(),
}
});
MeshTemplate {
verts: v.collect(),
faces: self.faces.clone(),
}
}
/// Appends any number of meshes together. Returns both a single
/// mesh, and a vector which gives the offset by which each
/// corresponding input mesh was shifted. That is, for the i'th
/// index in `meshes`, all of its triangle indices were shifted by
/// the i'th offset in the resultant mesh.
pub fn append<T, U>(meshes: T) -> (MeshTemplate, Vec<usize>)
where U: Borrow<MeshTemplate>,
T: IntoIterator<Item = U>
{
let mut offsets: Vec<usize> = vec![];
let mut v: Vec<VertexUnion> = vec![];
let mut f: Vec<usize> = vec![];
for mesh_ in meshes {
let mesh = mesh_.borrow();
// Position in 'verts' at which we're appending
// mesh.verts, which we need to know to shift indices:
let offset = v.len();
offsets.push(offset);
// Copy all vertices:
v.append(&mut mesh.verts.clone());
// Append its faces, applying offset:
f.extend(mesh.faces.iter().map(|n| n + offset));
}
(MeshTemplate { verts: v, faces: f }, offsets)
}
/// Treat this mesh as a 'parent' mesh to connect with any number /// Treat this mesh as a 'parent' mesh to connect with any number
/// of 'child' meshes, all of them paired with their respective /// of 'child' meshes, all of them paired with their respective
/// parent vertex mappings. This returns a tuple of (new mesh, /// parent vertex mappings. This returns a tuple of (new mesh,
@ -130,8 +151,8 @@ impl OpenMesh {
/// That is, the vertices of 'children[i]' begin at vertex /// That is, the vertices of 'children[i]' begin at vertex
/// 'offset[i]' of the new mesh. This is needed in some cases for /// 'offset[i]' of the new mesh. This is needed in some cases for
/// adjusting a parent vertex mapping, like 'vmap' of Rule::Child. /// adjusting a parent vertex mapping, like 'vmap' of Rule::Child.
pub fn connect<T, U>(&self, children: T) -> (OpenMesh, Vec<usize>) pub fn connect<T, U>(&self, children: T) -> (MeshTemplate, Vec<usize>)
where U: Borrow<OpenMesh>, where U: Borrow<MeshTemplate>,
T: IntoIterator<Item = (U, Vec<usize>)> T: IntoIterator<Item = (U, Vec<usize>)>
//pub fn connect(&self, children: &Vec<(OpenMesh, Vec<usize>)>) -> (OpenMesh, Vec<usize>) //pub fn connect(&self, children: &Vec<(OpenMesh, Vec<usize>)>) -> (OpenMesh, Vec<usize>)
{ {
@ -139,7 +160,7 @@ impl OpenMesh {
// TODO: Clean up Vec<usize> stuff // TODO: Clean up Vec<usize> stuff
// Copy body vertices & faces: // Copy body vertices & faces:
let mut verts: Vec<Vertex> = self.verts.clone(); let mut verts: Vec<VertexUnion> = self.verts.clone();
let mut faces = self.faces.clone(); let mut faces = self.faces.clone();
let mut offsets: Vec<usize> = vec![]; let mut offsets: Vec<usize> = vec![];
@ -148,29 +169,33 @@ impl OpenMesh {
let child = child_.borrow(); let child = child_.borrow();
// body_offset corresponds to the position in 'verts' at // offset corresponds to the position in 'verts' at
// which we're appending everything in 'child.verts' - // which we're appending everything in 'child.verts' -
// thus, the offset we shift all indices in 'children' by. // thus, the offset we shift all indices in 'children' by.
let body_offset = verts.len(); let offset = verts.len();
// Copy all vertices from 'child': // Concrete vertices in 'child.verts' need to be copied:
verts.append(&mut child.verts.clone()); verts.extend(child.verts.iter().filter_map(|v| {
match v {
// Append its faces: VertexUnion::Vertex(_) => Some(v.clone()),
faces.extend(child.faces.iter().map(|t| { VertexUnion::Alias(_) => None,
match t {
// Apply aforementioned shift to its body vertices:
Tag::Body(n) => Tag::Body(n + body_offset),
// Since 'self' vertices are in the same order,
// parent vertex references retain same index:
Tag::Parent(n) => Tag::Body(mapping[*n]),
} }
})); }));
offsets.push(body_offset); // All faces need copied, but if if the index was to
// a concrete vertex, then it needs shifted by 'offset';
// if an alias, it needs remapped.
faces.extend(child.faces.iter().map(|n|
match child.verts[*n] {
VertexUnion::Vertex(_) => n + offset,
VertexUnion::Alias(m) => mapping[m],
}
));
offsets.push(offset);
} }
let m = OpenMesh { let m = MeshTemplate {
verts: verts, verts: verts,
faces: faces, faces: faces,
}; };

View File

@ -1,17 +1,17 @@
use crate::openmesh::{OpenMesh, Tag}; use crate::mesh::{Mesh};
use crate::xform::{vertex, Transform}; use crate::xform::{vertex, Transform};
/// Returns an empty mesh (no vertices, no faces). /// Returns an empty mesh (no vertices, no faces).
pub fn empty_mesh() -> OpenMesh { pub fn empty_mesh() -> Mesh {
OpenMesh { Mesh {
verts: vec![], verts: vec![],
faces: vec![], faces: vec![],
} }
} }
/// Returns a cube of sidelength one centered at (0,0,0). /// Returns a cube of sidelength one centered at (0,0,0).
pub fn cube() -> OpenMesh { pub fn cube() -> Mesh {
OpenMesh { Mesh {
verts: vec![ verts: vec![
vertex(0.0, 0.0, 0.0), vertex(0.0, 0.0, 0.0),
vertex(1.0, 0.0, 0.0), vertex(1.0, 0.0, 0.0),
@ -23,18 +23,18 @@ pub fn cube() -> OpenMesh {
vertex(1.0, 1.0, 1.0), vertex(1.0, 1.0, 1.0),
], ],
faces: vec![ faces: vec![
Tag::Body(0), Tag::Body(3), Tag::Body(1), 0, 3, 1,
Tag::Body(0), Tag::Body(2), Tag::Body(3), 0, 2, 3,
Tag::Body(1), Tag::Body(7), Tag::Body(5), 1, 7, 5,
Tag::Body(1), Tag::Body(3), Tag::Body(7), 1, 3, 7,
Tag::Body(5), Tag::Body(6), Tag::Body(4), 5, 6, 4,
Tag::Body(5), Tag::Body(7), Tag::Body(6), 5, 7, 6,
Tag::Body(4), Tag::Body(2), Tag::Body(0), 4, 2, 0,
Tag::Body(4), Tag::Body(6), Tag::Body(2), 4, 6, 2,
Tag::Body(2), Tag::Body(7), Tag::Body(3), 2, 7, 3,
Tag::Body(2), Tag::Body(6), Tag::Body(7), 2, 6, 7,
Tag::Body(0), Tag::Body(1), Tag::Body(5), 0, 1, 5,
Tag::Body(0), Tag::Body(5), Tag::Body(4), 0, 5, 4,
], ],
}.transform(&Transform::new().translate(-0.5, -0.5, -0.5)) }.transform(&Transform::new().translate(-0.5, -0.5, -0.5))
} }

View File

@ -1,4 +1,4 @@
use crate::openmesh::{OpenMesh, Tag}; use crate::mesh::{MeshTemplate, VertexUnion};
use crate::xform::{Transform}; use crate::xform::{Transform};
//use crate::prim; //use crate::prim;
use std::borrow::Borrow; use std::borrow::Borrow;
@ -38,7 +38,7 @@ pub struct Rule<S> {
/// `geom`. /// `geom`.
pub struct RuleEval<S> { pub struct RuleEval<S> {
/// The geometry generated at just this iteration /// The geometry generated at just this iteration
pub geom: Rc<OpenMesh>, pub geom: Rc<MeshTemplate>,
/// The "final" geometry that is merged with `geom` via /// The "final" geometry that is merged with `geom` via
/// `connect()` in the event that recursion stops. This must be /// `connect()` in the event that recursion stops. This must be
@ -46,7 +46,7 @@ pub struct RuleEval<S> {
/// ///
/// Parent vertex references will be resolved directly to `geom` /// Parent vertex references will be resolved directly to `geom`
/// with no mapping. /// with no mapping.
pub final_geom: Rc<OpenMesh>, pub final_geom: Rc<MeshTemplate>,
/// The child invocations (used if recursion continues). The /// The child invocations (used if recursion continues). The
/// 'parent' mesh, from the perspective of all geometry produced /// 'parent' mesh, from the perspective of all geometry produced
@ -69,7 +69,7 @@ pub struct Child<S> {
/// The parent vertex mapping: a mapping to apply to turn a /// The parent vertex mapping: a mapping to apply to turn a
/// Tag::Parent vertex reference into a vertex index of the parent /// Tag::Parent vertex reference into a vertex index of the parent
/// mesh. That is, if `rule` produces an `OpenMesh` with a face /// mesh. That is, if `rule` produces a `MeshTemplate` with a face
/// of `Tag::Parent(n)`, this will correspond to index `vmap[n]` /// of `Tag::Parent(n)`, this will correspond to index `vmap[n]`
/// in the parent mesh. /// in the parent mesh.
pub vmap: Vec<usize>, pub vmap: Vec<usize>,
@ -80,7 +80,7 @@ impl<S> Rule<S> {
/// Convert this `Rule` to mesh data, recursively (depth first). /// Convert this `Rule` to mesh data, recursively (depth first).
/// `iters_left` sets the maximum recursion depth. This returns /// `iters_left` sets the maximum recursion depth. This returns
/// (geometry, number of rule evaluations). /// (geometry, number of rule evaluations).
pub fn to_mesh(s: Rc<Rule<S>>, iters_left: usize) -> (OpenMesh, usize) { pub fn to_mesh(s: Rc<Rule<S>>, iters_left: usize) -> (MeshTemplate, usize) {
let mut evals = 1; let mut evals = 1;
@ -95,7 +95,7 @@ impl<S> Rule<S> {
// TODO: This logic is more or less right, but it // TODO: This logic is more or less right, but it
// could perhaps use some un-tupling or something. // could perhaps use some un-tupling or something.
let subgeom: Vec<(OpenMesh, Vec<usize>)> = rs.children.iter().map(|sub| { let subgeom: Vec<(MeshTemplate, Vec<usize>)> = rs.children.iter().map(|sub| {
// Get sub-geometry (still un-transformed): // Get sub-geometry (still un-transformed):
let (submesh, eval) = Rule::to_mesh(sub.rule.clone(), iters_left - 1); let (submesh, eval) = Rule::to_mesh(sub.rule.clone(), iters_left - 1);
// Tally up eval count: // Tally up eval count:
@ -114,7 +114,7 @@ impl<S> Rule<S> {
/// This should be identical to to_mesh, but implemented /// This should be identical to to_mesh, but implemented
/// iteratively with an explicit stack rather than with recursive /// iteratively with an explicit stack rather than with recursive
/// function calls. /// function calls.
pub fn to_mesh_iter(s: Rc<Rule<S>>, max_depth: usize) -> (OpenMesh, usize) { pub fn to_mesh_iter(s: Rc<Rule<S>>, max_depth: usize) -> (MeshTemplate, usize) {
struct State<S> { struct State<S> {
// The set of rules we're currently handling: // The set of rules we're currently handling:
@ -185,14 +185,14 @@ impl<S> Rule<S> {
// actually need vmap. // actually need vmap.
let m = { let m = {
let mut m_ = 0; let mut m_ = 0;
for f in &final_geom.faces { for v in &final_geom.verts {
match f { match *v {
Tag::Parent(i) => { VertexUnion::Alias(a) => {
if *i > m_ { if a > m_ {
m_ = *i; m_ = a;
} }
} },
_ => {} VertexUnion::Vertex(_) => (),
} }
} }
m_ + 1 m_ + 1
@ -262,17 +262,17 @@ impl<S> Rule<S> {
} }
impl<S> RuleEval<S> { impl<S> RuleEval<S> {
/// Turn an iterator of (OpenMesh, Child) into a single RuleEval. /// Turn an iterator of (MeshTemplate, Child) into a single RuleEval.
/// All meshes are merged, and the `vmap` in each child has the /// All meshes are merged, and the `vmap` in each child has the
/// correct offsets applied to account for this merge. /// correct offsets applied to account for this merge.
/// ///
/// (`final_geom` is passed through to the RuleEval unmodified.) /// (`final_geom` is passed through to the RuleEval unmodified.)
pub fn from_pairs<T, U>(m: T, final_geom: OpenMesh) -> RuleEval<S> pub fn from_pairs<T, U>(m: T, final_geom: MeshTemplate) -> RuleEval<S>
where U: Borrow<OpenMesh>, where U: Borrow<MeshTemplate>,
T: IntoIterator<Item = (U, Child<S>)> T: IntoIterator<Item = (U, Child<S>)>
{ {
let (meshes, children): (Vec<_>, Vec<_>) = m.into_iter().unzip(); let (meshes, children): (Vec<_>, Vec<_>) = m.into_iter().unzip();
let (mesh, offsets) = OpenMesh::append(meshes); let (mesh, offsets) = MeshTemplate::append(meshes);
// Patch up vmap in each child, and copy everything else: // Patch up vmap in each child, and copy everything else:
let children2: Vec<Child<S>> = children.iter().zip(offsets.iter()).map(|(c,off)| { let children2: Vec<Child<S>> = children.iter().zip(offsets.iter()).map(|(c,off)| {

View File

@ -1,7 +1,24 @@
use crate::openmesh::{Tag, OpenMesh}; use std::ops::Range;
use crate::mesh::{Mesh, MeshTemplate, VertexUnion};
use crate::xform::{Vertex}; use crate::xform::{Vertex};
//use crate::rule::{Rule, Child}; //use crate::rule::{Rule, Child};
/// This is like `vec!`, but it can handle elements that are given
/// with `@var: element` rather than `element`, e.g. like
/// `vec_indexed![foo, bar, @a: baz, quux]`. The variable (which must
/// already be declared and a `usize`) is then assigned the index of the
/// element it precedes. This can be used any number of times with
/// different elements and indices.
#[macro_export]
macro_rules! vec_indexed {
// Thank you to GhostOfSteveJobs and Rantanen in the Rust discord.
($( $(@ $Index:ident :)? $Value:expr,)*) => {{
let mut v = Vec::new();
$( $($Index = v.len();)? v.push($Value); )*
v
}};
}
/// Linearly subdivides a list of points that are to be treated as a /// Linearly subdivides a list of points that are to be treated as a
/// cycle. This produces 'count' points for every element of 'p' /// cycle. This produces 'count' points for every element of 'p'
/// (thus, the returned length will be `count*p.len()`). /// (thus, the returned length will be `count*p.len()`).
@ -21,45 +38,57 @@ pub fn subdivide_cycle(p: &Vec<Vertex>, count: usize) -> Vec<Vertex> {
// TODO: This can be generalized to an iterator or to IntoIterator // TODO: This can be generalized to an iterator or to IntoIterator
// trait bound // trait bound
pub fn parallel_zigzag_faces(count: usize) -> Vec<Tag> { pub fn parallel_zigzag_faces(r1: Range<usize>, r2: Range<usize>) -> Vec<usize> {
let count = r1.end - r1.start;
if (r2.end - r2.start) != count {
panic!("Ranges must have the same size");
}
if (r2.end > r1.start && r2.end < r1.end) ||
(r1.end > r2.start && r1.end < r2.end) {
panic!("Ranges cannot overlap");
}
(0..count).map(|i0| { (0..count).map(|i0| {
let i1 = (i0+1) % count; // i0 is an *offset* for the 'current' index.
// i1 is for the 'next' index, wrapping back to 0.
let i1 = (i0 + 1) % count;
vec![ vec![
Tag::Body(i1), Tag::Parent(i0), Tag::Body(i0), // Mind winding order!
Tag::Parent(i1), Tag::Parent(i0), Tag::Body(i1), r1.start + i1, r2.start + i0, r1.start + i0,
r2.start + i1, r2.start + i0, r1.start + i1,
] ]
}).flatten().collect() }).flatten().collect()
} }
pub fn zigzag_to_parent(verts: Vec<Vertex>, count: usize) -> OpenMesh { pub fn zigzag_to_parent(verts: Vec<VertexUnion>, main: Range<usize>, parent: Range<usize>) -> MeshTemplate {
OpenMesh { MeshTemplate {
verts: verts, verts: verts,
faces: parallel_zigzag_faces(count), faces: parallel_zigzag_faces(main, parent),
} }
} }
pub fn connect_convex(verts: &Vec<Vertex>, as_parent: bool) -> (Vertex, Vec<Tag>) { pub fn centroid(verts: &Vec<Vertex>) -> Vertex {
let n = verts.len(); let n = verts.len();
let mut centroid = Vertex::new(0.0, 0.0, 0.0, 0.0); let mut centroid = Vertex::new(0.0, 0.0, 0.0, 0.0);
for v in verts { for v in verts {
centroid += v; centroid += v;
} }
centroid /= n as f32; centroid /= n as f32;
centroid
let faces: Vec<Tag> = { }
if as_parent {
(0..n).map(|f1| { pub fn connect_convex(range: Range<usize>, target: usize, as_parent: bool) -> Vec<usize> {
let f2 = (f1 + 1) % n;
vec![Tag::Parent(f2), Tag::Parent(f1), Tag::Body(0)] let count = range.end - range.start;
}).flatten().collect() if as_parent {
} else { (0..count).map(|i0| {
(0..n).map(|f1| { let i1 = (i0 + 1) % count;
let f2 = (f1 + 1) % n; vec![range.start + i1, range.start + i0, target]
// n is used for new center vertex }).flatten().collect()
vec![Tag::Body(f1), Tag::Body(f2), Tag::Body(n)] } else {
}).flatten().collect() (0..count).map(|i0| {
} let i1 = (i0 + 1) % count;
}; vec![range.start + i0, range.start + i1, target]
}).flatten().collect()
(centroid, faces) }
} }