From 4c626f6358f5d2c472561de3e1e7e4480f13c048 Mon Sep 17 00:00:00 2001 From: Chris Hodapp Date: Thu, 27 Feb 2020 21:51:34 -0500 Subject: [PATCH] Trying type parameters instead --- src/examples.rs | 708 +++++++++++++++++++++++++----------------------- src/rule.rs | 22 +- 2 files changed, 381 insertions(+), 349 deletions(-) diff --git a/src/examples.rs b/src/examples.rs index 8d373fc..964c055 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -6,354 +6,386 @@ use crate::rule::{Rule, RuleStep, Child}; use crate::prim; use crate::util; -fn curve_horn_start() -> RuleStep { - let id = nalgebra::geometry::Transform3::identity().to_homogeneous(); - let flip180 = nalgebra::geometry::Rotation3::from_axis_angle( - &nalgebra::Vector3::y_axis(), - std::f32::consts::PI).to_homogeneous(); - RuleStep { - geom: OpenMesh { - verts: vec![ +struct CurveHorn { + seed: Vec, + id_xform: Mat4, + flip180: Mat4, + incr: Mat4, +} + +impl CurveHorn { + + fn init() -> CurveHorn { + let y = &Vector3::y_axis(); + CurveHorn { + seed: vec![ vertex(-0.5, -0.5, 0.0), vertex(-0.5, 0.5, 0.0), vertex( 0.5, 0.5, 0.0), vertex( 0.5, -0.5, 0.0), ], - faces: vec![], - }, - final_geom: prim::empty_mesh(), - children: vec![ - Child { - rule: Rule::Recurse(curve_horn_thing_rule), - xf: id, - vmap: vec![0,1,2,3], - }, - Child { - rule: Rule::Recurse(curve_horn_thing_rule), - xf: flip180, - vmap: vec![3,2,1,0], - }, - ], - } -} - -fn curve_horn_thing_rule() -> RuleStep { - - let y = &Vector3::y_axis(); - - let m: Mat4 = geometry::Rotation3::from_axis_angle(y, 0.1).to_homogeneous() * - Matrix4::new_scaling(0.95) * - geometry::Translation3::new(0.0, 0.0, 0.2).to_homogeneous(); - - let verts = vec![ - vertex(-0.5, -0.5, 0.0), - vertex(-0.5, 0.5, 0.0), - vertex( 0.5, 0.5, 0.0), - vertex( 0.5, -0.5, 0.0), - ]; - let next_verts: Vec = verts.iter().map(|v| m * v).collect(); - - let geom = OpenMesh { - verts: next_verts.clone(), - faces: vec![ - // The below is just connecting two groups of 4 vertices - // each, straight across and then to the next. - Tag::Body(1), Tag::Parent(0), Tag::Body(0), - Tag::Parent(1), Tag::Parent(0), Tag::Body(1), - Tag::Body(2), Tag::Parent(1), Tag::Body(1), - Tag::Parent(2), Tag::Parent(1), Tag::Body(2), - Tag::Body(3), Tag::Parent(2), Tag::Body(2), - Tag::Parent(3), Tag::Parent(2), Tag::Body(3), - Tag::Body(0), Tag::Parent(3), Tag::Body(3), - Tag::Parent(0), Tag::Parent(3), Tag::Body(0), - // TODO: I should really generate these, not hard-code them. - ], - }; - - // TODO: This could be made slightly nicer by taking it to a peak - // instead of just flattening it in XY, but this is a pretty minor - // change. - let final_geom = OpenMesh { - verts: vec![], - faces: vec![ - Tag::Parent(0), Tag::Parent(2), Tag::Parent(1), - Tag::Parent(0), Tag::Parent(3), Tag::Parent(2), - ], - }; - - RuleStep{ - geom: geom, - final_geom: final_geom, - children: vec![ - Child { - rule: Rule::Recurse(curve_horn_thing_rule), - xf: m, - vmap: vec![0,1,2,3], - }, - ], - } -} - -fn cube_thing_rule() -> RuleStep { - - let mesh = prim::cube(); - - // Quarter-turn in radians: - let qtr = std::f32::consts::FRAC_PI_2; - - let y = &Vector3::y_axis(); - let z = &Vector3::z_axis(); - - // Each element of this turns to a branch for the recursion: - let turns: Vec = vec![ - geometry::Transform3::identity().to_homogeneous(), - geometry::Rotation3::from_axis_angle(y, qtr).to_homogeneous(), - geometry::Rotation3::from_axis_angle(y, qtr * 2.0).to_homogeneous(), - geometry::Rotation3::from_axis_angle(y, qtr * 3.0).to_homogeneous(), - geometry::Rotation3::from_axis_angle(z, qtr).to_homogeneous(), - geometry::Rotation3::from_axis_angle(z, -qtr).to_homogeneous(), - ]; - - 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::Recurse(cube_thing_rule), - xf: m, - vmap: vec![], + id_xform: nalgebra::geometry::Transform3::identity().to_homogeneous(), + flip180: nalgebra::geometry::Rotation3::from_axis_angle( + &nalgebra::Vector3::y_axis(), + std::f32::consts::PI).to_homogeneous(), + incr: geometry::Rotation3::from_axis_angle(y, 0.1).to_homogeneous() * + Matrix4::new_scaling(0.95) * + geometry::Translation3::new(0.0, 0.0, 0.2).to_homogeneous(), } - }; - - RuleStep { - geom: mesh, - final_geom: prim::empty_mesh(), - children: turns.iter().map(gen_rulestep).collect(), } -} - -// Conversion from Python & automata_scratch -fn ram_horn_start() -> RuleStep { - let opening_xform = |i| { - let r = std::f32::consts::FRAC_PI_2 * i; - ((geometry::Rotation3::from_axis_angle( - &nalgebra::Vector3::z_axis(), r).to_homogeneous()) * - geometry::Translation3::new(0.25, 0.25, 1.0).to_homogeneous() * - Matrix4::new_scaling(0.5) * - geometry::Translation3::new(0.0, 0.0, -1.0).to_homogeneous()) - }; - RuleStep { - geom: OpenMesh { - verts: vec![ - // 'Top' vertices: - vertex(-0.5, -0.5, 1.0), // 0 (above 9) - vertex(-0.5, 0.5, 1.0), // 1 (above 10) - vertex( 0.5, 0.5, 1.0), // 2 (above 11) - vertex( 0.5, -0.5, 1.0), // 3 (above 12) - // Top edge midpoints: - vertex(-0.5, 0.0, 1.0), // 4 (connects 0-1) - vertex( 0.0, 0.5, 1.0), // 5 (connects 1-2) - vertex( 0.5, 0.0, 1.0), // 6 (connects 2-3) - vertex( 0.0, -0.5, 1.0), // 7 (connects 3-0) - // Top middle: - vertex( 0.0, 0.0, 1.0), // 8 - // 'Bottom' vertices: - vertex(-0.5, -0.5, 0.0), // 9 - vertex(-0.5, 0.5, 0.0), // 10 - vertex( 0.5, 0.5, 0.0), // 11 - vertex( 0.5, -0.5, 0.0), // 12 + + fn start(&self) -> RuleStep { + RuleStep { + geom: OpenMesh { + verts: self.seed.clone(), + faces: vec![], + }, + final_geom: prim::empty_mesh(), + children: vec![ + Child { + rule: Rule::Recurse(Self::recur), + xf: self.id_xform, + vmap: vec![0,1,2,3], + }, + Child { + rule: Rule::Recurse(Self::recur), + xf: self.flip180, + vmap: vec![3,2,1,0], + }, ], + } + } + + fn recur(&self) -> RuleStep { + + let verts = self.seed.clone(); + let next_verts: Vec = verts.iter().map(|v| self.incr * v).collect(); + + let geom = OpenMesh { + verts: next_verts.clone(), faces: vec![ - // bottom face: - Tag::Body(9), Tag::Body(10), Tag::Body(11), - Tag::Body(9), Tag::Body(11), Tag::Body(12), - // two faces straddling edge from vertex 0: - Tag::Body(9), Tag::Body(0), Tag::Body(4), - Tag::Body(9), Tag::Body(7), Tag::Body(0), - // two faces straddling edge from vertex 1: - Tag::Body(10), Tag::Body(1), Tag::Body(5), - Tag::Body(10), Tag::Body(4), Tag::Body(1), - // two faces straddling edge from vertex 2: - Tag::Body(11), Tag::Body(2), Tag::Body(6), - Tag::Body(11), Tag::Body(5), Tag::Body(2), - // two faces straddling edge from vertex 3: - Tag::Body(12), Tag::Body(3), Tag::Body(7), - Tag::Body(12), Tag::Body(6), Tag::Body(3), - // four faces from edge (0,1), (1,2), (2,3), (3,0): - Tag::Body(9), Tag::Body(4), Tag::Body(10), - Tag::Body(10), Tag::Body(5), Tag::Body(11), - Tag::Body(11), Tag::Body(6), Tag::Body(12), - Tag::Body(12), Tag::Body(7), Tag::Body(9), + // The below is just connecting two groups of 4 vertices + // each, straight across and then to the next. + Tag::Body(1), Tag::Parent(0), Tag::Body(0), + Tag::Parent(1), Tag::Parent(0), Tag::Body(1), + Tag::Body(2), Tag::Parent(1), Tag::Body(1), + Tag::Parent(2), Tag::Parent(1), Tag::Body(2), + Tag::Body(3), Tag::Parent(2), Tag::Body(2), + Tag::Parent(3), Tag::Parent(2), Tag::Body(3), + Tag::Body(0), Tag::Parent(3), Tag::Body(3), + Tag::Parent(0), Tag::Parent(3), Tag::Body(0), + // TODO: I should really generate these, not hard-code them. ], - }, - final_geom: prim::empty_mesh(), - children: vec![ - Child { - rule: Rule::Recurse(ram_horn), - xf: opening_xform(0.0), - vmap: vec![5,2,6,8], - }, - Child { - rule: Rule::Recurse(ram_horn), - xf: opening_xform(1.0), - vmap: vec![4,1,5,8], - }, - Child { - rule: Rule::Recurse(ram_horn), - xf: opening_xform(2.0), - vmap: vec![7,0,4,8], - }, - Child { - rule: Rule::Recurse(ram_horn), - xf: opening_xform(3.0), - vmap: vec![6,3,7,8], - }, - // TODO: These vertex mappings appear to be right. - // Explain *why* they are right. - ], - } -} + }; -fn ram_horn() -> RuleStep { - 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() * - Matrix4::new_scaling(0.9); - let seed = vec![ - vertex(-0.5, -0.5, 1.0), - vertex(-0.5, 0.5, 1.0), - vertex( 0.5, 0.5, 1.0), - vertex( 0.5, -0.5, 1.0), - ]; - let next = seed.iter().map(|v| incr * v).collect(); - let geom = OpenMesh { - verts: next, - faces: vec![ - Tag::Body(1), Tag::Parent(0), Tag::Body(0), - Tag::Parent(1), Tag::Parent(0), Tag::Body(1), - Tag::Body(2), Tag::Parent(1), Tag::Body(1), - Tag::Parent(2), Tag::Parent(1), Tag::Body(2), - Tag::Body(3), Tag::Parent(2), Tag::Body(2), - Tag::Parent(3), Tag::Parent(2), Tag::Body(3), - Tag::Body(0), Tag::Parent(3), Tag::Body(3), - Tag::Parent(0), Tag::Parent(3), Tag::Body(0), - ], - }; - let final_geom = OpenMesh { - verts: vec![], - faces: vec![ - Tag::Parent(0), Tag::Parent(2), Tag::Parent(1), - Tag::Parent(0), Tag::Parent(3), Tag::Parent(2), - ], - }; - RuleStep { - geom: geom, - final_geom: final_geom, - children: vec![ - Child { - rule: Rule::Recurse(ram_horn), - xf: incr, - vmap: vec![0,1,2,3], - }, - ], - } -} - -/* -fn ram_horn_branch() -> RuleStep { - -} - */ - -// Meant to be a copy of twist_from_gen from Python & automata_scratch -pub fn twist_start() -> RuleStep { - //let ang=0.1; - let dx0=2.0; - let count=4; - // TODO: Factor these out (see twist) - - let seed = util::subdivide_cycle(&vec![ - vertex(-0.5, 0.0, -0.5), - vertex( 0.5, 0.0, -0.5), - vertex( 0.5, 0.0, 0.5), - vertex(-0.5, 0.0, 0.5), - ], 2); - // TODO: Factor out - let n = seed.len(); - // TODO: Factor out subdiv size - - // Quarter-turn in radians: - let qtr = std::f32::consts::FRAC_PI_2; - let y = &Vector3::y_axis(); - let xform = |i| { - (geometry::Rotation3::from_axis_angle(y, qtr * (i as f32)).to_homogeneous() * - geometry::Translation3::new(dx0, 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); - Child { - rule: Rule::Recurse(twist), - xf: xf, - vmap: (n*i..n*(i+count)).collect(), // N.B. + // TODO: This could be made slightly nicer by taking it to a peak + // instead of just flattening it in XY, but this is a pretty minor + // change. + let final_geom = OpenMesh { + verts: vec![], + faces: vec![ + Tag::Parent(0), Tag::Parent(2), Tag::Parent(1), + Tag::Parent(0), Tag::Parent(3), Tag::Parent(2), + ], + }; + + RuleStep{ + geom: geom, + final_geom: final_geom, + children: vec![ + Child { + rule: Rule::Recurse(Self::recur), + xf: self.incr, + vmap: vec![0,1,2,3], + }, + ], } - }).collect(); - - // Use byproducts of this to make 'count' copies of 'seed' with - // this same transform: - let mut verts = vec![]; - for child in &children { - verts.extend(seed.iter().map(|v| child.xf * v)); - } - - RuleStep { - geom: OpenMesh { - verts: verts, - faces: vec![], - // TODO: Close these initial faces off - }, - final_geom: prim::empty_mesh(), - children: children, } } -pub fn twist() -> RuleStep { - let ang=0.1; - let dx0=2.0; - let dy=0.1; - // TODO: Factor these out (see twist_start) +struct CubeThing { +} - let y = &Vector3::y_axis(); - let incr = 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(); +impl CubeThing { + + fn init() -> CubeThing { + CubeThing {} + } - let seed_orig = vec![ - vertex(-0.5, 0.0, -0.5), - vertex( 0.5, 0.0, -0.5), - vertex( 0.5, 0.0, 0.5), - vertex(-0.5, 0.0, 0.5), - // TODO: Likewise factor these out - ].iter().map(|v| incr * v).collect(); - let seed = util::subdivide_cycle(&seed_orig, 2); - let n = seed.len(); - // TODO: Factor out subdiv size - - RuleStep { - geom: OpenMesh { - verts: seed, - faces: util::parallel_zigzag_faces(n), - }, - final_geom: prim::empty_mesh(), // TODO: Close properly - children: vec![ + fn rec(&self) -> RuleStep { + + let mesh = prim::cube(); + + // Quarter-turn in radians: + let qtr = std::f32::consts::FRAC_PI_2; + + let y = &Vector3::y_axis(); + let z = &Vector3::z_axis(); + + // Each element of this turns to a branch for the recursion: + let turns: Vec = vec![ + geometry::Transform3::identity().to_homogeneous(), + geometry::Rotation3::from_axis_angle(y, qtr).to_homogeneous(), + geometry::Rotation3::from_axis_angle(y, qtr * 2.0).to_homogeneous(), + geometry::Rotation3::from_axis_angle(y, qtr * 3.0).to_homogeneous(), + geometry::Rotation3::from_axis_angle(z, qtr).to_homogeneous(), + geometry::Rotation3::from_axis_angle(z, -qtr).to_homogeneous(), + ]; + + 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::Recurse(twist), - xf: incr, - vmap: (0..n).collect(), + rule: Rule::Recurse(Self::rec), + xf: m, + vmap: vec![], + } + }; + + RuleStep { + geom: mesh, + final_geom: prim::empty_mesh(), + children: turns.iter().map(gen_rulestep).collect(), + } + } +} + +struct RamHorn { +} + +impl RamHorn { + + fn init() -> RamHorn { + RamHorn{} + } + + // Conversion from Python & automata_scratch + fn start(&self) -> RuleStep { + let opening_xform = |i| { + let r = std::f32::consts::FRAC_PI_2 * i; + ((geometry::Rotation3::from_axis_angle( + &nalgebra::Vector3::z_axis(), r).to_homogeneous()) * + geometry::Translation3::new(0.25, 0.25, 1.0).to_homogeneous() * + Matrix4::new_scaling(0.5) * + geometry::Translation3::new(0.0, 0.0, -1.0).to_homogeneous()) + }; + RuleStep { + geom: OpenMesh { + verts: vec![ + // 'Top' vertices: + vertex(-0.5, -0.5, 1.0), // 0 (above 9) + vertex(-0.5, 0.5, 1.0), // 1 (above 10) + vertex( 0.5, 0.5, 1.0), // 2 (above 11) + vertex( 0.5, -0.5, 1.0), // 3 (above 12) + // Top edge midpoints: + vertex(-0.5, 0.0, 1.0), // 4 (connects 0-1) + vertex( 0.0, 0.5, 1.0), // 5 (connects 1-2) + vertex( 0.5, 0.0, 1.0), // 6 (connects 2-3) + vertex( 0.0, -0.5, 1.0), // 7 (connects 3-0) + // Top middle: + vertex( 0.0, 0.0, 1.0), // 8 + // 'Bottom' vertices: + vertex(-0.5, -0.5, 0.0), // 9 + vertex(-0.5, 0.5, 0.0), // 10 + vertex( 0.5, 0.5, 0.0), // 11 + vertex( 0.5, -0.5, 0.0), // 12 + ], + faces: vec![ + // bottom face: + Tag::Body(9), Tag::Body(10), Tag::Body(11), + Tag::Body(9), Tag::Body(11), Tag::Body(12), + // two faces straddling edge from vertex 0: + Tag::Body(9), Tag::Body(0), Tag::Body(4), + Tag::Body(9), Tag::Body(7), Tag::Body(0), + // two faces straddling edge from vertex 1: + Tag::Body(10), Tag::Body(1), Tag::Body(5), + Tag::Body(10), Tag::Body(4), Tag::Body(1), + // two faces straddling edge from vertex 2: + Tag::Body(11), Tag::Body(2), Tag::Body(6), + Tag::Body(11), Tag::Body(5), Tag::Body(2), + // two faces straddling edge from vertex 3: + Tag::Body(12), Tag::Body(3), Tag::Body(7), + Tag::Body(12), Tag::Body(6), Tag::Body(3), + // four faces from edge (0,1), (1,2), (2,3), (3,0): + Tag::Body(9), Tag::Body(4), Tag::Body(10), + Tag::Body(10), Tag::Body(5), Tag::Body(11), + Tag::Body(11), Tag::Body(6), Tag::Body(12), + Tag::Body(12), Tag::Body(7), Tag::Body(9), + ], }, - ], + final_geom: prim::empty_mesh(), + children: vec![ + Child { + rule: Rule::Recurse(Self::ram_horn), + xf: opening_xform(0.0), + vmap: vec![5,2,6,8], + }, + Child { + rule: Rule::Recurse(Self::ram_horn), + xf: opening_xform(1.0), + vmap: vec![4,1,5,8], + }, + Child { + rule: Rule::Recurse(Self::ram_horn), + xf: opening_xform(2.0), + vmap: vec![7,0,4,8], + }, + Child { + rule: Rule::Recurse(Self::ram_horn), + xf: opening_xform(3.0), + vmap: vec![6,3,7,8], + }, + // TODO: These vertex mappings appear to be right. + // Explain *why* they are right. + ], + } + } + + fn ram_horn(&self) -> RuleStep { + 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() * + Matrix4::new_scaling(0.9); + let seed = vec![ + vertex(-0.5, -0.5, 1.0), + vertex(-0.5, 0.5, 1.0), + vertex( 0.5, 0.5, 1.0), + vertex( 0.5, -0.5, 1.0), + ]; + let next = seed.iter().map(|v| incr * v).collect(); + let geom = OpenMesh { + verts: next, + faces: vec![ + Tag::Body(1), Tag::Parent(0), Tag::Body(0), + Tag::Parent(1), Tag::Parent(0), Tag::Body(1), + Tag::Body(2), Tag::Parent(1), Tag::Body(1), + Tag::Parent(2), Tag::Parent(1), Tag::Body(2), + Tag::Body(3), Tag::Parent(2), Tag::Body(2), + Tag::Parent(3), Tag::Parent(2), Tag::Body(3), + Tag::Body(0), Tag::Parent(3), Tag::Body(3), + Tag::Parent(0), Tag::Parent(3), Tag::Body(0), + ], + }; + let final_geom = OpenMesh { + verts: vec![], + faces: vec![ + Tag::Parent(0), Tag::Parent(2), Tag::Parent(1), + Tag::Parent(0), Tag::Parent(3), Tag::Parent(2), + ], + }; + RuleStep { + geom: geom, + final_geom: final_geom, + children: vec![ + Child { + rule: Rule::Recurse(Self::ram_horn), + xf: incr, + vmap: vec![0,1,2,3], + }, + ], + } + } +} + +struct Twist { + seed: Vec, + seed_sub: Vec, + dx0: f32, + dy: f32, + ang: f32, + count: usize, + subdiv: usize, +} + +impl Twist { + + pub fn init() -> Twist { + let subdiv = 2; + let seed = vec![ + vertex(-0.5, 0.0, -0.5), + vertex( 0.5, 0.0, -0.5), + vertex( 0.5, 0.0, 0.5), + vertex(-0.5, 0.0, 0.5), + ]; + let seed_sub = util::subdivide_cycle(&seed, subdiv); + Twist { + dx0: 2.0, + dy: 0.1, + ang: 0.1, + count: 4, + seed: seed, + seed_sub: seed_sub, + subdiv: subdiv, + } + } + + // Meant to be a copy of twist_from_gen from Python & automata_scratch + pub fn start(&self) -> RuleStep { + + let n = self.seed.len(); + + // Quarter-turn in radians: + let qtr = std::f32::consts::FRAC_PI_2; + let y = &Vector3::y_axis(); + let xform = |i| { + (geometry::Rotation3::from_axis_angle(y, qtr * (i as f32)).to_homogeneous() * + geometry::Translation3::new(self.dx0, 0.0, 0.0).to_homogeneous()) + }; + + // First generate 'count' children, each one shifted/rotated + // differently: + let children: Vec> = (0..self.count).map(|i| { + let xf = xform(i); + Child { + rule: Rule::Recurse(Self::recur), + xf: xf, + vmap: (n*i..n*(i+self.count)).collect(), // N.B. + } + }).collect(); + + // Use byproducts of this to make 'count' copies of 'seed' with + // this same transform: + let mut verts = vec![]; + for child in &children { + verts.extend(self.seed_sub.iter().map(|v| child.xf * v)); + } + + RuleStep { + geom: OpenMesh { + verts: verts, + faces: vec![], + // TODO: Close these initial faces off + }, + final_geom: prim::empty_mesh(), + children: children, + } + } + + pub fn recur(&self) -> RuleStep { + 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() * + geometry::Translation3::new(self.dx0, self.dy, 0.0).to_homogeneous(); + + let seed_orig = self.seed.iter().map(|v| incr * v).collect(); + let seed_sub = util::subdivide_cycle(&seed_orig, self.subdiv); + let n = seed_sub.len(); + + RuleStep { + geom: OpenMesh { + verts: seed_sub, + faces: util::parallel_zigzag_faces(n), + }, + final_geom: prim::empty_mesh(), // TODO: Close properly + children: vec![ + Child { + rule: Rule::Recurse(Self::recur), + xf: incr, + vmap: (0..n).collect(), + }, + ], + } } } @@ -370,21 +402,21 @@ pub fn main() { println!("vs={:?}", vs); println!("vs2={:?}", vs2); } - - let run_test = |r: Rule, iters, name| { + + fn run_test(a: A, r: Rule, iters: u32, name: &str) { println!("Running {}...", name); - let (mesh, nodes) = r.to_mesh(iters); + let (mesh, nodes) = r.to_mesh(&a, iters); println!("Merged {} nodes", nodes); let fname = format!("{}.stl", name); println!("Writing {}...", fname); mesh.write_stl_file(&fname).unwrap(); - }; + } - run_test(Rule::Recurse(cube_thing_rule), 3, "cube_thing"); + run_test(CubeThing::init(), Rule::Recurse(CubeThing::rec), 3, "cube_thing"); // this can't work on its own because the resultant OpenMesh still // has parent references: - //run_test(Rule::Recurse(curve_horn_thing_rule), 100, "curve_horn_thing"); - run_test(Rule::Recurse(curve_horn_start), 100, "curve_horn2"); - run_test(Rule::Recurse(ram_horn_start), 200, "ram_horn"); - run_test(Rule::Recurse(twist_start), 200, "twist"); + //run_test(Rule::Recurse(recur), 100, "curve_horn_thing"); + run_test(CurveHorn::init(), Rule::Recurse(CurveHorn::start), 100, "curve_horn2"); + run_test(RamHorn::init(), Rule::Recurse(RamHorn::start), 200, "ram_horn"); + run_test(Twist::init(), Rule::Recurse(Twist::start), 200, "twist"); } diff --git a/src/rule.rs b/src/rule.rs index eb6422c..99c8d9e 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -6,9 +6,9 @@ use crate::prim; /// - produces geometry when it is evaluated /// - tells what other rules to invoke, and what to do with their /// geometry -pub enum Rule { +pub enum Rule { /// Produce some geometry, and possibly recurse further. - Recurse(fn () -> RuleStep), + Recurse(fn (&A) -> RuleStep), /// Produce nothing and recurse no further. EmptyRule, } @@ -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 RuleStep { /// The geometry generated at just this iteration pub geom: OpenMesh, @@ -43,16 +43,16 @@ pub struct RuleStep { /// 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 @@ -67,7 +67,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 @@ -80,14 +80,14 @@ impl Rule { /// Convert this `Rule` to mesh data, recursively. `iters_left` /// sets the maximum recursion depth. This returns (geometry, /// number of rule evaluations). - pub fn to_mesh(&self, iters_left: u32) -> (OpenMesh, u32) { + pub fn to_mesh(&self, arg: &A, iters_left: u32) -> (OpenMesh, u32) { let mut evals: u32 = 1; if iters_left <= 0 { match self { Rule::Recurse(f) => { - let rs: RuleStep = f(); + let rs: RuleStep = f(arg); return (rs.final_geom, 1); } Rule::EmptyRule => { @@ -98,13 +98,13 @@ impl Rule { match self { Rule::Recurse(f) => { - let rs: RuleStep = f(); + let rs: RuleStep = f(arg); // TODO: This logic is more or less right, but it // could perhaps use some un-tupling or something. let subgeom: Vec<(OpenMesh, &Vec)> = rs.children.iter().map(|sub| { // Get sub-geometry (still un-transformed): - let (submesh, eval) = sub.rule.to_mesh(iters_left - 1); + let (submesh, eval) = sub.rule.to_mesh(arg, iters_left - 1); // Tally up eval count: evals += eval;