Change name of 'vmap' to 'arg_vals' to fit with MeshFunc

This commit is contained in:
Chris Hodapp 2020-05-13 15:02:22 -04:00
parent ce3ca34b70
commit b7da8bea41
4 changed files with 84 additions and 88 deletions

View File

@ -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.)

View File

@ -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<NestSpiral2Ctxt> {
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<NestSpiral2Ctxt> {
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<NestSpiral2Ctxt> {
},
}),
xf: Transform::new(),
vmap: vec![], // no parent vertices
arg_vals: vec![], // no parent vertices
}
};
@ -463,7 +463,7 @@ pub fn twisty_torus() -> Rule<TorusCtxt> {
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<TorusCtxt> {
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<WindChimeCtxt> {
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<WindChimeCtxt> {
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<RamHornCtxt> {
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<RamHornCtxt> {
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<RamHornCtxt> {
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<RamHornCtxt2> {
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<RamHornCtxt2> {
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<RamHornCtxt2> {
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],
},
],
}

View File

@ -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<T, U>(&self, children: T) -> (MeshFunc, Vec<usize>)
where U: Borrow<MeshFunc>,
T: IntoIterator<Item = (U, Vec<usize>)>

View File

@ -46,6 +46,8 @@ pub struct RuleEval<S> {
///
/// 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<MeshFunc>,
/// The child invocations (used if recursion continues). The
@ -67,12 +69,15 @@ pub struct Child<S> {
/// 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<usize>,
/// 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<usize>,
}
impl<S> Rule<S> {
@ -88,7 +93,7 @@ impl<S> Rule<S> {
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<S> Rule<S> {
let m2 = submesh.transform(&sub.xf);
(m2, sub.vmap.clone())
(m2, sub.arg_vals.clone())
// TODO: Fix clone?
}).collect();
@ -181,8 +186,8 @@ impl<S> Rule<S> {
// 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<S> Rule<S> {
}
m_ + 1
};
let vmap: Vec<usize> = (0..m).collect();
let (geom2, _) = new_geom.connect(vec![(final_geom, vmap)]);
let arg_vals: Vec<usize> = (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<S> Rule<S> {
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<S> Rule<S> {
impl<S> RuleEval<S> {
/// 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<S> RuleEval<S> {
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<Child<S>> = 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();