From 7626f1a089b492b35500562bf292baf254e2a54d Mon Sep 17 00:00:00 2001 From: Chris Hodapp Date: Tue, 12 May 2020 15:46:03 -0400 Subject: [PATCH] Mesh stuff ugly-refactored but untested --- src/examples.rs | 168 ++++++++++++++++------------- src/lib.rs | 9 +- src/{openmesh.rs => mesh.rs} | 203 ++++++++++++++++++++--------------- src/prim.rs | 34 +++--- src/rule.rs | 36 +++---- src/util.rs | 81 +++++++++----- 6 files changed, 306 insertions(+), 225 deletions(-) rename src/{openmesh.rs => mesh.rs} (53%) diff --git a/src/examples.rs b/src/examples.rs index c060386..a9b05aa 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -1,14 +1,15 @@ use std::rc::Rc; + use nalgebra::*; use rand::Rng; -//pub mod examples; -use crate::openmesh::{OpenMesh, Tag}; -use crate::xform::{Transform, vertex, Mat4}; +use crate::util; +use crate::mesh::{Mesh, MeshTemplate}; +use crate::xform::{Transform, Vertex, vertex, Mat4}; use crate::rule::{Rule, RuleFn, RuleEval, Child}; use crate::prim; -use crate::util; +/* pub fn cube_thing() -> Rule<()> { // Quarter-turn in radians: @@ -47,11 +48,12 @@ pub fn cube_thing() -> Rule<()> { pub fn barbs() -> Rule<()> { - let base_verts = vec![ - vertex(-0.5, -0.5, 0.0), + 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), - vertex( 0.5, -0.5, 0.0), + @a1: vertex( 0.5, -0.5, 0.0), ]; let n = base_verts.len(); @@ -64,10 +66,11 @@ pub fn barbs() -> Rule<()> { let barb = move |self_: Rc>| -> RuleEval<()> { let next_verts = incr.transform(&b); - let geom = Rc::new(util::zigzag_to_parent(next_verts.clone(), n)); + let geom = Rc::new(util::zigzag_to_parent(next_verts.clone(), 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, }); @@ -93,6 +96,7 @@ pub fn barbs() -> Rule<()> { let (vc, faces) = util::connect_convex(&next_verts, true); let final_geom = Rc::new(OpenMesh { verts: vec![vc], + alias_verts: vec![], faces: faces, }); @@ -114,9 +118,10 @@ pub fn barbs() -> Rule<()> { RuleEval { geom: Rc::new(OpenMesh { verts: base_verts.clone(), + alias_verts: vec![], faces: vec![ - Tag::Body(0), Tag::Body(1), Tag::Body(2), - Tag::Body(0), Tag::Body(2), Tag::Body(3), + 0, 1, 2, + 0, 1, 3, ], }), final_geom: Rc::new(prim::empty_mesh()), @@ -173,6 +178,7 @@ pub fn twist(f: f32, subdiv: usize) -> Rule<()> { let (vc, faces) = util::connect_convex(&seed_next, true); let final_geom = Rc::new(OpenMesh { verts: vec![vc], + alias_verts: vec![], faces: faces, }); @@ -212,7 +218,7 @@ pub fn twist(f: f32, subdiv: usize) -> Rule<()> { // and in the process, generate faces for these seeds: let (centroid, f) = util::connect_convex(&vs, false); vs.push(centroid); - (OpenMesh { verts: vs, faces: f }, c) + (OpenMesh { verts: vs, faces: f, alias_verts: vec![] }, c) }; // Generate 'count' children, shifted/rotated differently: @@ -247,6 +253,7 @@ pub fn nest_spiral_2() -> Rule { let (vc, faces) = util::connect_convex(&seed, true); let final_geom = Rc::new(OpenMesh { verts: vec![vc], + alias_verts: vec![], faces: faces, }); @@ -276,7 +283,7 @@ pub fn nest_spiral_2() -> Rule { let (centroid, f) = util::connect_convex(&s2, false); s2.push(centroid); let n2 = s2.len(); - let g = OpenMesh { verts: s2, faces: f }; + let g = OpenMesh { verts: s2, faces: f, alias_verts: vec![] }; RuleEval { geom: Rc::new(g.transform(&xf)), final_geom: Rc::new(prim::empty_mesh()), @@ -369,6 +376,7 @@ pub fn twisty_torus() -> Rule { let (vc, faces) = util::connect_convex(&seed, true); let final_geom = Rc::new(OpenMesh { verts: vec![vc], + alias_verts: (0..(n+1)).collect(), faces: faces, }); @@ -404,7 +412,7 @@ pub fn twisty_torus() -> Rule { let (centroid, f) = util::connect_convex(&s2, false); s2.push(centroid); let n2 = s2.len(); - let g = OpenMesh { verts: s2, faces: f }; + let g = OpenMesh { verts: s2, faces: f, alias_verts: vec![] }; RuleEval { geom: Rc::new(g.transform(&xf)), final_geom: Rc::new(prim::empty_mesh()), @@ -469,6 +477,7 @@ pub fn twisty_torus_hardcode() -> Rule<()> { let (vc, faces) = util::connect_convex(&next, true); let final_geom = Rc::new(OpenMesh { verts: vec![vc], + alias_verts: (0..(n+1)).collect(), // TODO: Fix parent/connect_convex faces: faces, }); @@ -497,7 +506,7 @@ pub fn twisty_torus_hardcode() -> Rule<()> { let (centroid, f) = util::connect_convex(&s2, false); s2.push(centroid); let n2 = s2.len(); - let g = OpenMesh { verts: s2, faces: f }; + let g = OpenMesh { verts: s2, faces: f, alias_verts: vec![] }; RuleEval { geom: Rc::new(g.transform(&xf)), final_geom: Rc::new(prim::empty_mesh()), @@ -540,6 +549,7 @@ pub fn wind_chime_mistake_thing() -> Rule { let (vc, faces) = util::connect_convex(&seed, true); let final_geom = Rc::new(OpenMesh { verts: vec![vc], + alias_verts: (0..(n + 1)).collect(), // TODO: Check with parents (zigzag/connect_convex) faces: faces, }); @@ -572,7 +582,7 @@ pub fn wind_chime_mistake_thing() -> Rule { let (centroid, f) = util::connect_convex(&s2, false); s2.push(centroid); let n2 = s2.len(); - let g = OpenMesh { verts: s2, faces: f }; + let g = OpenMesh { verts: s2, faces: f, alias_verts: vec![] }; RuleEval { geom: Rc::new(g.transform(&xf)), final_geom: Rc::new(prim::empty_mesh()), @@ -629,23 +639,25 @@ pub fn ramhorn() -> Rule<()> { ]; let next = incr.transform(&seed); let geom = Rc::new(OpenMesh { + alias_verts: vec![0, 1, 2, 3], 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), + 5, 0, 4, + 1, 0, 5, + 6, 1, 5, + 2, 1, 6, + 7, 2, 6, + 3, 2, 7, + 4, 3, 7, + 0, 3, 4, ], }); let final_geom = Rc::new(OpenMesh { verts: vec![], + alias_verts: vec![0, 1, 2, 3], faces: vec![ - Tag::Parent(0), Tag::Parent(2), Tag::Parent(1), - Tag::Parent(0), Tag::Parent(3), Tag::Parent(2), + 0, 2, 1, + 0, 3, 2, ], }); @@ -695,27 +707,28 @@ pub fn ramhorn() -> Rule<()> { vertex( 0.5, 0.5, 0.0), // 11 vertex( 0.5, -0.5, 0.0), // 12 ], + alias_verts: vec![], faces: vec![ // bottom face: - Tag::Body(9), Tag::Body(10), Tag::Body(11), - Tag::Body(9), Tag::Body(11), Tag::Body(12), + 9, 10, 11, + 9, 11, 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), + 9, 0, 4, + 9, 7, 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), + 10, 1, 5, + 10, 4, 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), + 11, 2, 6, + 11, 5, 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), + 12, 3, 7, + 12, 6, 3, + // four faces from edge (0,1, (1,2, (2,3, (3,0): + 9, 4, 10, + 10, 5, 11, + 11, 6, 12, + 12, 7, 9, ], }), final_geom: Rc::new(prim::empty_mesh()), @@ -772,13 +785,16 @@ pub fn ramhorn_branch(depth: usize, f: f32) -> Rule { let next = incr.transform(&seed); let geom = Rc::new(OpenMesh { verts: next, + alias_verts: vec![], faces: util::parallel_zigzag_faces(4), + // TODO: Fix this (parallel_zigzag_faces has parents) }); let final_geom = Rc::new(OpenMesh { verts: vec![], + alias_verts: vec![0, 1, 2, 3], faces: vec![ - Tag::Parent(0), Tag::Parent(2), Tag::Parent(1), - Tag::Parent(0), Tag::Parent(3), Tag::Parent(2), + 0, 2, 1, + 0, 3, 2, ], }); @@ -807,24 +823,25 @@ pub fn ramhorn_branch(depth: usize, f: f32) -> Rule { ]; let trans_faces = vec![ // two faces straddling edge from vertex 0: - Tag::Parent(0), Tag::Body(0), Tag::Body(4), - Tag::Parent(0), Tag::Body(7), Tag::Body(0), + 0, 4, 8, + 0, 11, 4, // two faces straddling edge from vertex 1: - Tag::Parent(1), Tag::Body(1), Tag::Body(5), - Tag::Parent(1), Tag::Body(4), Tag::Body(1), + 1, 5, 9, + 1, 8, 5, // two faces straddling edge from vertex 2: - Tag::Parent(2), Tag::Body(2), Tag::Body(6), - Tag::Parent(2), Tag::Body(5), Tag::Body(2), + 2, 6, 10, + 2, 9, 6, // two faces straddling edge from vertex 3: - Tag::Parent(3), Tag::Body(3), Tag::Body(7), - Tag::Parent(3), Tag::Body(6), Tag::Body(3), + 3, 7, 11, + 3, 10, 7, // four faces from edge (0,1), (1,2), (2,3), (3,0): - Tag::Parent(0), Tag::Body(4), Tag::Parent(1), - Tag::Parent(1), Tag::Body(5), Tag::Parent(2), - Tag::Parent(2), Tag::Body(6), Tag::Parent(3), - Tag::Parent(3), Tag::Body(7), Tag::Parent(0), + 0, 8, 1, + 1, 9, 2, + 2, 10, 3, + 3, 11, 0, ]; let trans_geom = Rc::new(OpenMesh { + alias_verts: vec![0, 1, 2, 3], verts: trans_verts.clone(), faces: trans_faces.clone(), }); @@ -899,9 +916,10 @@ pub fn ramhorn_branch(depth: usize, f: f32) -> Rule { RuleEval { geom: Rc::new(OpenMesh { verts: Transform::new().translate(0.0, 0.0, -0.5).transform(&seed), + alias_verts: vec![], faces: vec![ - Tag::Body(0), Tag::Body(1), Tag::Body(2), - Tag::Body(0), Tag::Body(2), Tag::Body(3), + 0, 1, 2, + 0, 2, 3, ], }), final_geom: Rc::new(prim::empty_mesh()), @@ -941,12 +959,15 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule { let geom = Rc::new(OpenMesh { verts: next, faces: util::parallel_zigzag_faces(4), + alias_verts: vec![], + // TODO: Fix parents with parallel_zigzag }); let final_geom = Rc::new(OpenMesh { verts: vec![], + alias_verts: vec![0, 1, 2, 3], faces: vec![ - Tag::Parent(0), Tag::Parent(2), Tag::Parent(1), - Tag::Parent(0), Tag::Parent(3), Tag::Parent(2), + 0, 2, 1, + 0, 3, 2, ], }); @@ -975,24 +996,25 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule { ]; let trans_faces = vec![ // two faces straddling edge from vertex 0: - Tag::Parent(0), Tag::Body(0), Tag::Body(4), - Tag::Parent(0), Tag::Body(7), Tag::Body(0), + 0, 4, 8, + 0, 11, 4, // two faces straddling edge from vertex 1: - Tag::Parent(1), Tag::Body(1), Tag::Body(5), - Tag::Parent(1), Tag::Body(4), Tag::Body(1), + 1, 5, 9, + 1, 8, 5, // two faces straddling edge from vertex 2: - Tag::Parent(2), Tag::Body(2), Tag::Body(6), - Tag::Parent(2), Tag::Body(5), Tag::Body(2), + 2, 6, 10, + 2, 9, 6, // two faces straddling edge from vertex 3: - Tag::Parent(3), Tag::Body(3), Tag::Body(7), - Tag::Parent(3), Tag::Body(6), Tag::Body(3), + 3, 7, 11, + 3, 10, 7, // four faces from edge (0,1), (1,2), (2,3), (3,0): - Tag::Parent(0), Tag::Body(4), Tag::Parent(1), - Tag::Parent(1), Tag::Body(5), Tag::Parent(2), - Tag::Parent(2), Tag::Body(6), Tag::Parent(3), - Tag::Parent(3), Tag::Body(7), Tag::Parent(0), + 0, 8, 1, + 1, 9, 2, + 2, 10, 3, + 3, 11, 0, ]; let trans_geom = Rc::new(OpenMesh { + alias_verts: vec![0, 1, 2, 3], verts: trans_verts.clone(), faces: trans_faces.clone(), }); @@ -1068,9 +1090,10 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule { RuleEval { geom: Rc::new(OpenMesh { verts: Transform::new().translate(0.0, 0.0, -0.5).transform(&seed), + alias_verts: vec![], faces: vec![ - Tag::Body(0), Tag::Body(1), Tag::Body(2), - Tag::Body(0), Tag::Body(2), Tag::Body(3), + 0, 1, 2, + 0, 2, 3, ], }), final_geom: Rc::new(prim::empty_mesh()), @@ -1086,6 +1109,7 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule { Rule { eval: Rc::new(start), ctxt: RamHornCtxt2 { depth } } } + */ /* #[derive(Copy, Clone)] diff --git a/src/lib.rs b/src/lib.rs index d62cabb..691f6fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,10 @@ -pub mod examples; -pub mod openmesh; +pub mod mesh; pub mod rule; pub mod prim; +#[macro_use] pub mod util; pub mod xform; +pub mod examples; //pub use crate::examples; //pub use crate::openmesh::test_thing; @@ -62,7 +63,8 @@ mod tests { geom.transform(&(trans * rot)).write_stl_file("xform_mul_trans_rot.stl").unwrap(); geom.transform(&xf1).write_stl_file("xform_trans_rot.stl").unwrap(); } - + + /* // TODO: These tests don't test any conditions, so this is useful // short-hand to run, but not very meaningful as a test. #[test] @@ -127,6 +129,7 @@ mod tests { fn ramhorn_branch_random() { run_test(examples::ramhorn_branch_random(24, 0.25), 32, "ram_horn_branch_random", false); } + */ } // need this for now: // cargo test -- --nocapture diff --git a/src/openmesh.rs b/src/mesh.rs similarity index 53% rename from src/openmesh.rs rename to src/mesh.rs index 4a4a0c8..0e4ca28 100644 --- a/src/openmesh.rs +++ b/src/mesh.rs @@ -4,69 +4,18 @@ use std::borrow::Borrow; use crate::xform::{Vertex, Transform}; -/// A type for a 'tagged' vertex index referring either to an index of -/// a mesh, or of its parent. +/// Basic face-vertex mesh. `faces` contains indices of `verts` and is +/// taken in groups of 3 for each triangle. #[derive(Clone, Debug)] -pub enum Tag { - Body(usize), - Parent(usize), -} -// TODO: This is clumsy. Can I do this some other way, or at least -// phrase it better? - -/// A face-vertex mesh whose faces indices can refer either to its own -/// vertices, or to some 'parent' mesh. -#[derive(Clone, Debug)] -pub struct OpenMesh { - /// Vertices of mesh +pub struct Mesh { pub verts: Vec, - /// Indices of triangles (taken as every 3 values). `Tag::Body` - /// indices correspond to `verts`, while `Tag::Parent` indices - /// correspond to some parent mesh that must eventually be given - /// to complete this mesh. - pub faces: Vec, + pub faces: Vec, } -impl OpenMesh { - - /// Appends any number of meshes together. Returns both a single - /// mesh, and a vector which gives the offset by which each - /// 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) -> (OpenMesh, Vec) - where U: Borrow, - T: IntoIterator - { - let mut offsets: Vec = vec![]; - let mut v: Vec = vec![]; - let mut f: Vec = vec![]; - 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(); - offsets.push(offset); - - // Copy all vertices: - v.append(&mut mesh.verts.clone()); - // Append its faces, applying offset: - f.extend(mesh.faces.iter().map(|t| { - match t { - Tag::Body(n) => Tag::Body(n + offset), - Tag::Parent(_) => panic!("Cannot append() if mesh has parent references!"), - // TODO: Handle the above - } - })); - } - - (OpenMesh { verts: v, faces: f }, offsets) - } - - /// Returns a new `OpenMesh` whose vertices have been transformed. - pub fn transform(&self, xfm: &Transform) -> OpenMesh { - OpenMesh { +impl Mesh { + /// Returns a new `Mesh` whose vertices have been transformed. + pub fn transform(&self, xfm: &Transform) -> Mesh { + Mesh { verts: xfm.transform(&self.verts), // TODO: Is the above faster if I pack vectors into a // bigger matrix, and transform that? @@ -91,20 +40,12 @@ impl OpenMesh { vertices: [[0.0; 3]; 3], }; num_faces]; - let get_vert = |j| { - match self.faces[j] { - Tag::Body(n) => self.verts[n].xyz(), - Tag::Parent(_) => panic!("Cannot write_stl() if mesh has parent references!"), - } - }; - // TODO: Handle this behavior - // Turn every face into an stl_io::Triangle: for i in 0..num_faces { - let v0 = get_vert(3*i + 0); - let v1 = get_vert(3*i + 1); - let v2 = get_vert(3*i + 2); - + 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 normal = (v1-v0).cross(&(v2-v0)); triangles[i].normal.copy_from_slice(&normal.as_slice()); @@ -121,6 +62,86 @@ impl OpenMesh { stl_io::write_stl(writer, triangles.iter()) } + fn to_template(&self) -> MeshTemplate { + MeshTemplate { + faces: self.faces.clone(), + verts: self.verts.iter().map(|v| VertexUnion::Vertex(*v)).collect(), + } + } +} + +#[derive(Clone, Debug)] +pub enum VertexUnion { + /// A concrete vertex + Vertex(Vertex), + /// An alias to some other vertex (by index) + Alias(usize), +} + +/// A face-vertex mesh whose vertices can either be concrete values +/// (as in `Mesh`) or aliases (indices to other vertices of some +/// hypothetical mesh). This can be turned to `mesh` only if those +/// aliases are resolved to concrete vertices with a call like +/// `connect()`. +#[derive(Clone, Debug)] +pub struct MeshTemplate { + // + pub verts: Vec, + /// Indices of triangles (taken as every 3 values). Indices begin + /// with `alias_verts`, and then continue into `verts` - that is, + /// from `0..alias_verts.len()` they refer to `alias_verts`, and from + /// `alias_verts.len()..(alias_verts.len()+verts.len())` they refer to + /// `verts`. + pub faces: Vec, +} + +impl MeshTemplate { + + /// Returns a new `MeshTemplate` whose concrete vertices have + /// been transformed. Note that alias vertices are left untouched. + pub fn transform(&self, xfm: &Transform) -> MeshTemplate { + let v = self.verts.iter().map(|v| { + match v { + VertexUnion::Vertex(v) => VertexUnion::Vertex(xfm.mtx * v), + a@_ => a.clone(), + } + }); + + MeshTemplate { + verts: v.collect(), + faces: self.faces.clone(), + } + } + + /// Appends any number of meshes together. Returns both a single + /// mesh, and a vector which gives the offset by which each + /// 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, + T: IntoIterator + { + let mut offsets: Vec = vec![]; + let mut v: Vec = vec![]; + let mut f: Vec = vec![]; + 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(); + offsets.push(offset); + + // Copy all vertices: + v.append(&mut mesh.verts.clone()); + // Append its faces, applying offset: + f.extend(mesh.faces.iter().map(|n| n + offset)); + } + + (MeshTemplate { verts: v, faces: f }, offsets) + } + /// Treat this mesh as a 'parent' mesh to connect with any number /// of 'child' meshes, all of them paired with their respective /// parent vertex mappings. This returns a tuple of (new mesh, @@ -130,8 +151,8 @@ impl OpenMesh { /// 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) -> (OpenMesh, Vec) - where U: Borrow, + pub fn connect(&self, children: T) -> (MeshTemplate, Vec) + where U: Borrow, T: IntoIterator)> //pub fn connect(&self, children: &Vec<(OpenMesh, Vec)>) -> (OpenMesh, Vec) { @@ -139,7 +160,7 @@ impl OpenMesh { // TODO: Clean up Vec stuff // Copy body vertices & faces: - let mut verts: Vec = self.verts.clone(); + let mut verts: Vec = self.verts.clone(); let mut faces = self.faces.clone(); let mut offsets: Vec = vec![]; @@ -148,29 +169,33 @@ impl OpenMesh { let child = child_.borrow(); - // body_offset corresponds to the position in 'verts' at + // offset corresponds to the position in 'verts' at // which we're appending everything in 'child.verts' - // thus, the offset we shift all indices in 'children' by. - let body_offset = verts.len(); - - // Copy all vertices from 'child': - verts.append(&mut child.verts.clone()); + let offset = verts.len(); - // Append its faces: - faces.extend(child.faces.iter().map(|t| { - match t { - // Apply aforementioned shift to its body vertices: - Tag::Body(n) => Tag::Body(n + body_offset), - // Since 'self' vertices are in the same order, - // parent vertex references retain same index: - Tag::Parent(n) => Tag::Body(mapping[*n]), + // Concrete vertices in 'child.verts' need to be copied: + verts.extend(child.verts.iter().filter_map(|v| { + match v { + VertexUnion::Vertex(_) => Some(v.clone()), + VertexUnion::Alias(_) => None, } })); - offsets.push(body_offset); + // All faces need copied, but if if the index was to + // a concrete vertex, then it needs shifted by 'offset'; + // if an alias, it needs remapped. + faces.extend(child.faces.iter().map(|n| + match child.verts[*n] { + VertexUnion::Vertex(_) => n + offset, + VertexUnion::Alias(m) => mapping[m], + } + )); + + offsets.push(offset); } - let m = OpenMesh { + let m = MeshTemplate { verts: verts, faces: faces, }; diff --git a/src/prim.rs b/src/prim.rs index a872715..e8e2f1d 100644 --- a/src/prim.rs +++ b/src/prim.rs @@ -1,17 +1,17 @@ -use crate::openmesh::{OpenMesh, Tag}; +use crate::mesh::{Mesh}; use crate::xform::{vertex, Transform}; /// Returns an empty mesh (no vertices, no faces). -pub fn empty_mesh() -> OpenMesh { - OpenMesh { +pub fn empty_mesh() -> Mesh { + Mesh { verts: vec![], faces: vec![], } } /// Returns a cube of sidelength one centered at (0,0,0). -pub fn cube() -> OpenMesh { - OpenMesh { +pub fn cube() -> Mesh { + Mesh { verts: vec![ vertex(0.0, 0.0, 0.0), vertex(1.0, 0.0, 0.0), @@ -23,18 +23,18 @@ pub fn cube() -> OpenMesh { vertex(1.0, 1.0, 1.0), ], faces: vec![ - Tag::Body(0), Tag::Body(3), Tag::Body(1), - Tag::Body(0), Tag::Body(2), Tag::Body(3), - Tag::Body(1), Tag::Body(7), Tag::Body(5), - Tag::Body(1), Tag::Body(3), Tag::Body(7), - Tag::Body(5), Tag::Body(6), Tag::Body(4), - Tag::Body(5), Tag::Body(7), Tag::Body(6), - Tag::Body(4), Tag::Body(2), Tag::Body(0), - Tag::Body(4), Tag::Body(6), Tag::Body(2), - Tag::Body(2), Tag::Body(7), Tag::Body(3), - Tag::Body(2), Tag::Body(6), Tag::Body(7), - Tag::Body(0), Tag::Body(1), Tag::Body(5), - Tag::Body(0), Tag::Body(5), Tag::Body(4), + 0, 3, 1, + 0, 2, 3, + 1, 7, 5, + 1, 3, 7, + 5, 6, 4, + 5, 7, 6, + 4, 2, 0, + 4, 6, 2, + 2, 7, 3, + 2, 6, 7, + 0, 1, 5, + 0, 5, 4, ], }.transform(&Transform::new().translate(-0.5, -0.5, -0.5)) } diff --git a/src/rule.rs b/src/rule.rs index 0dab978..c7fd957 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -1,4 +1,4 @@ -use crate::openmesh::{OpenMesh, Tag}; +use crate::mesh::{MeshTemplate, 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 an `OpenMesh` with a face + /// mesh. That is, if `rule` produces a `MeshTemplate` 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) -> (OpenMesh, usize) { + pub fn to_mesh(s: Rc>, iters_left: usize) -> (MeshTemplate, 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<(OpenMesh, Vec)> = rs.children.iter().map(|sub| { + let subgeom: Vec<(MeshTemplate, 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) -> (OpenMesh, usize) { + pub fn to_mesh_iter(s: Rc>, max_depth: usize) -> (MeshTemplate, usize) { struct State { // The set of rules we're currently handling: @@ -185,14 +185,14 @@ impl Rule { // actually need vmap. let m = { let mut m_ = 0; - for f in &final_geom.faces { - match f { - Tag::Parent(i) => { - if *i > m_ { - m_ = *i; + for v in &final_geom.verts { + match *v { + VertexUnion::Alias(a) => { + if a > m_ { + m_ = a; } - } - _ => {} + }, + VertexUnion::Vertex(_) => (), } } m_ + 1 @@ -262,17 +262,17 @@ impl Rule { } impl RuleEval { - /// Turn an iterator of (OpenMesh, Child) into a single RuleEval. + /// Turn an iterator of (MeshTemplate, 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: OpenMesh) -> RuleEval - where U: Borrow, + pub fn from_pairs(m: T, final_geom: MeshTemplate) -> RuleEval + where U: Borrow, T: IntoIterator)> { let (meshes, children): (Vec<_>, Vec<_>) = m.into_iter().unzip(); - let (mesh, offsets) = OpenMesh::append(meshes); + let (mesh, offsets) = MeshTemplate::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 461ef63..1839f90 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,7 +1,24 @@ -use crate::openmesh::{Tag, OpenMesh}; +use std::ops::Range; +use crate::mesh::{Mesh, MeshTemplate, VertexUnion}; use crate::xform::{Vertex}; //use crate::rule::{Rule, Child}; +/// This is like `vec!`, but it can handle elements that are given +/// with `@var: element` rather than `element`, e.g. like +/// `vec_indexed![foo, bar, @a: baz, quux]`. The variable (which must +/// already be declared and a `usize`) is then assigned the index of the +/// element it precedes. This can be used any number of times with +/// different elements and indices. +#[macro_export] +macro_rules! vec_indexed { + // Thank you to GhostOfSteveJobs and Rantanen in the Rust discord. + ($( $(@ $Index:ident :)? $Value:expr,)*) => {{ + let mut v = Vec::new(); + $( $($Index = v.len();)? v.push($Value); )* + v + }}; +} + /// 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()`). @@ -21,45 +38,57 @@ pub fn subdivide_cycle(p: &Vec, count: usize) -> Vec { // TODO: This can be generalized to an iterator or to IntoIterator // trait bound -pub fn parallel_zigzag_faces(count: usize) -> Vec { +pub fn parallel_zigzag_faces(r1: Range, r2: Range) -> Vec { + let count = r1.end - r1.start; + if (r2.end - r2.start) != count { + panic!("Ranges must have the same size"); + } + if (r2.end > r1.start && r2.end < r1.end) || + (r1.end > r2.start && r1.end < r2.end) { + panic!("Ranges cannot overlap"); + } + (0..count).map(|i0| { - let i1 = (i0+1) % count; + // i0 is an *offset* for the 'current' index. + // i1 is for the 'next' index, wrapping back to 0. + let i1 = (i0 + 1) % count; vec![ - Tag::Body(i1), Tag::Parent(i0), Tag::Body(i0), - Tag::Parent(i1), Tag::Parent(i0), Tag::Body(i1), + // Mind winding order! + r1.start + i1, r2.start + i0, r1.start + i0, + r2.start + i1, r2.start + i0, r1.start + i1, ] }).flatten().collect() } -pub fn zigzag_to_parent(verts: Vec, count: usize) -> OpenMesh { - OpenMesh { +pub fn zigzag_to_parent(verts: Vec, main: Range, parent: Range) -> MeshTemplate { + MeshTemplate { verts: verts, - faces: parallel_zigzag_faces(count), + faces: parallel_zigzag_faces(main, parent), } } -pub fn connect_convex(verts: &Vec, as_parent: bool) -> (Vertex, Vec) { +pub fn centroid(verts: &Vec) -> Vertex { let n = verts.len(); let mut centroid = Vertex::new(0.0, 0.0, 0.0, 0.0); for v in verts { centroid += v; } centroid /= n as f32; - - let faces: Vec = { - if as_parent { - (0..n).map(|f1| { - let f2 = (f1 + 1) % n; - vec![Tag::Parent(f2), Tag::Parent(f1), Tag::Body(0)] - }).flatten().collect() - } else { - (0..n).map(|f1| { - let f2 = (f1 + 1) % n; - // n is used for new center vertex - vec![Tag::Body(f1), Tag::Body(f2), Tag::Body(n)] - }).flatten().collect() - } - }; - - (centroid, faces) + centroid +} + +pub fn connect_convex(range: Range, target: usize, as_parent: bool) -> Vec { + + let count = range.end - range.start; + if as_parent { + (0..count).map(|i0| { + let i1 = (i0 + 1) % count; + vec![range.start + i1, range.start + i0, target] + }).flatten().collect() + } else { + (0..count).map(|i0| { + let i1 = (i0 + 1) % count; + vec![range.start + i0, range.start + i1, target] + }).flatten().collect() + } }