From 05a0aed8eb4f648ab49756fd739eccd028960dcc Mon Sep 17 00:00:00 2001 From: Chris Hodapp Date: Sun, 5 Apr 2020 00:00:29 -0400 Subject: [PATCH] Rule now has, again, a type param --- src/examples.rs | 38 +++++++++++++++++++------------------- src/rule.rs | 38 ++++++++++++++++++++------------------ 2 files changed, 39 insertions(+), 37 deletions(-) diff --git a/src/examples.rs b/src/examples.rs index 9bff6db..1279061 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -10,7 +10,7 @@ use crate::util; use std::time::Instant; -fn cube_thing() -> Rule { +fn cube_thing() -> Rule<()> { // Quarter-turn in radians: let qtr = std::f32::consts::FRAC_PI_2; @@ -29,7 +29,7 @@ fn cube_thing() -> Rule { id.rotate(z, -qtr), ]; - let rec = move |self_: Rc| -> RuleEval { + let rec = move |self_: Rc>| -> RuleEval<()> { let xforms = turns.iter().map(|xf| xf.scale(0.5).translate(6.0, 0.0, 0.0)); RuleEval { @@ -43,11 +43,11 @@ fn cube_thing() -> Rule { } }; - Rule { eval: Box::new(rec) } + Rule { eval: Box::new(rec), ctxt: () } } // Meant to be a copy of twist_from_gen from Python & automata_scratch -fn twist(f: f32, subdiv: usize) -> Rule { +fn twist(f: f32, subdiv: usize) -> Rule<()> { // TODO: Clean this code up. It was a very naive conversion from // the non-closure version. let xf = Transform::new().rotate(&Vector3::x_axis(), -0.7); @@ -73,7 +73,7 @@ fn twist(f: f32, subdiv: usize) -> Rule { let seed2 = seed.clone(); // TODO: Why do I need the above? - let recur = move |incr: Transform| -> RuleFn { + let recur = move |incr: Transform| -> RuleFn<()> { let seed_next = incr.transform(&seed2); @@ -85,7 +85,7 @@ fn twist(f: f32, subdiv: usize) -> Rule { faces: faces, }); - let c = move |self_: Rc| -> RuleEval { + let c = move |self_: Rc>| -> RuleEval<()> { RuleEval { geom: geom.clone(), final_geom: final_geom.clone(), @@ -103,15 +103,15 @@ fn twist(f: f32, subdiv: usize) -> Rule { // TODO: Can a macro do anything to clean up some of the // repetition with HOFs & closures? - let start = move |_| -> RuleEval { + let start = move |_| -> RuleEval<()> { - let child = |incr, dx, i, ang0, div| -> (OpenMesh, Child) { + let child = |incr, dx, i, ang0, div| -> (OpenMesh, Child<()>) { let xform = Transform::new(). rotate(&y, ang0 + (qtr / div * (i as f32))). translate(dx, 0.0, 0.0); let c = Child { - rule: Rc::new(Rule { eval: (recur.clone())(incr) }), + rule: Rc::new(Rule { eval: (recur.clone())(incr), ctxt: () }), // TODO: Cleanliness fix - can macros clean up above? xf: xform, vmap: (0..(n+1)).collect(), @@ -131,10 +131,10 @@ fn twist(f: f32, subdiv: usize) -> Rule { RuleEval::from_pairs(inner.chain(outer), prim::empty_mesh()) }; - Rule { eval: Box::new(start) } + Rule { eval: Box::new(start), ctxt: () } } -fn ramhorn() -> Rule { +fn ramhorn() -> Rule<()> { let v = Unit::new_normalize(Vector3::new(-1.0, 0.0, 1.0)); let incr: Transform = Transform::new(). @@ -170,7 +170,7 @@ fn ramhorn() -> Rule { ], }); - let recur = move |self_: Rc| -> RuleEval { + let recur = move |self_: Rc>| -> RuleEval<()> { RuleEval { geom: geom.clone(), final_geom: final_geom.clone(), @@ -193,7 +193,7 @@ fn ramhorn() -> Rule { translate(0.0, 0.0, -1.0) }; - let start = move |_| -> RuleEval { + let start = move |_| -> RuleEval<()> { //let ofn = opening_xform.clone(); @@ -244,22 +244,22 @@ fn ramhorn() -> Rule { final_geom: Rc::new(prim::empty_mesh()), children: vec![ Child { - rule: Rc::new(Rule { eval: Box::new(recur.clone()) }), + rule: Rc::new(Rule { eval: Box::new(recur.clone()), ctxt: () }), xf: opening_xform(0.0), vmap: vec![5,2,6,8], }, Child { - rule: Rc::new(Rule { eval: Box::new(recur.clone()) }), + rule: Rc::new(Rule { eval: Box::new(recur.clone()), ctxt: () }), xf: opening_xform(1.0), vmap: vec![4,1,5,8], }, Child { - rule: Rc::new(Rule { eval: Box::new(recur.clone()) }), + rule: Rc::new(Rule { eval: Box::new(recur.clone()), ctxt: () }), xf: opening_xform(2.0), vmap: vec![7,0,4,8], }, Child { - rule: Rc::new(Rule { eval: Box::new(recur.clone()) }), + rule: Rc::new(Rule { eval: Box::new(recur.clone()), ctxt: () }), xf: opening_xform(3.0), vmap: vec![6,3,7,8], }, @@ -272,7 +272,7 @@ fn ramhorn() -> Rule { } }; - Rule { eval: Box::new(start) } + Rule { eval: Box::new(start), ctxt: () } } /* @@ -429,7 +429,7 @@ pub fn main() { } */ - fn run_test_iter(r: &Rc, iters: usize, name: &str) { + fn run_test_iter(r: &Rc>, iters: usize, name: &str) { println!("Running {}...", name); let start = Instant::now(); let n = 5; diff --git a/src/rule.rs b/src/rule.rs index 2adf93f..52f402e 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -4,16 +4,18 @@ use crate::xform::{Transform}; use std::borrow::Borrow; use std::rc::Rc; -pub type RuleFn = Box) -> RuleEval>; +pub type RuleFn = Box>) -> RuleEval>; /// Definition of a rule. In general, a `Rule`: /// /// - produces geometry when it is evaluated /// - tells what other rules to invoke, and what to do with their /// geometry -pub struct Rule { - pub eval: RuleFn, +pub struct Rule { + pub eval: RuleFn, + pub ctxt: S, } + // TODO: It may be possible to have just a 'static' rule that requires // no function call. // TODO: Do I benefit with Rc below so Rule can be shared? @@ -34,7 +36,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: Rc, @@ -49,16 +51,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: Rc, + pub rule: Rc>, /// The transform to apply to all geometry produced by `rule` /// (including its own `geom` and `final_geom` if needed, as well @@ -73,7 +75,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 @@ -86,11 +88,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(s: Rc, iters_left: u32) -> (OpenMesh, usize) { + pub fn to_mesh(s: Rc>, iters_left: u32) -> (OpenMesh, usize) { let mut evals = 1; - let rs: RuleEval = (s.eval)(s.clone()); + let rs: RuleEval = (s.eval)(s.clone()); if iters_left <= 0 { return ((*rs.final_geom).clone(), 1); // TODO: This is probably wrong because of the way that @@ -120,11 +122,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(s: Rc, max_depth: usize) -> (OpenMesh, usize) { + pub fn to_mesh_iter(s: Rc>, 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, @@ -142,7 +144,7 @@ impl Rule { // // We evaluate our own rule to initialize the stack: let eval = (s.eval)(s.clone()); - let mut stack: Vec = vec![State { + let mut stack: Vec> = vec![State { rules: eval.children, next: 0, xf: Transform::new(), @@ -259,21 +261,21 @@ impl Rule { } -impl RuleEval { +impl RuleEval { /// Turn an iterator of (OpenMesh, Child) into a single RuleEval. /// All meshes are merged, and the `vmap` in each child has the /// correct offsets applied to account for this merge. /// /// (`final_geom` is passed through to the RuleEval unmodified.) - pub fn from_pairs(m: T, final_geom: OpenMesh) -> RuleEval + pub fn from_pairs(m: T, final_geom: OpenMesh) -> RuleEval where U: Borrow, - T: IntoIterator + T: IntoIterator)> { let (meshes, children): (Vec<_>, Vec<_>) = m.into_iter().unzip(); let (mesh, offsets) = OpenMesh::append(meshes); // Patch up vmap in each child, and copy everything else: - let children2: Vec = children.iter().zip(offsets.iter()).map(|(c,off)| { + let children2: Vec> = children.iter().zip(offsets.iter()).map(|(c,off)| { Child { rule: c.rule.clone(), xf: c.xf.clone(),