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:
- If my `closure_try2` branch seems to be working: start converting
other things and cleaning them up. Modify `twist` to have the
things I wrote this for in the first place!
other things and cleaning everything up. (`twist` is still ugly.)
- See `automata_scratch/examples.py` and implement some of the tougher
examples.
- `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:
the clockwise boundaries, the zigzag connections, the iterating over
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
- 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.
## 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),
], &xf);
//let seed_sub = util::subdivide_cycle(&seed, subdiv);
let dx0: f32 = 1.5;
let dy: f32 = 0.1/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 xform = |dx, i, ang0| -> Mat4 {
(geometry::Rotation3::from_axis_angle(&y, ang0 + (qtr * (i as f32))).to_homogeneous() *
let xform = |dx, i, ang0, div| -> Mat4 {
(geometry::Rotation3::from_axis_angle(&y, ang0 + (qtr / div * (i as f32))).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_sub = util::subdivide_cycle(&seed_orig, subdiv);
@ -447,32 +446,23 @@ fn twist(f: f32, subdiv: usize) -> Rule {
let c = Child {
rule: Rc::new(Rule { eval: (recur.clone())(incr) }),
xf: xform(dx, i, ang0),
vmap: ((n+1)*i..(n+1)*(i+count)).collect(), // N.B.
// note 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.
xf: xform,
vmap: (0..(n+1)).collect(),
// N.B. n+1, not n. the +1 is for the centroid below
};
let mut vs = transform(&seed_sub, &c.xf);
let mut vs = transform(&seed_sub, &xform);
// and in the process, generate faces for these seeds:
let (centroid, f) = util::connect_convex(&vs, false);
vs.push(centroid);
(c, OpenMesh { verts: vs, faces: f })
(OpenMesh { verts: vs, faces: f }, c)
};
// First generate 'count' children, each one shifted/rotated
// differently:
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 + 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();
// Generate 'count' children, shifted/rotated differently:
let children_inner = (0..count).map(|i| make_child(i, incr_inner, xform(dx0, i, 0.0, 1.0)));
let children_outer = (0..count).map(|i| make_child(i, incr_outer, xform(dx0*2.0, i, qtr/2.0, 2.0)));
RuleEval {
geom: OpenMesh::append(meshes),
final_geom: prim::empty_mesh(),
children: children,
}
RuleEval::from_pairs(
children_inner.chain(children_outer), prim::empty_mesh())
};
Rule { eval: Box::new(start) }

View File

@ -45,10 +45,16 @@ pub struct 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>,
T: IntoIterator<Item = U>
{
let mut offsets: Vec<usize> = vec![];
let mut v: Vec<Vertex> = vec![];
let mut f: Vec<Tag> = vec![];
for mesh_ in meshes {
@ -57,6 +63,7 @@ impl OpenMesh {
// 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());
@ -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.

View File

@ -1,5 +1,6 @@
use crate::openmesh::{OpenMesh, Tag, Mat4};
//use crate::prim;
use std::borrow::Borrow;
use std::rc::Rc;
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,
}
}
}