From b7da8bea414db24b0236b196191b185cfed19f20 Mon Sep 17 00:00:00 2001 From: Chris Hodapp Date: Wed, 13 May 2020 15:02:22 -0400 Subject: [PATCH] Change name of 'vmap' to 'arg_vals' to fit with MeshFunc --- README.md | 12 +------ src/examples.rs | 88 ++++++++++++++++++++++++------------------------- src/mesh.rs | 17 ++++++---- src/rule.rs | 55 ++++++++++++++++--------------- 4 files changed, 84 insertions(+), 88 deletions(-) diff --git a/README.md b/README.md index 89c83e6..a8d80ea 100644 --- a/README.md +++ b/README.md @@ -6,18 +6,8 @@ transformations so that I'm actually constructing things to be correct instead of just throwing shit at the wall. See my "Composing Transformations" link in log.org. -- My "Barbs" example revealed another pesky limitation: a parent vertex - cannot refer to a parent vertex of the parent itself. This came up - because I had a rule inheriting 4 vertices (one side of a cube), and - creating 4 new vertices (the opposite side of a cube). I wanted its - child rules to be able to create faces that had 2 vertices of the - parent and 2 vertices that the parent inherited (basically grandparent - vertices) - think of one of the remaining 4 sides of the cube. I have - no way to do this and no easy workarounds I can see, given that the - rule does not have access to the exact vertex positions (so just making - new vertices that are 'close' and connecting them isn't an option). - Adaptive subdivision - which means having to generalize past some - `vmap` stuff. + `arg_vals` stuff. - Try some non-deterministic examples. - Get identical or near-identical meshes to `ramhorn_branch` from Python. (Should just be a matter of tweaking parameters.) diff --git a/src/examples.rs b/src/examples.rs index 9c4f1e0..f87571d 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -39,7 +39,7 @@ pub fn cube_thing() -> Rule<()> { children: xforms.map(move |xf| Child { rule: self_.clone(), xf: xf, - vmap: vec![], + arg_vals: vec![], }).collect(), } }; @@ -85,7 +85,7 @@ pub fn barbs() -> Rule<()> { Child { rule: self_.clone(), xf: barb_incr, - vmap: (0..n).collect(), + arg_vals: (0..n).collect(), } ] } @@ -128,27 +128,27 @@ pub fn barbs() -> Rule<()> { Child { rule: self_.clone(), xf: main_incr, - vmap: (0..n).collect(), + arg_vals: (0..n).collect(), }, Child { - rule: Rc::new(Rule { eval: barb_.clone(), ctxt: () }), + rule: Rc::new(Rule { eval: barb_.clone(), ctxt: () }), xf: main_barb_trans(0), - vmap: vec![b0 + 0, b0 + 1, a0 + 1, a0 + 0], + arg_vals: vec![b0 + 0, b0 + 1, a0 + 1, a0 + 0], }, Child { - rule: Rc::new(Rule { eval: barb_.clone(), ctxt: () }), + rule: Rc::new(Rule { eval: barb_.clone(), ctxt: () }), xf: main_barb_trans(1), - vmap: vec![b0 + 1, b0 + 2, a0 + 2, a0 + 1], + arg_vals: vec![b0 + 1, b0 + 2, a0 + 2, a0 + 1], }, Child { - rule: Rc::new(Rule { eval: barb_.clone(), ctxt: () }), + rule: Rc::new(Rule { eval: barb_.clone(), ctxt: () }), xf: main_barb_trans(2), - vmap: vec![b0 + 2, b0 + 3, a0 + 3, a0 + 2], + arg_vals: vec![b0 + 2, b0 + 3, a0 + 3, a0 + 2], }, Child { - rule: Rc::new(Rule { eval: barb_.clone(), ctxt: () }), + rule: Rc::new(Rule { eval: barb_.clone(), ctxt: () }), xf: main_barb_trans(3), - vmap: vec![b0 + 3, b0 + 0, a0 + 0, a0 + 3], + arg_vals: vec![b0 + 3, b0 + 0, a0 + 0, a0 + 3], }, // TODO: Factor out repetition ], @@ -171,7 +171,7 @@ pub fn barbs() -> Rule<()> { Child { rule: Rc::new(Rule { eval: main_.clone(), ctxt: () }), xf: Transform::new(), - vmap: (0..n).collect(), + arg_vals: (0..n).collect(), }, ], } @@ -233,7 +233,7 @@ pub fn twist(f: f32, subdiv: usize) -> Rule<()> { Child { rule: self_.clone(), xf: incr, - vmap: (0..n).collect(), + arg_vals: (0..n).collect(), }, ], } @@ -254,7 +254,7 @@ pub fn twist(f: f32, subdiv: usize) -> Rule<()> { rule: Rc::new(Rule { eval: (recur.clone())(incr), ctxt: () }), // TODO: Cleanliness fix - can macros clean up above? xf: xform, - vmap: (0..(n+1)).collect(), + arg_vals: (0..(n+1)).collect(), // N.B. n+1, not n. the +1 is for the centroid below. }; let mut vs = xform.transform(&seed); @@ -334,7 +334,7 @@ pub fn nest_spiral_2() -> Rule { Child { rule: Rc::new(next_rule), xf: Transform::new(), - vmap: (0..n2).collect(), + arg_vals: (0..n2).collect(), }, ], } @@ -346,7 +346,7 @@ pub fn nest_spiral_2() -> Rule { Child { rule: Rc::new(next_rule), xf: Transform::new(), - vmap: (0..n).collect(), + arg_vals: (0..n).collect(), }, ], } @@ -372,7 +372,7 @@ pub fn nest_spiral_2() -> Rule { }, }), xf: Transform::new(), - vmap: vec![], // no parent vertices + arg_vals: vec![], // no parent vertices } }; @@ -463,7 +463,7 @@ pub fn twisty_torus() -> Rule { Child { rule: Rc::new(next_rule), xf: Transform::new(), - vmap: (0..n2).collect(), + arg_vals: (0..n2).collect(), }, ], } @@ -475,7 +475,7 @@ pub fn twisty_torus() -> Rule { Child { rule: Rc::new(next_rule), xf: Transform::new(), - vmap: (0..n).collect(), + arg_vals: (0..n).collect(), }, ], } @@ -538,7 +538,7 @@ pub fn twisty_torus_hardcode() -> Rule<()> { Child { rule: self_.clone(), xf: incr, - vmap: (0..n).collect(), + arg_vals: (0..n).collect(), }, ], } @@ -557,7 +557,7 @@ pub fn twisty_torus_hardcode() -> Rule<()> { Child { rule: Rc::new(Rule { eval: Rc::new(recur.clone()), ctxt: () }), xf: incr, - vmap: (0..n2).collect(), + arg_vals: (0..n2).collect(), }, ], } @@ -633,7 +633,7 @@ pub fn wind_chime_mistake_thing() -> Rule { Child { rule: Rc::new(next_rule), xf: Transform::new(), - vmap: (0..n2).collect(), + arg_vals: (0..n2).collect(), }, ], } @@ -645,7 +645,7 @@ pub fn wind_chime_mistake_thing() -> Rule { Child { rule: Rc::new(next_rule), xf: Transform::new(), - vmap: (0..n).collect(), + arg_vals: (0..n).collect(), }, ], } @@ -712,7 +712,7 @@ pub fn ramhorn() -> Rule<()> { Child { rule: self_.clone(), xf: incr, - vmap: vec![0,1,2,3], + arg_vals: vec![0,1,2,3], }, ], } @@ -779,22 +779,22 @@ pub fn ramhorn() -> Rule<()> { Child { rule: Rc::new(Rule { eval: Rc::new(recur.clone()), ctxt: () }), xf: opening_xform(0.0), - vmap: vec![5,2,6,8], + arg_vals: vec![5,2,6,8], }, Child { rule: Rc::new(Rule { eval: Rc::new(recur.clone()), ctxt: () }), xf: opening_xform(1.0), - vmap: vec![4,1,5,8], + arg_vals: vec![4,1,5,8], }, Child { rule: Rc::new(Rule { eval: Rc::new(recur.clone()), ctxt: () }), xf: opening_xform(2.0), - vmap: vec![7,0,4,8], + arg_vals: vec![7,0,4,8], }, Child { rule: Rc::new(Rule { eval: Rc::new(recur.clone()), ctxt: () }), xf: opening_xform(3.0), - vmap: vec![6,3,7,8], + arg_vals: vec![6,3,7,8], }, // TODO: These vertex mappings appear to be right. // Explain *why* they are right. @@ -893,22 +893,22 @@ pub fn ramhorn_branch(depth: usize, f: f32) -> Rule { Child { rule: Rc::new(Rule { eval: recur.clone(), ctxt }), xf: opening_xform(0.0), - vmap: vec![5,2,6,8], + arg_vals: vec![5,2,6,8], }, Child { rule: Rc::new(Rule { eval: recur.clone(), ctxt }), xf: opening_xform(1.0), - vmap: vec![4,1,5,8], + arg_vals: vec![4,1,5,8], }, Child { rule: Rc::new(Rule { eval: recur.clone(), ctxt }), xf: opening_xform(2.0), - vmap: vec![7,0,4,8], + arg_vals: vec![7,0,4,8], }, Child { rule: Rc::new(Rule { eval: recur.clone(), ctxt }), xf: opening_xform(3.0), - vmap: vec![6,3,7,8], + arg_vals: vec![6,3,7,8], }, // TODO: These vertex mappings appear to be right. // Explain *why* they are right. @@ -940,7 +940,7 @@ pub fn ramhorn_branch(depth: usize, f: f32) -> Rule { Child { rule: Rc::new(next_rule), xf: incr, - vmap: vec![0,1,2,3], + arg_vals: vec![0,1,2,3], }, ], } @@ -970,7 +970,7 @@ pub fn ramhorn_branch(depth: usize, f: f32) -> Rule { Child { rule: Rc::new(Rule { eval: Rc::new(trans.clone()), ctxt: self_.ctxt }), xf: Transform::new(), - vmap: vec![0,1,2,3], + arg_vals: vec![0,1,2,3], }, ], } @@ -1066,22 +1066,22 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule { Child { rule: Rc::new(Rule { eval: recur.clone(), ctxt }), xf: opening_xform(0.0), - vmap: vec![5,2,6,8], + arg_vals: vec![5,2,6,8], }, Child { rule: Rc::new(Rule { eval: recur.clone(), ctxt }), xf: opening_xform(1.0), - vmap: vec![4,1,5,8], + arg_vals: vec![4,1,5,8], }, Child { rule: Rc::new(Rule { eval: recur.clone(), ctxt }), xf: opening_xform(2.0), - vmap: vec![7,0,4,8], + arg_vals: vec![7,0,4,8], }, Child { rule: Rc::new(Rule { eval: recur.clone(), ctxt }), xf: opening_xform(3.0), - vmap: vec![6,3,7,8], + arg_vals: vec![6,3,7,8], }, // TODO: These vertex mappings appear to be right. // Explain *why* they are right. @@ -1114,7 +1114,7 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule { Child { rule: Rc::new(next_rule), xf: incr, - vmap: vec![0,1,2,3], + arg_vals: vec![0,1,2,3], }, ], } @@ -1144,7 +1144,7 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule { Child { rule: Rc::new(Rule { eval: Rc::new(trans.clone()), ctxt: self_.ctxt }), xf: Transform::new(), - vmap: vec![0,1,2,3], + arg_vals: vec![0,1,2,3], }, ], } @@ -1178,7 +1178,7 @@ impl CurveHorn { Child { rule: Rule { eval: Rc::new(move || self.do_nothing()) }, xf: self.id_xform, - vmap: vec![0,1,2,3], + arg_vals: vec![0,1,2,3], }, ], } @@ -1215,12 +1215,12 @@ impl CurveHorn { Child { rule: Rule { eval: Rc::new(move || self.recur()) }, xf: self.id_xform, - vmap: vec![0,1,2,3], + arg_vals: vec![0,1,2,3], }, Child { rule: Rule { eval: Rc::new(move || self.recur()) }, xf: self.flip180, - vmap: vec![3,2,1,0], + arg_vals: vec![3,2,1,0], }, ], } @@ -1266,7 +1266,7 @@ impl CurveHorn { Child { rule: Rule { eval: Rc::new(move || self.recur()) }, xf: self.incr, - vmap: vec![0,1,2,3], + arg_vals: vec![0,1,2,3], }, ], } diff --git a/src/mesh.rs b/src/mesh.rs index ac8c3f2..b7a84aa 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -74,8 +74,11 @@ impl Mesh { pub enum VertexUnion { /// A concrete vertex. Vertex(Vertex), - /// An 'unbound' vertex - something like an argument to a function with + /// A vertex argument - something like an argument to a function with /// the given positional index. + /// + /// The job of `MeshFunc.connect` is to bind these arguments to concrete + /// vertices. Arg(usize), } @@ -155,13 +158,15 @@ impl MeshFunc { /// 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, - /// offsets), where 'offsets' gives the offset of where child - /// meshes were shifted in the new mesh. + /// vertex argument values (i.e. `arg_vals` from `Child`). + /// This returns a tuple of (new mesh, offsets), where 'offsets' + /// gives the offset of where child meshes were shifted in the new + /// mesh. /// /// 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. + /// 'offset[i]' of the new mesh. This is needed in order to adjust + /// references to vertices of a mesh in 'children' - such as + /// 'arg_vals' of `rule::Child`. pub fn connect(&self, children: T) -> (MeshFunc, Vec) where U: Borrow, T: IntoIterator)> diff --git a/src/rule.rs b/src/rule.rs index c26e6a2..e4c4aac 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -46,6 +46,8 @@ pub struct RuleEval { /// /// Parent vertex references will be resolved directly to `geom` /// with no mapping. + /// (TODO: Does this make sense? Nowhere else do I treat Arg(n) as + /// an index - it's always a positional argument.) pub final_geom: Rc, /// The child invocations (used if recursion continues). The @@ -67,12 +69,15 @@ pub struct Child { /// as all sub-geometry produced recursively). pub xf: Transform, - /// 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 `MeshFunc` with a face - /// of `Tag::Parent(n)`, this will correspond to index `vmap[n]` - /// in the parent mesh. - pub vmap: Vec, + /// The 'argument values' to apply to vertex arguments of a `MeshFunc` + /// from `geom` and `final_geom` that `rule` produces when evaluated. + /// The values of this are treated as indices into the parent + /// `RuleEval` that produced this `Child`. + /// + /// In specific: if `arg_vals[i] = j` and `rule` produces some `geom` or + /// `final_geom`, then any vertex of `VertexUnion::Arg(i)` will be mapped + /// to `geom.verts[j]` in the *parent* geometry. + pub arg_vals: Vec, } impl Rule { @@ -88,7 +93,7 @@ impl Rule { if iters_left <= 0 { return ((*rs.final_geom).clone(), 1); // TODO: This is probably wrong because of the way that - // sub.vmap is used below. final_geom is not supposed to + // sub.arg_vals is used below. final_geom is not supposed to // have any vertex mapping applied. } @@ -103,7 +108,7 @@ impl Rule { let m2 = submesh.transform(&sub.xf); - (m2, sub.vmap.clone()) + (m2, sub.arg_vals.clone()) // TODO: Fix clone? }).collect(); @@ -181,8 +186,8 @@ impl Rule { // geometry properly: let final_geom = eval.final_geom.transform(&xf); // TODO: Fix the awful hack below. I do this only to - // generate an identity mapping for vmap when I don't - // actually need vmap. + // generate an identity mapping for arg_vals when I don't + // actually need arg_vals. let m = { let mut m_ = 0; for v in &final_geom.verts { @@ -197,10 +202,10 @@ impl Rule { } m_ + 1 }; - let vmap: Vec = (0..m).collect(); - let (geom2, _) = new_geom.connect(vec![(final_geom, vmap)]); + let arg_vals: Vec = (0..m).collect(); + let (geom2, _) = new_geom.connect(vec![(final_geom, arg_vals)]); - geom = geom.connect(vec![(geom2, child.vmap.clone())]).0; + geom = geom.connect(vec![(geom2, child.arg_vals.clone())]).0; // TODO: Fix clone? // If we end recursion on one child, we must end it @@ -216,23 +221,19 @@ impl Rule { continue; } - let (g, offsets) = geom.connect(vec![(new_geom, child.vmap.clone())]); + let (g, offsets) = geom.connect(vec![(new_geom, child.arg_vals.clone())]); geom = g; - // 'new_geom' may itself be parent geometry for - // 'eval.children' (via Tag::Parent), and vmap is there to - // resolve Tag::Parent references to the right vertices in - // 'new_geom'. - // - // However, we connect() on the global geometry which we - // merged 'new_geom' into, not 'new_geom' directly. To - // account for this, we must shift vmap by the offset that - // 'geom.connect' gave us: + // 'eval.children' may contain (via 'arg_vals') references to + // indices of 'new_geom'. However, we don't connect() to + // 'new_geom', but to the global geometry we just merged it + // into. To account for this, we must shift 'arg_vals' by + // the offset that 'geom.connect' gave us. let off = offsets[0]; // (We pass a one-element vector to geom.connect() above // so offsets always has just one element.) for child in eval.children.iter_mut() { - child.vmap = child.vmap.iter().map(|n| n + off).collect(); + child.arg_vals = child.arg_vals.iter().map(|n| n + off).collect(); } // We're done evaluating this rule, so increment 'next'. @@ -263,7 +264,7 @@ impl Rule { impl RuleEval { /// Turn an iterator of (MeshFunc, Child) into a single RuleEval. - /// All meshes are merged, and the `vmap` in each child has the + /// All meshes are merged, and the `arg_vals` in each child has the /// correct offsets applied to account for this merge. /// /// (`final_geom` is passed through to the RuleEval unmodified.) @@ -274,13 +275,13 @@ impl RuleEval { let (meshes, children): (Vec<_>, Vec<_>) = m.into_iter().unzip(); let (mesh, offsets) = MeshFunc::append(meshes); - // Patch up vmap in each child, and copy everything else: + // Patch up arg_vals in each child, and copy everything else: let children2: Vec> = children.iter().zip(offsets.iter()).map(|(c,off)| { Child { rule: c.rule.clone(), xf: c.xf.clone(), // simply add offset: - vmap: c.vmap.iter().map(|i| i + off).collect(), + arg_vals: c.arg_vals.iter().map(|i| i + off).collect(), } }).collect();