Added helper function to avoid juggling of indices

This commit is contained in:
Chris Hodapp 2020-03-31 15:30:25 -04:00
parent 558bd062d9
commit 45ab4ed9e0
4 changed files with 60 additions and 29 deletions

View File

@ -3,8 +3,7 @@
## Highest priority: ## Highest priority:
- If my `closure_try2` branch seems to be working: start converting - If my `closure_try2` branch seems to be working: start converting
other things and cleaning them up. Modify `twist` to have the other things and cleaning everything up. (`twist` is still ugly.)
things I wrote this for in the first place!
- See `automata_scratch/examples.py` and implement some of the tougher - See `automata_scratch/examples.py` and implement some of the tougher
examples. examples.
- `spiral_nested_2` & `spiral_nested_3` (how to compose - `spiral_nested_2` & `spiral_nested_3` (how to compose
@ -21,10 +20,12 @@
- What patterns can I factor out? I do some things regularly, like: - What patterns can I factor out? I do some things regularly, like:
the clockwise boundaries, the zigzag connections, the iterating over the clockwise boundaries, the zigzag connections, the iterating over
a `Vec<Vertex>` to transform each element and make another vector. a `Vec<Vertex>` to transform each element and make another vector.
- I have seen many of my bugs come from: all this arithmetic on
indices. I generate vertex maps more or less manually.
- Docs on modules - Docs on modules
- Grep for all TODOs in code, really. - Grep for all TODOs in code, really.
- Look at performance. Can I save on copies of geometry by using
`Rc<OpenMesh>` or the like? In many cases I have nothing but copied
geometry. Can I pre-allocate vectors instead of
extending/appending?
- Look at everything in README.md in automata_scratch. - Look at everything in README.md in automata_scratch.
## If I'm bored: ## If I'm bored:

View File

@ -375,7 +375,6 @@ fn twist(f: f32, subdiv: usize) -> Rule {
vertex( 0.5, 0.0, 0.5), vertex( 0.5, 0.0, 0.5),
vertex(-0.5, 0.0, 0.5), vertex(-0.5, 0.0, 0.5),
], &xf); ], &xf);
//let seed_sub = util::subdivide_cycle(&seed, subdiv);
let dx0: f32 = 1.5; let dx0: f32 = 1.5;
let dy: f32 = 0.1/f; let dy: f32 = 0.1/f;
let ang: f32 = 0.05/f; let ang: f32 = 0.05/f;
@ -434,12 +433,12 @@ fn twist(f: f32, subdiv: usize) -> Rule {
let start = move |self_: Rc<Rule>| -> RuleEval { let start = move |self_: Rc<Rule>| -> RuleEval {
let xform = |dx, i, ang0| -> Mat4 { let xform = |dx, i, ang0, div| -> Mat4 {
(geometry::Rotation3::from_axis_angle(&y, ang0 + (qtr * (i as f32))).to_homogeneous() * (geometry::Rotation3::from_axis_angle(&y, ang0 + (qtr / div * (i as f32))).to_homogeneous() *
geometry::Translation3::new(dx, 0.0, 0.0).to_homogeneous()) geometry::Translation3::new(dx, 0.0, 0.0).to_homogeneous())
}; };
let make_child = |i, dx, incr, ang0| -> (Child, OpenMesh) { let make_child = |i, incr, xform| -> (OpenMesh, Child) {
let seed_orig = transform(&seed, &incr); let seed_orig = transform(&seed, &incr);
let seed_sub = util::subdivide_cycle(&seed_orig, subdiv); let seed_sub = util::subdivide_cycle(&seed_orig, subdiv);
@ -447,32 +446,23 @@ fn twist(f: f32, subdiv: usize) -> Rule {
let c = Child { let c = Child {
rule: Rc::new(Rule { eval: (recur.clone())(incr) }), rule: Rc::new(Rule { eval: (recur.clone())(incr) }),
xf: xform(dx, i, ang0), xf: xform,
vmap: ((n+1)*i..(n+1)*(i+count)).collect(), // N.B. vmap: (0..(n+1)).collect(),
// note n+1, not n. the +1 is for the centroid below // N.B. n+1, not n. the +1 is for the centroid below
// TODO: The above vmap is wrong when I call
// 'make_child' twice and then append.
}; };
let mut vs = transform(&seed_sub, &c.xf); let mut vs = transform(&seed_sub, &xform);
// and in the process, generate faces for these seeds: // and in the process, generate faces for these seeds:
let (centroid, f) = util::connect_convex(&vs, false); let (centroid, f) = util::connect_convex(&vs, false);
vs.push(centroid); vs.push(centroid);
(c, OpenMesh { verts: vs, faces: f }) (OpenMesh { verts: vs, faces: f }, c)
}; };
// First generate 'count' children, each one shifted/rotated // Generate 'count' children, shifted/rotated differently:
// differently: let children_inner = (0..count).map(|i| make_child(i, incr_inner, xform(dx0, i, 0.0, 1.0)));
let children_inner = (0..count).map(|i| make_child(i, dx0, incr_inner, 0.0)); let children_outer = (0..count).map(|i| make_child(i, incr_outer, xform(dx0*2.0, i, qtr/2.0, 2.0)));
let children_outer = (0..count).map(|i| make_child(i + count, dx0*2.0, incr_outer, qtr/2.0));
// TODO: the +count is only to work around vmap kludges
let (children, meshes): (Vec<_>, Vec<_>) = children_inner.chain(children_outer).unzip();
RuleEval { RuleEval::from_pairs(
geom: OpenMesh::append(meshes), children_inner.chain(children_outer), prim::empty_mesh())
final_geom: prim::empty_mesh(),
children: children,
}
}; };
Rule { eval: Box::new(start) } Rule { eval: Box::new(start) }

View File

@ -45,10 +45,16 @@ pub struct OpenMesh {
impl OpenMesh { impl OpenMesh {
pub fn append<T, U>(meshes: T) -> 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<T, U>(meshes: T) -> (OpenMesh, Vec<usize>)
where U: Borrow<OpenMesh>, where U: Borrow<OpenMesh>,
T: IntoIterator<Item = U> T: IntoIterator<Item = U>
{ {
let mut offsets: Vec<usize> = vec![];
let mut v: Vec<Vertex> = vec![]; let mut v: Vec<Vertex> = vec![];
let mut f: Vec<Tag> = vec![]; let mut f: Vec<Tag> = vec![];
for mesh_ in meshes { for mesh_ in meshes {
@ -57,6 +63,7 @@ impl OpenMesh {
// Position in 'verts' at which we're appending // Position in 'verts' at which we're appending
// mesh.verts, which we need to know to shift indices: // mesh.verts, which we need to know to shift indices:
let offset = v.len(); let offset = v.len();
offsets.push(offset);
// Copy all vertices: // Copy all vertices:
v.append(&mut mesh.verts.clone()); v.append(&mut mesh.verts.clone());
@ -70,7 +77,7 @@ impl OpenMesh {
})); }));
} }
OpenMesh { verts: v, faces: f } (OpenMesh { verts: v, faces: f }, offsets)
} }
/// Returns a new `OpenMesh` whose vertices have been transformed. /// Returns a new `OpenMesh` whose vertices have been transformed.

View File

@ -1,5 +1,6 @@
use crate::openmesh::{OpenMesh, Tag, Mat4}; use crate::openmesh::{OpenMesh, Tag, Mat4};
//use crate::prim; //use crate::prim;
use std::borrow::Borrow;
use std::rc::Rc; use std::rc::Rc;
pub type RuleFn = Box<dyn Fn(Rc<Rule>) -> RuleEval>; pub type RuleFn = Box<dyn Fn(Rc<Rule>) -> RuleEval>;
@ -254,3 +255,35 @@ impl Rule {
} }
} }
impl RuleEval {
/// Turn an iterator of (OpenMesh, 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<T, U>(m: T, final_geom: OpenMesh) -> RuleEval
where U: Borrow<OpenMesh>,
T: IntoIterator<Item = (U, Child)>
{
let (meshes, children): (Vec<_>, Vec<_>) = m.into_iter().unzip();
let (mesh, offsets) = OpenMesh::append(meshes);
// Patch up vmap in each child, and copy everything else:
let children2: Vec<Child> = 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(),
}
}).collect();
RuleEval {
geom: mesh,
final_geom: final_geom,
children: children2,
}
}
}