From 4df6b8442cb058e691f099ceb0a6886e989c79b4 Mon Sep 17 00:00:00 2001 From: hodapp Date: Tue, 10 Mar 2020 21:25:50 -0400 Subject: [PATCH] Add (non-building) attempt at using closures again --- src/examples.rs | 72 +++++++++++++++++++++++++++---------------------- src/rule.rs | 32 +++++++++++----------- 2 files changed, 56 insertions(+), 48 deletions(-) diff --git a/src/examples.rs b/src/examples.rs index 9b80176..6b7ec1a 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -6,6 +6,12 @@ use crate::rule::{Rule, RuleEval, Child}; use crate::prim; use crate::util; +fn recurRule RuleEval>(f: A) -> Rule { + Rule { + eval: Box::new(f), + } +} + struct CurveHorn { seed: Vec, id_xform: Mat4, @@ -15,7 +21,7 @@ struct CurveHorn { impl CurveHorn { - fn init() -> (CurveHorn, Rule) { + fn init() -> Rule { let y = &Vector3::y_axis(); let c = CurveHorn { seed: vec![ @@ -32,10 +38,10 @@ impl CurveHorn { Matrix4::new_scaling(0.95) * geometry::Translation3::new(0.0, 0.0, 0.2).to_homogeneous(), }; - (c, Rule { eval: Self::start }) + recurRule(|| c.start()) } - fn start(&self) -> RuleEval { + fn start(&self) -> RuleEval { RuleEval { geom: OpenMesh { verts: self.seed.clone(), @@ -44,12 +50,12 @@ impl CurveHorn { final_geom: prim::empty_mesh(), children: vec![ Child { - rule: Rule { eval: Self::recur }, + rule: recurRule(|| self.recur()), xf: self.id_xform, vmap: vec![0,1,2,3], }, Child { - rule: Rule { eval: Self::recur }, + rule: recurRule(|| self.recur()), xf: self.flip180, vmap: vec![3,2,1,0], }, @@ -57,7 +63,7 @@ impl CurveHorn { } } - fn recur(&self) -> RuleEval { + fn recur(&self) -> RuleEval { let verts = self.seed.clone(); let next_verts: Vec = transform(&verts, &self.incr); @@ -95,7 +101,7 @@ impl CurveHorn { final_geom: final_geom, children: vec![ Child { - rule: Rule { eval: Self::recur }, + rule: recurRule(|| self.recur()), xf: self.incr, vmap: vec![0,1,2,3], }, @@ -109,11 +115,12 @@ struct CubeThing { impl CubeThing { - fn init() -> (CubeThing, Rule) { - (CubeThing {}, Rule { eval: Self::rec }) + fn init() -> Rule { + let c = CubeThing {}; + recurRule(|| c.rec()) } - fn rec(&self) -> RuleEval { + fn rec(&self) -> RuleEval { let mesh = prim::cube(); @@ -133,12 +140,12 @@ impl CubeThing { geometry::Rotation3::from_axis_angle(z, -qtr).to_homogeneous(), ]; - let gen_rulestep = |rot: &Mat4| -> Child { + let gen_rulestep = |rot: &Mat4| -> Child { let m: Mat4 = rot * Matrix4::new_scaling(0.5) * geometry::Translation3::new(6.0, 0.0, 0.0).to_homogeneous(); Child { - rule: Rule { eval: Self::rec }, + rule: recurRule(|| self.rec()), xf: m, vmap: vec![], } @@ -157,12 +164,13 @@ struct RamHorn { impl RamHorn { - fn init() -> (RamHorn, Rule) { - (RamHorn{}, Rule { eval: Self::start }) + fn init() -> Rule { + let r = RamHorn{}; + recurRule(|| r.start()) } // Conversion from Python & automata_scratch - fn start(&self) -> RuleEval { + fn start(&self) -> RuleEval { let opening_xform = |i| { let r = std::f32::consts::FRAC_PI_2 * i; ((geometry::Rotation3::from_axis_angle( @@ -218,22 +226,22 @@ impl RamHorn { final_geom: prim::empty_mesh(), children: vec![ Child { - rule: Rule { eval: Self::ram_horn }, + rule: recurRule(|| self.ram_horn()), xf: opening_xform(0.0), vmap: vec![5,2,6,8], }, Child { - rule: Rule { eval: Self::ram_horn }, + rule: recurRule(|| self.ram_horn()), xf: opening_xform(1.0), vmap: vec![4,1,5,8], }, Child { - rule: Rule { eval: Self::ram_horn }, + rule: recurRule(|| self.ram_horn()), xf: opening_xform(2.0), vmap: vec![7,0,4,8], }, Child { - rule: Rule { eval: Self::ram_horn }, + rule: recurRule(|| self.ram_horn()), xf: opening_xform(3.0), vmap: vec![6,3,7,8], }, @@ -243,7 +251,7 @@ impl RamHorn { } } - fn ram_horn(&self) -> RuleEval { + fn ram_horn(&self) -> RuleEval { let v = Unit::new_normalize(Vector3::new(-1.0, 0.0, 1.0)); let incr: Mat4 = geometry::Translation3::new(0.0, 0.0, 0.8).to_homogeneous() * geometry::Rotation3::from_axis_angle(&v, 0.3).to_homogeneous() * @@ -280,7 +288,7 @@ impl RamHorn { final_geom: final_geom, children: vec![ Child { - rule: Rule { eval: Self::ram_horn }, + rule: recurRule(|| self.ram_horn()), xf: incr, vmap: vec![0,1,2,3], }, @@ -301,7 +309,7 @@ struct Twist { impl Twist { - pub fn init(f: f32, subdiv: usize) -> (Twist, Rule) { + pub fn init(f: f32, subdiv: usize) -> Rule { let xf = geometry::Rotation3::from_axis_angle(&Vector3::x_axis(), -0.7).to_homogeneous(); let seed = transform(&vec![ vertex(-0.5, 0.0, -0.5), @@ -319,11 +327,11 @@ impl Twist { seed_sub: seed_sub, subdiv: subdiv, }; - (t, Rule { eval: Self::start }) + recurRule(|| t.start()) } // Meant to be a copy of twist_from_gen from Python & automata_scratch - pub fn start(&self) -> RuleEval { + pub fn start(&self) -> RuleEval { let n = self.seed_sub.len(); @@ -337,10 +345,10 @@ impl Twist { // First generate 'count' children, each one shifted/rotated // differently: - let children: Vec> = (0..self.count).map(|i| { + let children: Vec = (0..self.count).map(|i| { let xf = xform(i); Child { - rule: Rule { eval: Self::recur }, + rule: recurRule(|| self.recur()), xf: xf, vmap: ((n+1)*i..(n+1)*(i+self.count)).collect(), // N.B. // note n+1, not n. the +1 is for the centroid below @@ -364,7 +372,7 @@ impl Twist { } } - pub fn recur(&self) -> RuleEval { + pub fn recur(&self) -> RuleEval { let y = &Vector3::y_axis(); let incr = geometry::Translation3::new(-self.dx0, 0.0, 0.0).to_homogeneous() * geometry::Rotation3::from_axis_angle(y, self.ang).to_homogeneous() * @@ -384,7 +392,7 @@ impl Twist { final_geom: OpenMesh { verts: vec![vc], faces }, children: vec![ Child { - rule: Rule { eval: Self::recur }, + rule: recurRule(|| self.recur()), xf: incr, vmap: (0..n).collect(), }, @@ -407,18 +415,18 @@ pub fn main() { println!("vs2={:?}", vs2); } - fn run_test((a, r): (A, Rule), iters: u32, name: &str) { + fn run_test(r: Rule, iters: u32, name: &str) { println!("Running {}...", name); - let (mesh, nodes) = r.to_mesh(&a, iters); + let (mesh, nodes) = r.to_mesh(iters); println!("Evaluated {} rules", nodes); let fname = format!("{}.stl", name); println!("Writing {}...", fname); mesh.write_stl_file(&fname).unwrap(); } - fn run_test_iter((a, r): (A, Rule), iters: usize, name: &str) { + fn run_test_iter(r: Rule, iters: usize, name: &str) { println!("Running {}...", name); - let (mesh, nodes) = r.to_mesh_iter(&a, iters); + let (mesh, nodes) = r.to_mesh_iter(iters); println!("Evaluated {} rules", nodes); let fname = format!("{}.stl", name); println!("Writing {}...", fname); diff --git a/src/rule.rs b/src/rule.rs index 7088ac7..e814316 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -6,8 +6,8 @@ use crate::openmesh::{OpenMesh, Tag, Mat4}; /// - produces geometry when it is evaluated /// - tells what other rules to invoke, and what to do with their /// geometry -pub struct Rule { - pub eval: fn (&A) -> RuleEval, +pub struct Rule { + pub eval: Box RuleEval>, } // TODO: It may be possible to have just a 'static' rule that requires // no function call. @@ -24,7 +24,7 @@ pub struct Rule { /// - if recursion continues, the rules of `children` are evaluated, /// and the resultant geometry is transformed and then connected with /// `geom`. -pub struct RuleEval { +pub struct RuleEval { /// The geometry generated at just this iteration pub geom: OpenMesh, @@ -39,16 +39,16 @@ pub struct RuleEval { /// The child invocations (used if recursion continues). The /// 'parent' mesh, from the perspective of all geometry produced /// by `children`, is `geom`. - pub children: Vec>, + pub children: Vec, } /// `Child` evaluations, pairing another `Rule` with the /// transformations and parent vertex mappings that should be applied /// to it. -pub struct Child { +pub struct Child { /// Rule to evaluate to produce geometry - pub rule: Rule, + pub rule: Rule, /// The transform to apply to all geometry produced by `rule` /// (including its own `geom` and `final_geom` if needed, as well @@ -63,7 +63,7 @@ pub struct Child { pub vmap: Vec, } -impl Rule { +impl Rule { // TODO: Do I want to make 'geom' shared somehow, maybe with Rc? I // could end up having a lot of identical geometry that need not be @@ -76,11 +76,11 @@ impl Rule { /// Convert this `Rule` to mesh data, recursively (depth first). /// `iters_left` sets the maximum recursion depth. This returns /// (geometry, number of rule evaluations). - pub fn to_mesh(&self, arg: &A, iters_left: u32) -> (OpenMesh, usize) { + pub fn to_mesh(&self, iters_left: u32) -> (OpenMesh, usize) { let mut evals = 1; - let rs: RuleEval = (self.eval)(arg); + let rs: RuleEval = (self.eval)(); if iters_left <= 0 { return (rs.final_geom, 1); // TODO: This is probably wrong because of the way that @@ -93,7 +93,7 @@ impl Rule { let subgeom: Vec<(OpenMesh, &Vec)> = rs.children.iter().map(|sub| { // Get sub-geometry (still un-transformed): - let (submesh, eval) = sub.rule.to_mesh(arg, iters_left - 1); + let (submesh, eval) = sub.rule.to_mesh(iters_left - 1); // Tally up eval count: evals += eval; @@ -109,11 +109,11 @@ impl Rule { /// This should be identical to to_mesh, but implemented /// iteratively with an explicit stack rather than with recursive /// function calls. - pub fn to_mesh_iter(&self, arg: &A, max_depth: usize) -> (OpenMesh, usize) { + pub fn to_mesh_iter(&self, max_depth: usize) -> (OpenMesh, usize) { - struct State { + struct State { // The set of rules we're currently handling: - rules: Vec>, + rules: Vec, // The next element of 'children' to handle: next: usize, // World transform of the *parent* of 'rules', that is, @@ -130,8 +130,8 @@ impl Rule { // (usually because they involve multiple rules). // // We evaluate our own rule to initialize the stack: - let eval = (self.eval)(arg); - let mut stack: Vec> = vec![State { + let eval = (self.eval)(); + let mut stack: Vec = vec![State { rules: eval.children, next: 0, xf: nalgebra::geometry::Transform3::identity().to_homogeneous(), @@ -159,7 +159,7 @@ impl Rule { // Evaluate the rule: let child = &s.rules[s.next]; - let mut eval = (child.rule.eval)(arg); + let mut eval = (child.rule.eval)(); eval_count += 1; // Make an updated world transform: