diff --git a/src/examples.rs b/src/examples.rs index 964c055..68db177 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -2,7 +2,7 @@ use nalgebra::*; //pub mod examples; use crate::openmesh::{OpenMesh, Tag, Mat4, Vertex, vertex}; -use crate::rule::{Rule, RuleStep, Child}; +use crate::rule::{Rule, RuleEval, Child}; use crate::prim; use crate::util; @@ -34,8 +34,8 @@ impl CurveHorn { } } - fn start(&self) -> RuleStep { - RuleStep { + fn start(&self) -> RuleEval { + RuleEval { geom: OpenMesh { verts: self.seed.clone(), faces: vec![], @@ -56,7 +56,7 @@ impl CurveHorn { } } - fn recur(&self) -> RuleStep { + fn recur(&self) -> RuleEval { let verts = self.seed.clone(); let next_verts: Vec = verts.iter().map(|v| self.incr * v).collect(); @@ -89,7 +89,7 @@ impl CurveHorn { ], }; - RuleStep{ + RuleEval{ geom: geom, final_geom: final_geom, children: vec![ @@ -112,7 +112,7 @@ impl CubeThing { CubeThing {} } - fn rec(&self) -> RuleStep { + fn rec(&self) -> RuleEval { let mesh = prim::cube(); @@ -143,7 +143,7 @@ impl CubeThing { } }; - RuleStep { + RuleEval { geom: mesh, final_geom: prim::empty_mesh(), children: turns.iter().map(gen_rulestep).collect(), @@ -161,7 +161,7 @@ impl RamHorn { } // Conversion from Python & automata_scratch - fn start(&self) -> RuleStep { + fn start(&self) -> RuleEval { let opening_xform = |i| { let r = std::f32::consts::FRAC_PI_2 * i; ((geometry::Rotation3::from_axis_angle( @@ -170,7 +170,7 @@ impl RamHorn { Matrix4::new_scaling(0.5) * geometry::Translation3::new(0.0, 0.0, -1.0).to_homogeneous()) }; - RuleStep { + RuleEval { geom: OpenMesh { verts: vec![ // 'Top' vertices: @@ -242,7 +242,7 @@ impl RamHorn { } } - fn ram_horn(&self) -> RuleStep { + 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() * @@ -274,7 +274,7 @@ impl RamHorn { Tag::Parent(0), Tag::Parent(3), Tag::Parent(2), ], }; - RuleStep { + RuleEval { geom: geom, final_geom: final_geom, children: vec![ @@ -321,7 +321,7 @@ impl Twist { } // Meant to be a copy of twist_from_gen from Python & automata_scratch - pub fn start(&self) -> RuleStep { + pub fn start(&self) -> RuleEval { let n = self.seed.len(); @@ -351,7 +351,7 @@ impl Twist { verts.extend(self.seed_sub.iter().map(|v| child.xf * v)); } - RuleStep { + RuleEval { geom: OpenMesh { verts: verts, faces: vec![], @@ -362,7 +362,7 @@ impl Twist { } } - pub fn recur(&self) -> RuleStep { + 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() * @@ -372,7 +372,7 @@ impl Twist { let seed_sub = util::subdivide_cycle(&seed_orig, self.subdiv); let n = seed_sub.len(); - RuleStep { + RuleEval { geom: OpenMesh { verts: seed_sub, faces: util::parallel_zigzag_faces(n), diff --git a/src/rule.rs b/src/rule.rs index 99c8d9e..fe7416e 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -8,7 +8,7 @@ use crate::prim; /// geometry pub enum Rule { /// Produce some geometry, and possibly recurse further. - Recurse(fn (&A) -> RuleStep), + Recurse(fn (&A) -> RuleEval), /// Produce nothing and recurse no further. EmptyRule, } @@ -17,7 +17,7 @@ pub enum Rule { // no function call. // TODO: Do I benefit with Rc below so Rule can be shared? -/// `RuleStep` supplies the results of evaluating some `Rule` for one +/// `RuleEval` supplies the results of evaluating some `Rule` for one /// iteration: it contains the geometry produced at this step /// (`geom`), and it tells what to do next depending on whether /// recursion continues further, or is stopped here (due to hitting @@ -28,7 +28,7 @@ pub enum Rule { /// - if recursion continues, the rules of `children` are evaluated, /// and the resultant geometry is transformed and then connected with /// `geom`. -pub struct RuleStep { +pub struct RuleEval { /// The geometry generated at just this iteration pub geom: OpenMesh, @@ -77,9 +77,9 @@ impl Rule { // rather than repeatedly transforming meshes, it stacks // transformations and then applies them all at once. - /// Convert this `Rule` to mesh data, recursively. `iters_left` - /// sets the maximum recursion depth. This returns (geometry, - /// number of rule evaluations). + /// 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, u32) { let mut evals: u32 = 1; @@ -87,7 +87,7 @@ impl Rule { if iters_left <= 0 { match self { Rule::Recurse(f) => { - let rs: RuleStep = f(arg); + let rs: RuleEval = f(arg); return (rs.final_geom, 1); } Rule::EmptyRule => { @@ -98,7 +98,7 @@ impl Rule { match self { Rule::Recurse(f) => { - let rs: RuleStep = f(arg); + let rs: RuleEval = f(arg); // TODO: This logic is more or less right, but it // could perhaps use some un-tupling or something. @@ -121,4 +121,96 @@ impl Rule { } } } + + pub fn to_mesh_iter(&self, arg: &A, max_depth: usize) -> (OpenMesh, u32) { + + let mut geom = prim::empty_mesh(); + let mut stack: Vec<(RuleEval, usize)> = vec![]; + + match self { + Rule::Recurse(f) => stack.push((f(arg), 0)), + Rule::EmptyRule => {}, + } + + loop { + let n = stack.len(); // TODO: Just keep a running total. + // We can increment/decrement as we push/pop. + let (eval, idx) = stack[n-1]; + // note that: + // stack[n-2].children[idx] = eval (so to speak) + + // I can't do the above. I can either... + // - Implement Copy for RuleEval. + // - push/pop all over the place and deal with the Option + // unpacking and the extra state-changes. + // - use something nicer than RuleEval? + + // I can't borrow it because a mutable borrow is already + // done with the pop? + + // I don't need to share geometry. I use geometry only + // once (though I may need to be careful on the rules with + // final_geom), though that's not yet implemented. + + // Deriving automatically puts the Copy constraint on A, + // and I am not sure I want to deal with that - but I have + // to be able to copy Child regardless, thus Rule. + + // Function pointers support Copy, so Rule is fine. + // Vectors by design do *not*. + + // Seems a little bizarre that none of this affects + // recursive to_mesh... what am I doing differently? + + // See if it is time to backtrack: + if n > max_depth || eval.children.is_empty() { + // This has no parents: + if n < 2 { + break; + } + + // Backtrack: + stack.pop(); + // TODO: Pop transform off of stack + + // If possible, step to the next sibling: + let (parent, _) = &stack[n-2]; + if (idx + 1) < parent.children.len() { + let sib = parent.children[idx + 1]; + match sib.rule { + Rule::Recurse(f) => { + let eval_sib = f(arg); + stack.push((eval_sib, idx + 1)); + // TODO: Push transform onto stack + // TODO: Append geometry + }, + Rule::EmptyRule => { + // Nowhere to recurse further + } + } + } + continue; + } else { + // Otherwise, try to recurse to first child: + let child = eval.children[0]; + match child.rule { + Rule::Recurse(f) => { + let eval_child = f(arg); + stack.push((eval_child, 0)); + // TODO: Push transform onto stack + // TODO: Append geometry + } + Rule::EmptyRule => { + // Do nothing. + } + } + } + } + + // TODO: Return right number + return (geom, 0); + + } + + } diff --git a/src/util.rs b/src/util.rs index 66baa85..be77f06 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,5 +1,5 @@ -use crate::openmesh::{OpenMesh, Tag, Mat4, Vertex, vertex}; -use crate::rule::{Rule, RuleStep, Child}; +use crate::openmesh::{Tag, Vertex}; +//use crate::rule::{Rule, Child}; /// Linearly subdivides a list of points that are to be treated as a /// cycle. This produces 'count' points for every element of 'p'