diff --git a/src/examples.rs b/src/examples.rs index 62411f1..7a3a3c0 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -50,6 +50,110 @@ pub fn cube_thing() -> Rule<()> { Rule { eval: Rc::new(rec), ctxt: () } } +#[derive(Clone)] +pub struct BarbsCtxt { + base_incr: Transform, + barb_incr: Transform, + sides: [Transform; 4], + base: Vec, + + verts: Vec, + faces: Vec, +} + +impl BarbsCtxt { + pub fn new() -> BarbsCtxt { + // Incremental transform from each stage to the next: + let base_incr = id().translate(0.0, 0.0, 1.0). + rotate(&Vector3::z_axis(), 0.15). + rotate(&Vector3::x_axis(), 0.1). + scale(0.95); + let barb_incr = id().translate(0.0, 0.0, 0.5). + rotate(&Vector3::y_axis(), -0.2). + scale(0.8); + // 'Base' vertices, used throughout: + let base = 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), + ]; + // sides[i] gives transformation from a 'base' layer to the + // i'th side (0 to 3): + let mut sides: [Transform; 4] = [id(); 4]; + for i in 0..4 { + sides[i] = id(). + rotate(&Vector3::z_axis(), -FRAC_PI_2 * (i as f32)). + rotate(&Vector3::y_axis(), -FRAC_PI_2). + translate(0.5, 0.0, 0.5);// * barb_incr; + } + BarbsCtxt { + base_incr: base_incr, + barb_incr: barb_incr, + base: base, + sides: sides, + verts: vec![], + faces: vec![], + } + } + + pub fn barb(&mut self, iters: usize, xform: Transform, bound: [usize; 4]) { + + if iters <= 0 { + self.faces.extend_from_slice(&[ + bound[0], bound[2], bound[1], + bound[0], bound[3], bound[2], + ]); + return; + } + + let xform2 = xform * self.barb_incr; + let g = xform2.transform(&self.base); + let (a0, a1) = self.verts.append_indexed(g); + + self.faces.append(&mut util::parallel_zigzag2(bound.to_vec(), a0..a1)); + + self.barb(iters - 1, xform2, [a0, a0+1, a0+2, a0+3]); + } + + pub fn main(&mut self, iters: usize, xform: Transform, bound: [usize; 4]) { + + if iters <= 0 { + self.faces.extend_from_slice(&[ + bound[0], bound[2], bound[1], + bound[0], bound[3], bound[2], + ]); + return; + } + + let xform2 = xform * self.base_incr; + let g = xform2.transform(&self.base); + let (a0, _) = self.verts.append_indexed(g); + + // TODO: Isn't there some cleaner way? + self.main(iters - 1, xform2, [a0, a0+1, a0+2, a0+3]); + self.barb(iters - 1, xform * self.sides[0], [bound[0], bound[1], a0+1, a0+0]); + self.barb(iters - 1, xform * self.sides[1], [bound[1], bound[2], a0+2, a0+1]); + self.barb(iters - 1, xform * self.sides[2], [bound[2], bound[3], a0+3, a0+2]); + self.barb(iters - 1, xform * self.sides[3], [bound[3], bound[0], a0+0, a0+3]); + } + + pub fn run(mut self, iters: usize) -> Mesh { + self.verts.append(&mut self.base.clone()); + self.faces.extend_from_slice(&[ + 0, 1, 2, + 0, 2, 3, + ]); + + self.main(iters, id(), [0,1,2,3]); + + return Mesh { + verts: self.verts, + faces: self.faces, + } + } +} + pub fn barbs(random: bool) -> Rule<()> { let (b0, bn); diff --git a/src/lib.rs b/src/lib.rs index 5414672..01451b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,6 +76,21 @@ mod tests { #[test] fn barbs() { run_test(examples::barbs(false), 80, "barbs", false); } + #[test] + fn barbs_direct() { + let name = "barbs_test"; + println!("---------------------------------------------------"); + let b = examples::BarbsCtxt::new(); + let m = b.run(100); + + println!("Got {} verts...", m.verts.len()); + + let fname = format!("{}.stl", name); + println!("Writing {}...", fname); + m.write_stl_file(&fname).unwrap(); + + } + #[test] fn barbs_random() { run_test(examples::barbs(true), 80, "barbs_random", false); } diff --git a/src/mesh.rs b/src/mesh.rs index add220d..844a4ff 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -217,7 +217,12 @@ impl MeshFunc { faces.extend(child.faces.iter().map(|n| { let f = match child.verts[*n] { VertexUnion::Vertex(_) => remap[*n], - VertexUnion::Arg(m) => arg_vals[m], + VertexUnion::Arg(m) => { + println!("remap face: vert {} arg {} = vert {} ({:?})", + *n, m, arg_vals[m], verts[arg_vals[m]] + ); + arg_vals[m] + }, }; if f >= verts.len() { panic!("face >= num_verts") diff --git a/src/util.rs b/src/util.rs index 9e16adb..efb22df 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,5 +1,5 @@ use std::ops::Range; -use crate::mesh::{MeshFunc, VertexUnion}; +use crate::mesh::{Mesh, MeshFunc, VertexUnion}; use crate::xform::{Vertex}; /// This is like `vec!`, but it can handle elements that are given @@ -85,6 +85,35 @@ pub fn parallel_zigzag(verts: Vec, main: Range, parent: Rang } } +pub fn parallel_zigzag_mesh(verts: Vec, main: Range, parent: Range) -> Mesh { + Mesh { + verts: verts, + faces: parallel_zigzag_faces(main, parent), + } +} + +pub fn parallel_zigzag2(main: T, parent: U) -> Vec +where T: IntoIterator, U: IntoIterator +{ + let m: Vec = main.into_iter().collect(); + let p: Vec = parent.into_iter().collect(); + let l = m.len(); + if l != p.len() { + panic!("Vectors must be the same size!") + } + + (0..l).map(|i0| { + // i0 is an *offset* for the 'current' index. + // i1 is for the 'next' index, wrapping back to 0. + let i1 = (i0 + 1) % l; + vec![ + // Mind winding order! + m[i1], p[i0], m[i0], + p[i1], p[i0], m[i1], + ] + }).flatten().collect() +} + pub fn centroid(verts: &Vec) -> Vertex { let n = verts.len(); let mut centroid = Vertex::new(0.0, 0.0, 0.0, 0.0);