From 21ce55d14121e26a2be130a00c3ac7b1346dd228 Mon Sep 17 00:00:00 2001 From: Chris Hodapp Date: Fri, 27 Mar 2020 23:00:24 -0400 Subject: [PATCH] Add hacky example of (incorrect) double spiral in twist() --- src/examples.rs | 74 ++++++++++++++++++++++++++++++------------------- src/openmesh.rs | 9 ++++-- src/rule.rs | 4 ++- 3 files changed, 55 insertions(+), 32 deletions(-) diff --git a/src/examples.rs b/src/examples.rs index f529bba..b3e5ef7 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -3,7 +3,7 @@ use nalgebra::*; //pub mod examples; use crate::openmesh::{OpenMesh, Tag, Mat4, Vertex, vertex, transform}; -use crate::rule::{Rule, RuleEval, Child}; +use crate::rule::{Rule, RuleFn, RuleEval, Child}; use crate::prim; use crate::util; use crate::scratch; @@ -375,24 +375,26 @@ fn twist(f: f32, subdiv: usize) -> Rule { vertex( 0.5, 0.0, 0.5), vertex(-0.5, 0.0, 0.5), ], &xf); - let seed_sub = util::subdivide_cycle(&seed, subdiv); + //let seed_sub = util::subdivide_cycle(&seed, subdiv); let dx0: f32 = 2.0; let dy: f32 = 0.1/f; let ang: f32 = 0.1/f; let count: usize = 4; - - let n = seed_sub.len(); // Quarter-turn in radians: let qtr = std::f32::consts::FRAC_PI_2; let y = Vector3::y_axis(); - let incr = geometry::Translation3::new(-dx0, 0.0, 0.0).to_homogeneous() * + let incr_inner = geometry::Translation3::new(-dx0, 0.0, 0.0).to_homogeneous() * geometry::Rotation3::from_axis_angle(&y, ang).to_homogeneous() * geometry::Translation3::new(dx0, dy, 0.0).to_homogeneous(); + let incr_outer = geometry::Translation3::new(-dx0*2.0, 0.0, 0.0).to_homogeneous() * + geometry::Rotation3::from_axis_angle(&y, ang/2.0).to_homogeneous() * + geometry::Translation3::new(dx0*2.0, dy, 0.0).to_homogeneous(); - let seed_orig = transform(&seed, &incr); + let seed_orig = transform(&seed, &incr_inner); let seed_sub = util::subdivide_cycle(&seed_orig, subdiv); + let n = seed_sub.len(); let geom = OpenMesh { verts: seed_sub.clone(), @@ -403,42 +405,56 @@ fn twist(f: f32, subdiv: usize) -> Rule { verts: vec![vc], faces: faces.clone(), }; - - let recur = move |self_: Rc| -> RuleEval { - // TODO: Why clone geometry here if I just have to clone it - // later on? Seems like Rc may be much easier (if I can't - // borrow directly - which is probably the case). - RuleEval { - geom: geom.clone(), - final_geom: final_geom.clone(), - children: vec![ - Child { - rule: self_.clone(), - xf: incr, - vmap: (0..n).collect(), - }, - ], - } + + let recur = move |incr: Mat4| -> RuleFn { + let c = move |self_: Rc| -> RuleEval { + // TODO: Why clone geometry here if I just have to clone it + // later on? Seems like Rc may be much easier (if I can't + // borrow directly - which is probably the case). + RuleEval { + geom: geom.clone(), + final_geom: final_geom.clone(), + children: vec![ + Child { + rule: self_.clone(), + xf: incr, + vmap: (0..n).collect(), + }, + ], + } + }; + Box::new(c) }; + // TODO: so there's incr_inner & incr_outer that I wanted to + // parametrize over. why is it so ugly to do so? + let start = move |self_: Rc| -> RuleEval { - let xform = |i| { + let xform = |dx, i| { (geometry::Rotation3::from_axis_angle(&y, qtr * (i as f32)).to_homogeneous() * - geometry::Translation3::new(dx0, 0.0, 0.0).to_homogeneous()) + geometry::Translation3::new(dx, 0.0, 0.0).to_homogeneous()) }; // First generate 'count' children, each one shifted/rotated // differently: - let children: Vec = (0..count).map(|i| { - let xf = xform(i); + let children_inner = (0..count).map(|i| { Child { - rule: Rc::new(Rule { eval: Box::new(recur.clone()) }), - xf: xf, + rule: Rc::new(Rule { eval: (recur.clone())(incr_inner) }), + xf: xform(dx0, i), vmap: ((n+1)*i..(n+1)*(i+count)).collect(), // N.B. // note n+1, not n. the +1 is for the centroid below } - }).collect(); + }); + let children_outer = (0..count).map(|i| { + Child { + rule: Rc::new(Rule { eval: (recur.clone())(incr_outer) }), + xf: xform(dx0*2.0, i), + vmap: ((n+1)*i..(n+1)*(i+count)).collect(), // N.B. + // note n+1, not n. the +1 is for the centroid below + } + }); + let children: Vec = children_inner.chain(children_outer).collect(); // Use byproducts of this to make 'count' copies of 'seed' with // this same transform: diff --git a/src/openmesh.rs b/src/openmesh.rs index 7153033..d44897d 100644 --- a/src/openmesh.rs +++ b/src/openmesh.rs @@ -3,6 +3,7 @@ use nalgebra::*; use std::fs::OpenOptions; use std::io; +use std::borrow::Borrow; /// A type for mesh vertices. Initialize with [vertex][self::vertex]. pub type Vertex = Vector4; @@ -44,11 +45,15 @@ pub struct OpenMesh { impl OpenMesh { - pub fn append>(meshes: T) -> OpenMesh + pub fn append(meshes: T) -> OpenMesh + where U: Borrow, + T: IntoIterator { let mut v: Vec = vec![]; let mut f: Vec = vec![]; - for mesh in meshes { + for mesh_ in meshes { + let mesh = mesh_.borrow(); + // Position in 'verts' at which we're appending // mesh.verts, which we need to know to shift indices: let offset = v.len(); diff --git a/src/rule.rs b/src/rule.rs index a6180ea..0347816 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -2,13 +2,15 @@ use crate::openmesh::{OpenMesh, Tag, Mat4}; //use crate::prim; use std::rc::Rc; +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: Box) -> RuleEval>, + pub eval: RuleFn, } // TODO: It may be possible to have just a 'static' rule that requires // no function call.