Rule now has, again, a type param

This commit is contained in:
Chris Hodapp 2020-04-05 00:00:29 -04:00
parent bd7105e333
commit 05a0aed8eb
2 changed files with 39 additions and 37 deletions

View File

@ -10,7 +10,7 @@ use crate::util;
use std::time::Instant; use std::time::Instant;
fn cube_thing() -> Rule { fn cube_thing() -> Rule<()> {
// Quarter-turn in radians: // Quarter-turn in radians:
let qtr = std::f32::consts::FRAC_PI_2; let qtr = std::f32::consts::FRAC_PI_2;
@ -29,7 +29,7 @@ fn cube_thing() -> Rule {
id.rotate(z, -qtr), id.rotate(z, -qtr),
]; ];
let rec = move |self_: Rc<Rule>| -> RuleEval { let rec = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
let xforms = turns.iter().map(|xf| xf.scale(0.5).translate(6.0, 0.0, 0.0)); let xforms = turns.iter().map(|xf| xf.scale(0.5).translate(6.0, 0.0, 0.0));
RuleEval { 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 // 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 // TODO: Clean this code up. It was a very naive conversion from
// the non-closure version. // the non-closure version.
let xf = Transform::new().rotate(&Vector3::x_axis(), -0.7); 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(); let seed2 = seed.clone();
// TODO: Why do I need the above? // 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); let seed_next = incr.transform(&seed2);
@ -85,7 +85,7 @@ fn twist(f: f32, subdiv: usize) -> Rule {
faces: faces, faces: faces,
}); });
let c = move |self_: Rc<Rule>| -> RuleEval { let c = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
RuleEval { RuleEval {
geom: geom.clone(), geom: geom.clone(),
final_geom: final_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 // TODO: Can a macro do anything to clean up some of the
// repetition with HOFs & closures? // 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(). let xform = Transform::new().
rotate(&y, ang0 + (qtr / div * (i as f32))). rotate(&y, ang0 + (qtr / div * (i as f32))).
translate(dx, 0.0, 0.0); translate(dx, 0.0, 0.0);
let c = Child { 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? // TODO: Cleanliness fix - can macros clean up above?
xf: xform, xf: xform,
vmap: (0..(n+1)).collect(), 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()) 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 v = Unit::new_normalize(Vector3::new(-1.0, 0.0, 1.0));
let incr: Transform = Transform::new(). let incr: Transform = Transform::new().
@ -170,7 +170,7 @@ fn ramhorn() -> Rule {
], ],
}); });
let recur = move |self_: Rc<Rule>| -> RuleEval { let recur = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
RuleEval { RuleEval {
geom: geom.clone(), geom: geom.clone(),
final_geom: final_geom.clone(), final_geom: final_geom.clone(),
@ -193,7 +193,7 @@ fn ramhorn() -> Rule {
translate(0.0, 0.0, -1.0) translate(0.0, 0.0, -1.0)
}; };
let start = move |_| -> RuleEval { let start = move |_| -> RuleEval<()> {
//let ofn = opening_xform.clone(); //let ofn = opening_xform.clone();
@ -244,22 +244,22 @@ fn ramhorn() -> Rule {
final_geom: Rc::new(prim::empty_mesh()), final_geom: Rc::new(prim::empty_mesh()),
children: vec![ children: vec![
Child { 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), xf: opening_xform(0.0),
vmap: vec![5,2,6,8], vmap: vec![5,2,6,8],
}, },
Child { 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), xf: opening_xform(1.0),
vmap: vec![4,1,5,8], vmap: vec![4,1,5,8],
}, },
Child { 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), xf: opening_xform(2.0),
vmap: vec![7,0,4,8], vmap: vec![7,0,4,8],
}, },
Child { 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), xf: opening_xform(3.0),
vmap: vec![6,3,7,8], 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<Rule>, iters: usize, name: &str) { fn run_test_iter<S>(r: &Rc<Rule<S>>, iters: usize, name: &str) {
println!("Running {}...", name); println!("Running {}...", name);
let start = Instant::now(); let start = Instant::now();
let n = 5; let n = 5;

View File

@ -4,16 +4,18 @@ use crate::xform::{Transform};
use std::borrow::Borrow; use std::borrow::Borrow;
use std::rc::Rc; use std::rc::Rc;
pub type RuleFn = Box<dyn Fn(Rc<Rule>) -> RuleEval>; pub type RuleFn<S> = Box<dyn Fn(Rc<Rule<S>>) -> RuleEval<S>>;
/// Definition of a rule. In general, a `Rule`: /// Definition of a rule. In general, a `Rule`:
/// ///
/// - produces geometry when it is evaluated /// - produces geometry when it is evaluated
/// - tells what other rules to invoke, and what to do with their /// - tells what other rules to invoke, and what to do with their
/// geometry /// geometry
pub struct Rule { pub struct Rule<S> {
pub eval: RuleFn, pub eval: RuleFn<S>,
pub ctxt: S,
} }
// TODO: It may be possible to have just a 'static' rule that requires // TODO: It may be possible to have just a 'static' rule that requires
// no function call. // no function call.
// TODO: Do I benefit with Rc<Rule> below so Rule can be shared? // TODO: Do I benefit with Rc<Rule> below so Rule can be shared?
@ -34,7 +36,7 @@ pub struct Rule {
/// - if recursion continues, the rules of `children` are evaluated, /// - if recursion continues, the rules of `children` are evaluated,
/// and the resultant geometry is transformed and then connected with /// and the resultant geometry is transformed and then connected with
/// `geom`. /// `geom`.
pub struct RuleEval { 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<OpenMesh>,
@ -49,16 +51,16 @@ pub struct RuleEval {
/// 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
/// by `children`, is `geom`. /// by `children`, is `geom`.
pub children: Vec<Child>, pub children: Vec<Child<S>>,
} }
/// `Child` evaluations, pairing another `Rule` with the /// `Child` evaluations, pairing another `Rule` with the
/// transformations and parent vertex mappings that should be applied /// transformations and parent vertex mappings that should be applied
/// to it. /// to it.
pub struct Child { pub struct Child<S> {
/// Rule to evaluate to produce geometry /// Rule to evaluate to produce geometry
pub rule: Rc<Rule>, pub rule: Rc<Rule<S>>,
/// The transform to apply to all geometry produced by `rule` /// The transform to apply to all geometry produced by `rule`
/// (including its own `geom` and `final_geom` if needed, as well /// (including its own `geom` and `final_geom` if needed, as well
@ -73,7 +75,7 @@ pub struct Child {
pub vmap: Vec<usize>, pub vmap: Vec<usize>,
} }
impl Rule { impl<S> Rule<S> {
// TODO: Do I want to make 'geom' shared somehow, maybe with Rc? I // 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 // 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). /// 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<Self>, iters_left: u32) -> (OpenMesh, usize) { pub fn to_mesh(s: Rc<Rule<S>>, iters_left: u32) -> (OpenMesh, usize) {
let mut evals = 1; let mut evals = 1;
let rs: RuleEval = (s.eval)(s.clone()); let rs: RuleEval<S> = (s.eval)(s.clone());
if iters_left <= 0 { if iters_left <= 0 {
return ((*rs.final_geom).clone(), 1); return ((*rs.final_geom).clone(), 1);
// TODO: This is probably wrong because of the way that // 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 /// 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<Self>, max_depth: usize) -> (OpenMesh, usize) { pub fn to_mesh_iter(s: Rc<Rule<S>>, max_depth: usize) -> (OpenMesh, usize) {
struct State { struct State<S> {
// The set of rules we're currently handling: // The set of rules we're currently handling:
rules: Vec<Child>, rules: Vec<Child<S>>,
// The next element of 'children' to handle: // The next element of 'children' to handle:
next: usize, next: usize,
// World transform of the *parent* of 'rules', that is, // World transform of the *parent* of 'rules', that is,
@ -142,7 +144,7 @@ impl Rule {
// //
// We evaluate our own rule to initialize the stack: // We evaluate our own rule to initialize the stack:
let eval = (s.eval)(s.clone()); let eval = (s.eval)(s.clone());
let mut stack: Vec<State> = vec![State { let mut stack: Vec<State<S>> = vec![State {
rules: eval.children, rules: eval.children,
next: 0, next: 0,
xf: Transform::new(), xf: Transform::new(),
@ -259,21 +261,21 @@ impl Rule {
} }
impl RuleEval { impl<S> RuleEval<S> {
/// Turn an iterator of (OpenMesh, Child) into a single RuleEval. /// Turn an iterator of (OpenMesh, 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 pub fn from_pairs<T, U>(m: T, final_geom: OpenMesh) -> RuleEval<S>
where U: Borrow<OpenMesh>, where U: Borrow<OpenMesh>,
T: IntoIterator<Item = (U, Child)> 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) = OpenMesh::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> = children.iter().zip(offsets.iter()).map(|(c,off)| { let children2: Vec<Child<S>> = children.iter().zip(offsets.iter()).map(|(c,off)| {
Child { Child {
rule: c.rule.clone(), rule: c.rule.clone(),
xf: c.xf.clone(), xf: c.xf.clone(),