From 670b7859a9262322fb693ec82cf9163927909c66 Mon Sep 17 00:00:00 2001 From: Chris Hodapp Date: Sun, 24 Jan 2021 18:48:34 -0500 Subject: [PATCH] Refactor to use itertools --- Cargo.toml | 3 +- src/examples.rs | 129 +++++++++++++++++++++++------------------------- 2 files changed, 63 insertions(+), 69 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d726ba4..6018e9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,10 +9,11 @@ edition = "2018" [profile.release] # Unoptimized debug builds are too slow to profile # having debug info doesn't hurt perf for now -# debug = true +debug = true [dependencies] euclid = "0.20.7" nalgebra = "0.19.0" stl_io = "0.4.2" rand = "0.7.3" +itertools = "0.10.0" diff --git a/src/examples.rs b/src/examples.rs index 4844ab0..fa28c9d 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -8,6 +8,7 @@ use crate::util; use crate::util::VecExt; use crate::mesh::{Mesh}; use crate::xform::{Transform, Vertex, vertex, id}; +use itertools::Itertools; pub struct Barbs { base_incr: Transform, @@ -372,10 +373,9 @@ pub struct NestedSpiral { base: Vec, verts: Vec, faces: Vec, - seeds: Vec>, - incr: Vec, } +// TODO: Add original mesh as a conditional impl NestedSpiral { pub fn new() -> NestedSpiral { // 'Base' vertices, used throughout: @@ -390,61 +390,76 @@ impl NestedSpiral { // TODO: Subdivide vertices down (Python version goes from 4 // verts up to 16 by subdividing twice) - let rot_y = |ang| id().rotate(&Vector3::y_axis(), ang); - let rot_y_and_trans = |ang, dx| rot_y(ang).translate(dx, 0.0, 0.0); - - - let get_xform = |i, j, k| { - let i0 = PI*2.0*(i as f32) / 4.0; - let j0 = PI*2.0*(j as f32) / 4.0; - let k0 = PI*2.0*(k as f32) / 4.0; - // Pairs of (seed transform, incremental transform): - vec![ - id(), - rot_y_and_trans(i0, 3.0), - rot_y_and_trans(j0, 1.0), - rot_y_and_trans(k0, 0.5), - ] - // TODO: Does it make sense that this should be the reverse of the Python ones? - }; - - let mut seeds = vec![]; - for i in 0..4 { - for j in 0..4 { - for k in 0..4 { - seeds.push(get_xform(i, j, k)); - } - } - } - - let incr = vec![ - id().translate(0.0, 0.1, 0.0), - rot_y(-0.03), - rot_y(0.07), - rot_y(-0.2), - ]; - // TODO: This is kludgy (having it separate 'incremental' and 'seed' - // transformations) - NestedSpiral { base: base, verts: vec![], faces: vec![], - incr: incr, - seeds: seeds, } } - pub fn iter(&mut self, count: usize, b: [usize; 4], xforms: &Vec) { + pub fn run(mut self) -> Mesh { - if count <= 0 { - self.faces.extend_from_slice(&[b[0], b[2], b[1], b[0], b[3], b[2]]); - return; + //let mut rng = rand::thread_rng(); + + let rot_y = |ang| id().rotate(&Vector3::y_axis(), ang); + let rot_y_and_trans = |ang, dx| rot_y(ang).translate(dx, 0.0, 0.0); + + // The inner-most tuples are: (seed transform, incremental transform) + let xforms: Vec> = vec![ + (0..1).map(|_| { + (id(), id().translate(0.0, 0.1, 0.0).scale(0.995)) + }).collect(), + (0..2).map(|i| { + (rot_y_and_trans(PI*2.0*(i as f32) / 2.0, 5.0), rot_y(0.02)) + }).collect(), + (0..4).map(|i| { + (rot_y_and_trans(PI*2.0*(i as f32) / 4.0, 3.0), rot_y(-0.03)) + }).collect(), + (0..4).map(|i| { + (rot_y_and_trans(PI*2.0*(i as f32) / 4.0, 1.0), rot_y(0.07)) + }).collect(), + (0..4).map(|i| { + (rot_y_and_trans(PI*2.0*(i as f32) / 4.0, 0.5), rot_y(-0.2)) + }).collect(), + ]; + // Each inner vector here is a 'branching' transformation, so to + // flatten this, we need Cartesian product: + + for xform in xforms.iter().multi_cartesian_product() { + + let (seed, incr): (Vec, Vec) = xform.iter().map(|i| **i).unzip(); + // TODO: is it silly to un-zip this just to re-zip it in iter()? + + let global = seed.iter().fold(id(), |acc, m| acc * (*m)); + let g = global.transform(&self.base); + let (n0, _) = self.verts.append_indexed(g); + self.faces.extend_from_slice(&[n0, n0+1, n0+2, n0, n0+2, n0+3]); + + // let count: usize = rng.gen_range(500, 2500); + // Old effect: just set count to 500 + let count = 2000; + + self.iter(count, [n0, n0 + 1, n0 + 2, n0 + 3], &seed, &incr); } + return Mesh { + verts: self.verts, + faces: self.faces, + }; + } + + pub fn iter(&mut self, count: usize, b: [usize; 4], xforms: &Vec, incr: &Vec) { + // Compute global transform with product of all 'xforms': let global = xforms.iter().fold(id(), |acc, m| acc * (*m)); + // See if we should bail out here: + let (s, _, _) = global.get_scale(); + if s < 0.01 || count <= 0 { + self.faces.extend_from_slice(&[b[0], b[2], b[1], b[0], b[3], b[2]]); + return; + } + // Generate geometry: let g = global.transform(&self.base); let (n0, n1) = self.verts.append_indexed(g); @@ -452,33 +467,11 @@ impl NestedSpiral { // Increment the individual transformations: let xforms_next: Vec = xforms.iter() - .zip(self.incr.iter()) + .zip(incr.iter()) .map(|(m,incr)| ((*incr) * (*m))) .collect(); - self.iter(count - 1, [n0, n0 + 1, n0 + 2, n0 + 3], &xforms_next); + self.iter(count - 1, [n0, n0 + 1, n0 + 2, n0 + 3], &xforms_next, &incr); } - pub fn run(mut self) -> Mesh { - - let seeds = self.seeds.clone(); - let mut rng = rand::thread_rng(); - - for seed in seeds { - let global = seed.iter().fold(id(), |acc, m| acc * (*m)); - let g = global.transform(&self.base); - let (n0, _) = self.verts.append_indexed(g); - self.faces.extend_from_slice(&[n0, n0+1, n0+2, n0, n0+2, n0+3]); - - let count: usize = rng.gen_range(100, 500); - // Old effect: just set count to 500 - - self.iter(count, [n0, n0 + 1, n0 + 2, n0 + 3], &seed); - } - - return Mesh { - verts: self.verts, - faces: self.faces, - }; - } }