From c5945386444d16e69ea3971ec1f5a2a9dc8f6889 Mon Sep 17 00:00:00 2001 From: Chris Hodapp Date: Sat, 22 Feb 2020 08:26:27 -0500 Subject: [PATCH] Fixed ram_horn example, slight refactor on to_mesh --- README.md | 12 ++++++------ src/examples.rs | 28 ++++++++++++++-------------- src/openmesh.rs | 3 ++- src/rule.rs | 29 +++++++++++++++++------------ 4 files changed, 39 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 1c8ec62..d0165f4 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,15 @@ ## Highest priority: -- See `ram_horn_*` and `curve_horn_*` TODOs: these are both solved by - some sort of parent-vertex-mapping layer. The only other way around - this that I need is to require that rule functions exist in - explictly separate forms. -- Consider trampolining `to_mesh`. My call stack seems needlessly - deep in spots. Can I make tail-recursive? +- Clean up my 'parent vertex mapping' thingy, *and* come up with + meaningful terms to discuss it. +- Do transforms compose in the *reverse* of automata_scratch? This + appears to be the case. ## Important but less critical: +- Consider trampolining `to_mesh`. My call stack seems needlessly + deep in spots. Can I make tail-recursive? - Grep for all TODOs in code, really. - Look at everything in README.md in automata_scratch. - Implement some of the tougher examples from the above too, e.g. the diff --git a/src/examples.rs b/src/examples.rs index 08801c2..7ecf35a 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -119,11 +119,11 @@ fn cube_thing_rule() -> RuleStep { // Conversion from Python & automata_scratch fn ram_horn_start() -> RuleStep { let opening_xform = |i| { - (geometry::Translation3::new(0.0, 0.0, -1.0).to_homogeneous() * - Matrix4::new_scaling(0.5) * + ((geometry::Rotation3::from_axis_angle( + &nalgebra::Vector3::z_axis(), i).to_homogeneous()) * geometry::Translation3::new(0.25, 0.25, 1.0).to_homogeneous() * - geometry::Rotation3::from_axis_angle( - &nalgebra::Vector3::z_axis(), i).to_homogeneous()) + Matrix4::new_scaling(0.5) * + geometry::Translation3::new(0.0, 0.0, -1.0).to_homogeneous()) }; RuleStep { geom: OpenMesh { @@ -171,19 +171,21 @@ fn ram_horn_start() -> RuleStep { }, final_geom: prim::empty_mesh(), children: vec![ - (Rule::Recurse(ram_horn), opening_xform(0.0), vec![0,4,8,7]), - (Rule::Recurse(ram_horn), opening_xform(std::f32::consts::FRAC_PI_2), vec![1,5,8,4]), - (Rule::Recurse(ram_horn), opening_xform(std::f32::consts::FRAC_PI_2*2.0), vec![2,6,8,5]), - (Rule::Recurse(ram_horn), opening_xform(std::f32::consts::FRAC_PI_2*3.0), vec![3,7,8,6]), + (Rule::Recurse(ram_horn), opening_xform(0.0), vec![5,2,6,8]), + (Rule::Recurse(ram_horn), opening_xform(std::f32::consts::FRAC_PI_2), vec![4,1,5,8]), + (Rule::Recurse(ram_horn), opening_xform(std::f32::consts::FRAC_PI_2*2.0), vec![7,0,4,8]), + (Rule::Recurse(ram_horn), opening_xform(std::f32::consts::FRAC_PI_2*3.0), vec![6,3,7,8]), + // TODO: These vertex mappings appear to be right. + // Understand *why* they are right. ], } } fn ram_horn() -> RuleStep { let v = Unit::new_normalize(Vector3::new(-1.0, 0.0, 1.0)); - let incr: Mat4 = Matrix4::new_scaling(0.9) * + let incr: Mat4 = geometry::Translation3::new(0.0, 0.0, 0.8).to_homogeneous() * geometry::Rotation3::from_axis_angle(&v, 0.3).to_homogeneous() * - geometry::Translation3::new(0.0, 0.0, 0.8).to_homogeneous(); + Matrix4::new_scaling(0.9); let seed = vec![ vertex(-0.5, -0.5, 1.0), vertex(-0.5, 0.5, 1.0), @@ -202,10 +204,6 @@ fn ram_horn() -> RuleStep { Tag::Parent(3), Tag::Parent(2), Tag::Body(3), Tag::Body(0), Tag::Parent(3), Tag::Body(3), Tag::Parent(0), Tag::Parent(3), Tag::Body(0), - // TODO: These are correct once the recursion is already - // going - but they are wrong at the start! Note how I'm - // never using the 'midpoint' vertex from the parent, - // Tag::Parent(8). ], }; let final_geom = OpenMesh { @@ -238,6 +236,8 @@ pub fn main() { }; run_test(Rule::Recurse(cube_thing_rule), 3, "cube_thing"); + // this can't work on its own because the resultant OpenMesh still + // has parent references: //run_test(Rule::Recurse(curve_horn_thing_rule), 100, "curve_horn_thing"); run_test(Rule::Recurse(curve_horn_start), 100, "curve_horn2"); run_test(Rule::Recurse(ram_horn_start), 200, "ram_horn"); diff --git a/src/openmesh.rs b/src/openmesh.rs index 1cdf47f..cd53b29 100644 --- a/src/openmesh.rs +++ b/src/openmesh.rs @@ -84,7 +84,8 @@ impl OpenMesh { stl_io::write_stl(writer, triangles.iter()) } - pub fn connect(&self, others: &Vec<(OpenMesh, Vec)>) -> OpenMesh { + pub fn connect(&self, others: &Vec<(OpenMesh, &Vec)>) -> OpenMesh { + // TODO: Clean up Vec stuff // Copy body vertices & faces: let mut verts: Vec = self.verts.clone(); diff --git a/src/rule.rs b/src/rule.rs index 4e11cff..ec0b725 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -26,6 +26,9 @@ pub struct RuleStep { // Child rules, paired with the transform that will be applied to // all of their geometry and parent vertex mappings pub children: Vec<(Rule, Mat4, Vec)>, + // TODO: Clean this up, perhaps change the tuple to something + // saner. + // TODO: Also, document & rename this more clearly. } impl Rule { @@ -57,21 +60,23 @@ impl Rule { match self { Rule::Recurse(f) => { let rs: RuleStep = f(); + // TODO: This logic is more or less right, but it + // could perhaps use some un-tupling or something. - // Get sub-geometry (from child rules) and transform it: - let subgeom: Vec<(OpenMesh, Mat4, u32, Vec)> = rs.children.iter().map(|(subrule, subxform, mapping)| { - let (m,n) = subrule.to_mesh(iters_left - 1); - (m, *subxform, n, mapping.clone()) - }).collect(); - - // Tally up node count: - subgeom.iter().for_each(|(_,_,n,_)| nodes += n); - - let g: Vec<(OpenMesh, Vec)> = subgeom.iter().map(|(m,x,_,mv)| (m.transform(*x), mv.clone())).collect(); - // TODO: Not clone twice + let subgeom: Vec<(OpenMesh, &Vec)> = rs.children.iter().map( + |(subrule, subxform, vmap)| { + // Get sub-geometry (still un-transformed): + let (submesh,n) = subrule.to_mesh(iters_left - 1); + // Tally up node count: + nodes += n; + + let m2 = submesh.transform(*subxform); + + (m2, vmap) + }).collect(); // Connect geometry from this rule (not child rules): - return (rs.geom.connect(&g), nodes); + return (rs.geom.connect(&subgeom), nodes); } Rule::EmptyRule => { return (prim::empty_mesh(), nodes);