diff --git a/src/examples.rs b/src/examples.rs index a9b05aa..611065c 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -4,7 +4,8 @@ use nalgebra::*; use rand::Rng; use crate::util; -use crate::mesh::{Mesh, MeshTemplate}; +use crate::util::VecExt; +use crate::mesh::{Mesh, MeshFunc, VertexUnion}; use crate::xform::{Transform, Vertex, vertex, Mat4}; use crate::rule::{Rule, RuleFn, RuleEval, Child}; use crate::prim; @@ -45,15 +46,16 @@ pub fn cube_thing() -> Rule<()> { Rule { eval: Rc::new(rec), ctxt: () } } +*/ pub fn barbs() -> Rule<()> { - let (a0, a1); - let base_verts: Vec = vec_indexed![ - @a0: vertex(-0.5, -0.5, 0.0), - vertex(-0.5, 0.5, 0.0), - vertex( 0.5, 0.5, 0.0), - @a1: vertex( 0.5, -0.5, 0.0), + let (b0, b1); + let base_verts: Vec = vec_indexed![ + @b0: VertexUnion::Vertex(vertex(-0.5, -0.5, 0.0)), + VertexUnion::Vertex(vertex(-0.5, 0.5, 0.0)), + VertexUnion::Vertex(vertex( 0.5, 0.5, 0.0)), + @b1: VertexUnion::Vertex(vertex( 0.5, -0.5, 0.0)), ]; let n = base_verts.len(); @@ -64,19 +66,24 @@ pub fn barbs() -> Rule<()> { let b = base_verts.clone(); let barb = move |self_: Rc>| -> RuleEval<()> { - let next_verts = incr.transform(&b); + let mut next_verts = b.clone(); + let (a0, a1) = next_verts.append_indexed( + &mut (0..4).map(|i| VertexUnion::Arg(i)).collect() + ); - let geom = Rc::new(util::zigzag_to_parent(next_verts.clone(), a0..a1)); - let (vc, faces) = util::connect_convex(&next_verts, true); + + let geom = util::parallel_zigzag(next_verts.clone(), b0..b1, a0..a1); + /*let (vc, faces) = util::connect_convex(&next_verts, true); let final_geom = Rc::new(OpenMesh { verts: vec![vc], alias_verts: vec![], faces: faces, }); + */ RuleEval { - geom: geom, - final_geom: final_geom, + geom: Rc::new(geom.transform(&incr)), + final_geom: Rc::new(prim::empty_meshfunc()), // TODO children: vec![ Child { rule: self_.clone(), @@ -89,20 +96,24 @@ pub fn barbs() -> Rule<()> { let b = base_verts.clone(); let main = move |self_: Rc>| -> RuleEval<()> { - let next_verts = incr.transform(&b); + let mut next_verts = b.clone(); + let (a0, a1) = next_verts.append_indexed( + &mut (0..4).map(|i| VertexUnion::Arg(i)).collect() + ); // TODO: Once I start doing the barbs this will go away - let geom = Rc::new(util::zigzag_to_parent(next_verts.clone(), n)); + let geom = util::parallel_zigzag(next_verts.clone(), b0..b1+1, a0..a1); + /* let (vc, faces) = util::connect_convex(&next_verts, true); - let final_geom = Rc::new(OpenMesh { + let final_geom = Rc::new(MeshFunc { verts: vec![vc], - alias_verts: vec![], faces: faces, }); + */ RuleEval { - geom: geom, - final_geom: final_geom, + geom: Rc::new(geom.transform(&incr)), + final_geom: Rc::new(prim::empty_meshfunc()), // TODO children: vec![ Child { rule: self_.clone(), @@ -116,15 +127,14 @@ pub fn barbs() -> Rule<()> { let main_ = Rc::new(main); let base = move |self_: Rc>| -> RuleEval<()> { RuleEval { - geom: Rc::new(OpenMesh { + geom: Rc::new(MeshFunc { verts: base_verts.clone(), - alias_verts: vec![], faces: vec![ - 0, 1, 2, - 0, 1, 3, + b0, b0 + 1, b0 + 2, + b0, b0 + 2, b0 + 3, ], }), - final_geom: Rc::new(prim::empty_mesh()), + final_geom: Rc::new(prim::empty_meshfunc()), children: vec![ Child { rule: Rc::new(Rule { eval: main_.clone(), ctxt: () }), @@ -138,6 +148,7 @@ pub fn barbs() -> Rule<()> { Rule { eval: Rc::new(base), ctxt: () } } +/* // Meant to be a copy of twist_from_gen from Python & // automata_scratch, but has since acquired a sort of life of its own pub fn twist(f: f32, subdiv: usize) -> Rule<()> { diff --git a/src/lib.rs b/src/lib.rs index 691f6fa..6ff56dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,7 +36,7 @@ mod tests { println!("Evaluated {} rules to {} verts", nodes, mesh.verts.len()); let fname = format!("{}.stl", name); println!("Writing {}...", fname); - mesh.write_stl_file(&fname).unwrap(); + mesh.to_mesh().write_stl_file(&fname).unwrap(); } #[test] @@ -71,10 +71,12 @@ mod tests { fn cube_thing() { run_test(examples::cube_thing(), 3, "cube_thing3", false); } + */ #[test] fn barbs() { run_test(examples::barbs(), 20, "barbs", false); } + /* #[test] fn twist() { run_test(examples::twist(1.0, 2), 200, "screw", false); diff --git a/src/mesh.rs b/src/mesh.rs index 0e4ca28..ac8c3f2 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -42,9 +42,9 @@ impl Mesh { // Turn every face into an stl_io::Triangle: for i in 0..num_faces { - let v0 = self.verts[3*i + 0].xyz(); - let v1 = self.verts[3*i + 1].xyz(); - let v2 = self.verts[3*i + 2].xyz(); + let v0 = self.verts[self.faces[3*i + 0]].xyz(); + let v1 = self.verts[self.faces[3*i + 1]].xyz(); + let v2 = self.verts[self.faces[3*i + 2]].xyz(); let normal = (v1-v0).cross(&(v2-v0)); @@ -62,8 +62,8 @@ impl Mesh { stl_io::write_stl(writer, triangles.iter()) } - fn to_template(&self) -> MeshTemplate { - MeshTemplate { + fn to_meshfunc(&self) -> MeshFunc { + MeshFunc { faces: self.faces.clone(), verts: self.verts.iter().map(|v| VertexUnion::Vertex(*v)).collect(), } @@ -72,10 +72,11 @@ impl Mesh { #[derive(Clone, Debug)] pub enum VertexUnion { - /// A concrete vertex + /// A concrete vertex. Vertex(Vertex), - /// An alias to some other vertex (by index) - Alias(usize), + /// An 'unbound' vertex - something like an argument to a function with + /// the given positional index. + Arg(usize), } /// A face-vertex mesh whose vertices can either be concrete values @@ -84,7 +85,7 @@ pub enum VertexUnion { /// aliases are resolved to concrete vertices with a call like /// `connect()`. #[derive(Clone, Debug)] -pub struct MeshTemplate { +pub struct MeshFunc { // pub verts: Vec, /// Indices of triangles (taken as every 3 values). Indices begin @@ -95,11 +96,21 @@ pub struct MeshTemplate { pub faces: Vec, } -impl MeshTemplate { +impl MeshFunc { - /// Returns a new `MeshTemplate` whose concrete vertices have + pub fn to_mesh(&self) -> Mesh { + Mesh { + faces: self.faces.clone(), + verts: self.verts.iter().map(|v| match *v { + VertexUnion::Vertex(v) => v, + VertexUnion::Arg(_) => panic!("Mesh still has vertex arguments!"), + }).collect(), + } + } + + /// Returns a new `MeshFunc` whose concrete vertices have /// been transformed. Note that alias vertices are left untouched. - pub fn transform(&self, xfm: &Transform) -> MeshTemplate { + pub fn transform(&self, xfm: &Transform) -> MeshFunc { let v = self.verts.iter().map(|v| { match v { VertexUnion::Vertex(v) => VertexUnion::Vertex(xfm.mtx * v), @@ -107,7 +118,7 @@ impl MeshTemplate { } }); - MeshTemplate { + MeshFunc { verts: v.collect(), faces: self.faces.clone(), } @@ -118,8 +129,8 @@ impl MeshTemplate { /// corresponding input mesh was shifted. That is, for the i'th /// index in `meshes`, all of its triangle indices were shifted by /// the i'th offset in the resultant mesh. - pub fn append(meshes: T) -> (MeshTemplate, Vec) - where U: Borrow, + pub fn append(meshes: T) -> (MeshFunc, Vec) + where U: Borrow, T: IntoIterator { let mut offsets: Vec = vec![]; @@ -139,7 +150,7 @@ impl MeshTemplate { f.extend(mesh.faces.iter().map(|n| n + offset)); } - (MeshTemplate { verts: v, faces: f }, offsets) + (MeshFunc { verts: v, faces: f }, offsets) } /// Treat this mesh as a 'parent' mesh to connect with any number @@ -151,8 +162,8 @@ impl MeshTemplate { /// That is, the vertices of 'children[i]' begin at vertex /// 'offset[i]' of the new mesh. This is needed in some cases for /// adjusting a parent vertex mapping, like 'vmap' of Rule::Child. - pub fn connect(&self, children: T) -> (MeshTemplate, Vec) - where U: Borrow, + pub fn connect(&self, children: T) -> (MeshFunc, Vec) + where U: Borrow, T: IntoIterator)> //pub fn connect(&self, children: &Vec<(OpenMesh, Vec)>) -> (OpenMesh, Vec) { @@ -178,7 +189,7 @@ impl MeshTemplate { verts.extend(child.verts.iter().filter_map(|v| { match v { VertexUnion::Vertex(_) => Some(v.clone()), - VertexUnion::Alias(_) => None, + VertexUnion::Arg(_) => None, } })); @@ -188,14 +199,14 @@ impl MeshTemplate { faces.extend(child.faces.iter().map(|n| match child.verts[*n] { VertexUnion::Vertex(_) => n + offset, - VertexUnion::Alias(m) => mapping[m], + VertexUnion::Arg(m) => mapping[m], } )); offsets.push(offset); } - let m = MeshTemplate { + let m = MeshFunc { verts: verts, faces: faces, }; diff --git a/src/prim.rs b/src/prim.rs index e8e2f1d..b34b530 100644 --- a/src/prim.rs +++ b/src/prim.rs @@ -1,4 +1,4 @@ -use crate::mesh::{Mesh}; +use crate::mesh::{Mesh, MeshFunc}; use crate::xform::{vertex, Transform}; /// Returns an empty mesh (no vertices, no faces). @@ -9,6 +9,14 @@ pub fn empty_mesh() -> Mesh { } } +/// Returns an empty MeshFn (no vertices, no faces, thus no args). +pub fn empty_meshfunc() -> MeshFunc { + MeshFunc { + verts: vec![], + faces: vec![], + } +} + /// Returns a cube of sidelength one centered at (0,0,0). pub fn cube() -> Mesh { Mesh { diff --git a/src/rule.rs b/src/rule.rs index c7fd957..c26e6a2 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -1,4 +1,4 @@ -use crate::mesh::{MeshTemplate, VertexUnion}; +use crate::mesh::{MeshFunc, VertexUnion}; use crate::xform::{Transform}; //use crate::prim; use std::borrow::Borrow; @@ -38,7 +38,7 @@ pub struct Rule { /// `geom`. pub struct RuleEval { /// The geometry generated at just this iteration - pub geom: Rc, + pub geom: Rc, /// The "final" geometry that is merged with `geom` via /// `connect()` in the event that recursion stops. This must be @@ -46,7 +46,7 @@ pub struct RuleEval { /// /// Parent vertex references will be resolved directly to `geom` /// with no mapping. - pub final_geom: Rc, + pub final_geom: Rc, /// The child invocations (used if recursion continues). The /// 'parent' mesh, from the perspective of all geometry produced @@ -69,7 +69,7 @@ pub struct Child { /// The parent vertex mapping: a mapping to apply to turn a /// Tag::Parent vertex reference into a vertex index of the parent - /// mesh. That is, if `rule` produces a `MeshTemplate` with a face + /// mesh. That is, if `rule` produces a `MeshFunc` with a face /// of `Tag::Parent(n)`, this will correspond to index `vmap[n]` /// in the parent mesh. pub vmap: Vec, @@ -80,7 +80,7 @@ impl Rule { /// 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(s: Rc>, iters_left: usize) -> (MeshTemplate, usize) { + pub fn to_mesh(s: Rc>, iters_left: usize) -> (MeshFunc, usize) { let mut evals = 1; @@ -95,7 +95,7 @@ impl Rule { // TODO: This logic is more or less right, but it // could perhaps use some un-tupling or something. - let subgeom: Vec<(MeshTemplate, Vec)> = rs.children.iter().map(|sub| { + let subgeom: Vec<(MeshFunc, Vec)> = rs.children.iter().map(|sub| { // Get sub-geometry (still un-transformed): let (submesh, eval) = Rule::to_mesh(sub.rule.clone(), iters_left - 1); // Tally up eval count: @@ -114,7 +114,7 @@ impl Rule { /// This should be identical to to_mesh, but implemented /// iteratively with an explicit stack rather than with recursive /// function calls. - pub fn to_mesh_iter(s: Rc>, max_depth: usize) -> (MeshTemplate, usize) { + pub fn to_mesh_iter(s: Rc>, max_depth: usize) -> (MeshFunc, usize) { struct State { // The set of rules we're currently handling: @@ -187,7 +187,7 @@ impl Rule { let mut m_ = 0; for v in &final_geom.verts { match *v { - VertexUnion::Alias(a) => { + VertexUnion::Arg(a) => { if a > m_ { m_ = a; } @@ -262,17 +262,17 @@ impl Rule { } impl RuleEval { - /// Turn an iterator of (MeshTemplate, Child) into a single RuleEval. + /// Turn an iterator of (MeshFunc, Child) into a single RuleEval. /// All meshes are merged, and the `vmap` in each child has the /// correct offsets applied to account for this merge. /// /// (`final_geom` is passed through to the RuleEval unmodified.) - pub fn from_pairs(m: T, final_geom: MeshTemplate) -> RuleEval - where U: Borrow, + pub fn from_pairs(m: T, final_geom: MeshFunc) -> RuleEval + where U: Borrow, T: IntoIterator)> { let (meshes, children): (Vec<_>, Vec<_>) = m.into_iter().unzip(); - let (mesh, offsets) = MeshTemplate::append(meshes); + let (mesh, offsets) = MeshFunc::append(meshes); // Patch up vmap in each child, and copy everything else: let children2: Vec> = children.iter().zip(offsets.iter()).map(|(c,off)| { diff --git a/src/util.rs b/src/util.rs index 1839f90..2bd933a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,5 +1,5 @@ use std::ops::Range; -use crate::mesh::{Mesh, MeshTemplate, VertexUnion}; +use crate::mesh::{Mesh, MeshFunc, VertexUnion}; use crate::xform::{Vertex}; //use crate::rule::{Rule, Child}; @@ -19,6 +19,21 @@ macro_rules! vec_indexed { }}; } +pub trait VecExt { + fn append_indexed(&mut self, other: &mut Vec) -> (usize, usize); +} + +impl VecExt for Vec { + // Like `append`, but returning `(a, b)` which give the range of + // elements just inserted. + fn append_indexed(&mut self, other: &mut Vec) -> (usize, usize) { + let a = self.len(); + self.append(other); + let b = self.len(); + (a, b) + } +} + /// Linearly subdivides a list of points that are to be treated as a /// cycle. This produces 'count' points for every element of 'p' /// (thus, the returned length will be `count*p.len()`). @@ -60,8 +75,8 @@ pub fn parallel_zigzag_faces(r1: Range, r2: Range) -> Vec { }).flatten().collect() } -pub fn zigzag_to_parent(verts: Vec, main: Range, parent: Range) -> MeshTemplate { - MeshTemplate { +pub fn parallel_zigzag(verts: Vec, main: Range, parent: Range) -> MeshFunc { + MeshFunc { verts: verts, faces: parallel_zigzag_faces(main, parent), }