One example is building and running, mostly

This commit is contained in:
Chris Hodapp 2020-05-12 18:47:29 -04:00
parent 7626f1a089
commit 19988a0b35
6 changed files with 108 additions and 61 deletions

View File

@ -4,7 +4,8 @@ use nalgebra::*;
use rand::Rng; use rand::Rng;
use crate::util; use crate::util;
use crate::mesh::{Mesh, MeshTemplate}; use crate::util::VecExt;
use crate::mesh::{Mesh, MeshFunc, VertexUnion};
use crate::xform::{Transform, Vertex, vertex, Mat4}; use crate::xform::{Transform, Vertex, vertex, Mat4};
use crate::rule::{Rule, RuleFn, RuleEval, Child}; use crate::rule::{Rule, RuleFn, RuleEval, Child};
use crate::prim; use crate::prim;
@ -45,15 +46,16 @@ pub fn cube_thing() -> Rule<()> {
Rule { eval: Rc::new(rec), ctxt: () } Rule { eval: Rc::new(rec), ctxt: () }
} }
*/
pub fn barbs() -> Rule<()> { pub fn barbs() -> Rule<()> {
let (a0, a1); let (b0, b1);
let base_verts: Vec<Vertex> = vec_indexed![ let base_verts: Vec<VertexUnion> = vec_indexed![
@a0: vertex(-0.5, -0.5, 0.0), @b0: VertexUnion::Vertex(vertex(-0.5, -0.5, 0.0)),
vertex(-0.5, 0.5, 0.0), VertexUnion::Vertex(vertex(-0.5, 0.5, 0.0)),
vertex( 0.5, 0.5, 0.0), VertexUnion::Vertex(vertex( 0.5, 0.5, 0.0)),
@a1: vertex( 0.5, -0.5, 0.0), @b1: VertexUnion::Vertex(vertex( 0.5, -0.5, 0.0)),
]; ];
let n = base_verts.len(); let n = base_verts.len();
@ -64,19 +66,24 @@ pub fn barbs() -> Rule<()> {
let b = base_verts.clone(); let b = base_verts.clone();
let barb = move |self_: Rc<Rule<()>>| -> RuleEval<()> { let barb = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
let next_verts = incr.transform(&b); let mut next_verts = b.clone();
let (a0, a1) = next_verts.append_indexed(
&mut (0..4).map(|i| VertexUnion::Arg(i)).collect()
);
let geom = Rc::new(util::zigzag_to_parent(next_verts.clone(), a0..a1));
let (vc, faces) = util::connect_convex(&next_verts, true); let geom = util::parallel_zigzag(next_verts.clone(), b0..b1, a0..a1);
/*let (vc, faces) = util::connect_convex(&next_verts, true);
let final_geom = Rc::new(OpenMesh { let final_geom = Rc::new(OpenMesh {
verts: vec![vc], verts: vec![vc],
alias_verts: vec![], alias_verts: vec![],
faces: faces, faces: faces,
}); });
*/
RuleEval { RuleEval {
geom: geom, geom: Rc::new(geom.transform(&incr)),
final_geom: final_geom, final_geom: Rc::new(prim::empty_meshfunc()), // TODO
children: vec![ children: vec![
Child { Child {
rule: self_.clone(), rule: self_.clone(),
@ -89,20 +96,24 @@ pub fn barbs() -> Rule<()> {
let b = base_verts.clone(); let b = base_verts.clone();
let main = move |self_: Rc<Rule<()>>| -> RuleEval<()> { let main = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
let next_verts = incr.transform(&b); let mut next_verts = b.clone();
let (a0, a1) = next_verts.append_indexed(
&mut (0..4).map(|i| VertexUnion::Arg(i)).collect()
);
// TODO: Once I start doing the barbs this will go away // TODO: Once I start doing the barbs this will go away
let geom = Rc::new(util::zigzag_to_parent(next_verts.clone(), n)); let geom = util::parallel_zigzag(next_verts.clone(), b0..b1+1, a0..a1);
/*
let (vc, faces) = util::connect_convex(&next_verts, true); let (vc, faces) = util::connect_convex(&next_verts, true);
let final_geom = Rc::new(OpenMesh { let final_geom = Rc::new(MeshFunc {
verts: vec![vc], verts: vec![vc],
alias_verts: vec![],
faces: faces, faces: faces,
}); });
*/
RuleEval { RuleEval {
geom: geom, geom: Rc::new(geom.transform(&incr)),
final_geom: final_geom, final_geom: Rc::new(prim::empty_meshfunc()), // TODO
children: vec![ children: vec![
Child { Child {
rule: self_.clone(), rule: self_.clone(),
@ -116,15 +127,14 @@ pub fn barbs() -> Rule<()> {
let main_ = Rc::new(main); let main_ = Rc::new(main);
let base = move |self_: Rc<Rule<()>>| -> RuleEval<()> { let base = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
RuleEval { RuleEval {
geom: Rc::new(OpenMesh { geom: Rc::new(MeshFunc {
verts: base_verts.clone(), verts: base_verts.clone(),
alias_verts: vec![],
faces: vec![ faces: vec![
0, 1, 2, b0, b0 + 1, b0 + 2,
0, 1, 3, b0, b0 + 2, b0 + 3,
], ],
}), }),
final_geom: Rc::new(prim::empty_mesh()), final_geom: Rc::new(prim::empty_meshfunc()),
children: vec![ children: vec![
Child { Child {
rule: Rc::new(Rule { eval: main_.clone(), ctxt: () }), rule: Rc::new(Rule { eval: main_.clone(), ctxt: () }),
@ -138,6 +148,7 @@ pub fn barbs() -> Rule<()> {
Rule { eval: Rc::new(base), ctxt: () } Rule { eval: Rc::new(base), ctxt: () }
} }
/*
// Meant to be a copy of twist_from_gen from Python & // Meant to be a copy of twist_from_gen from Python &
// automata_scratch, but has since acquired a sort of life of its own // automata_scratch, but has since acquired a sort of life of its own
pub fn twist(f: f32, subdiv: usize) -> Rule<()> { pub fn twist(f: f32, subdiv: usize) -> Rule<()> {

View File

@ -36,7 +36,7 @@ mod tests {
println!("Evaluated {} rules to {} verts", nodes, mesh.verts.len()); println!("Evaluated {} rules to {} verts", nodes, mesh.verts.len());
let fname = format!("{}.stl", name); let fname = format!("{}.stl", name);
println!("Writing {}...", fname); println!("Writing {}...", fname);
mesh.write_stl_file(&fname).unwrap(); mesh.to_mesh().write_stl_file(&fname).unwrap();
} }
#[test] #[test]
@ -71,10 +71,12 @@ mod tests {
fn cube_thing() { fn cube_thing() {
run_test(examples::cube_thing(), 3, "cube_thing3", false); run_test(examples::cube_thing(), 3, "cube_thing3", false);
} }
*/
#[test] #[test]
fn barbs() { run_test(examples::barbs(), 20, "barbs", false); } fn barbs() { run_test(examples::barbs(), 20, "barbs", false); }
/*
#[test] #[test]
fn twist() { fn twist() {
run_test(examples::twist(1.0, 2), 200, "screw", false); run_test(examples::twist(1.0, 2), 200, "screw", false);

View File

@ -42,9 +42,9 @@ impl Mesh {
// Turn every face into an stl_io::Triangle: // Turn every face into an stl_io::Triangle:
for i in 0..num_faces { for i in 0..num_faces {
let v0 = self.verts[3*i + 0].xyz(); let v0 = self.verts[self.faces[3*i + 0]].xyz();
let v1 = self.verts[3*i + 1].xyz(); let v1 = self.verts[self.faces[3*i + 1]].xyz();
let v2 = self.verts[3*i + 2].xyz(); let v2 = self.verts[self.faces[3*i + 2]].xyz();
let normal = (v1-v0).cross(&(v2-v0)); let normal = (v1-v0).cross(&(v2-v0));
@ -62,8 +62,8 @@ impl Mesh {
stl_io::write_stl(writer, triangles.iter()) stl_io::write_stl(writer, triangles.iter())
} }
fn to_template(&self) -> MeshTemplate { fn to_meshfunc(&self) -> MeshFunc {
MeshTemplate { MeshFunc {
faces: self.faces.clone(), faces: self.faces.clone(),
verts: self.verts.iter().map(|v| VertexUnion::Vertex(*v)).collect(), verts: self.verts.iter().map(|v| VertexUnion::Vertex(*v)).collect(),
} }
@ -72,10 +72,11 @@ impl Mesh {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum VertexUnion { pub enum VertexUnion {
/// A concrete vertex /// A concrete vertex.
Vertex(Vertex), Vertex(Vertex),
/// An alias to some other vertex (by index) /// An 'unbound' vertex - something like an argument to a function with
Alias(usize), /// the given positional index.
Arg(usize),
} }
/// A face-vertex mesh whose vertices can either be concrete values /// A face-vertex mesh whose vertices can either be concrete values
@ -84,7 +85,7 @@ pub enum VertexUnion {
/// aliases are resolved to concrete vertices with a call like /// aliases are resolved to concrete vertices with a call like
/// `connect()`. /// `connect()`.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MeshTemplate { pub struct MeshFunc {
// //
pub verts: Vec<VertexUnion>, pub verts: Vec<VertexUnion>,
/// Indices of triangles (taken as every 3 values). Indices begin /// Indices of triangles (taken as every 3 values). Indices begin
@ -95,11 +96,21 @@ pub struct MeshTemplate {
pub faces: Vec<usize>, pub faces: Vec<usize>,
} }
impl MeshTemplate { impl MeshFunc {
/// Returns a new `MeshTemplate` whose concrete vertices have pub fn to_mesh(&self) -> Mesh {
Mesh {
faces: self.faces.clone(),
verts: self.verts.iter().map(|v| match *v {
VertexUnion::Vertex(v) => v,
VertexUnion::Arg(_) => panic!("Mesh still has vertex arguments!"),
}).collect(),
}
}
/// Returns a new `MeshFunc` whose concrete vertices have
/// been transformed. Note that alias vertices are left untouched. /// been transformed. Note that alias vertices are left untouched.
pub fn transform(&self, xfm: &Transform) -> MeshTemplate { pub fn transform(&self, xfm: &Transform) -> MeshFunc {
let v = self.verts.iter().map(|v| { let v = self.verts.iter().map(|v| {
match v { match v {
VertexUnion::Vertex(v) => VertexUnion::Vertex(xfm.mtx * v), VertexUnion::Vertex(v) => VertexUnion::Vertex(xfm.mtx * v),
@ -107,7 +118,7 @@ impl MeshTemplate {
} }
}); });
MeshTemplate { MeshFunc {
verts: v.collect(), verts: v.collect(),
faces: self.faces.clone(), faces: self.faces.clone(),
} }
@ -118,8 +129,8 @@ impl MeshTemplate {
/// corresponding input mesh was shifted. That is, for the i'th /// corresponding input mesh was shifted. That is, for the i'th
/// index in `meshes`, all of its triangle indices were shifted by /// index in `meshes`, all of its triangle indices were shifted by
/// the i'th offset in the resultant mesh. /// the i'th offset in the resultant mesh.
pub fn append<T, U>(meshes: T) -> (MeshTemplate, Vec<usize>) pub fn append<T, U>(meshes: T) -> (MeshFunc, Vec<usize>)
where U: Borrow<MeshTemplate>, where U: Borrow<MeshFunc>,
T: IntoIterator<Item = U> T: IntoIterator<Item = U>
{ {
let mut offsets: Vec<usize> = vec![]; let mut offsets: Vec<usize> = vec![];
@ -139,7 +150,7 @@ impl MeshTemplate {
f.extend(mesh.faces.iter().map(|n| n + offset)); f.extend(mesh.faces.iter().map(|n| n + offset));
} }
(MeshTemplate { verts: v, faces: f }, offsets) (MeshFunc { verts: v, faces: f }, offsets)
} }
/// Treat this mesh as a 'parent' mesh to connect with any number /// Treat this mesh as a 'parent' mesh to connect with any number
@ -151,8 +162,8 @@ impl MeshTemplate {
/// That is, the vertices of 'children[i]' begin at vertex /// That is, the vertices of 'children[i]' begin at vertex
/// 'offset[i]' of the new mesh. This is needed in some cases for /// 'offset[i]' of the new mesh. This is needed in some cases for
/// adjusting a parent vertex mapping, like 'vmap' of Rule::Child. /// adjusting a parent vertex mapping, like 'vmap' of Rule::Child.
pub fn connect<T, U>(&self, children: T) -> (MeshTemplate, Vec<usize>) pub fn connect<T, U>(&self, children: T) -> (MeshFunc, Vec<usize>)
where U: Borrow<MeshTemplate>, where U: Borrow<MeshFunc>,
T: IntoIterator<Item = (U, Vec<usize>)> T: IntoIterator<Item = (U, Vec<usize>)>
//pub fn connect(&self, children: &Vec<(OpenMesh, Vec<usize>)>) -> (OpenMesh, Vec<usize>) //pub fn connect(&self, children: &Vec<(OpenMesh, Vec<usize>)>) -> (OpenMesh, Vec<usize>)
{ {
@ -178,7 +189,7 @@ impl MeshTemplate {
verts.extend(child.verts.iter().filter_map(|v| { verts.extend(child.verts.iter().filter_map(|v| {
match v { match v {
VertexUnion::Vertex(_) => Some(v.clone()), VertexUnion::Vertex(_) => Some(v.clone()),
VertexUnion::Alias(_) => None, VertexUnion::Arg(_) => None,
} }
})); }));
@ -188,14 +199,14 @@ impl MeshTemplate {
faces.extend(child.faces.iter().map(|n| faces.extend(child.faces.iter().map(|n|
match child.verts[*n] { match child.verts[*n] {
VertexUnion::Vertex(_) => n + offset, VertexUnion::Vertex(_) => n + offset,
VertexUnion::Alias(m) => mapping[m], VertexUnion::Arg(m) => mapping[m],
} }
)); ));
offsets.push(offset); offsets.push(offset);
} }
let m = MeshTemplate { let m = MeshFunc {
verts: verts, verts: verts,
faces: faces, faces: faces,
}; };

View File

@ -1,4 +1,4 @@
use crate::mesh::{Mesh}; use crate::mesh::{Mesh, MeshFunc};
use crate::xform::{vertex, Transform}; use crate::xform::{vertex, Transform};
/// Returns an empty mesh (no vertices, no faces). /// Returns an empty mesh (no vertices, no faces).
@ -9,6 +9,14 @@ pub fn empty_mesh() -> Mesh {
} }
} }
/// Returns an empty MeshFn (no vertices, no faces, thus no args).
pub fn empty_meshfunc() -> MeshFunc {
MeshFunc {
verts: vec![],
faces: vec![],
}
}
/// Returns a cube of sidelength one centered at (0,0,0). /// Returns a cube of sidelength one centered at (0,0,0).
pub fn cube() -> Mesh { pub fn cube() -> Mesh {
Mesh { Mesh {

View File

@ -1,4 +1,4 @@
use crate::mesh::{MeshTemplate, VertexUnion}; use crate::mesh::{MeshFunc, VertexUnion};
use crate::xform::{Transform}; use crate::xform::{Transform};
//use crate::prim; //use crate::prim;
use std::borrow::Borrow; use std::borrow::Borrow;
@ -38,7 +38,7 @@ pub struct Rule<S> {
/// `geom`. /// `geom`.
pub struct RuleEval<S> { pub struct RuleEval<S> {
/// The geometry generated at just this iteration /// The geometry generated at just this iteration
pub geom: Rc<MeshTemplate>, pub geom: Rc<MeshFunc>,
/// The "final" geometry that is merged with `geom` via /// The "final" geometry that is merged with `geom` via
/// `connect()` in the event that recursion stops. This must be /// `connect()` in the event that recursion stops. This must be
@ -46,7 +46,7 @@ pub struct RuleEval<S> {
/// ///
/// Parent vertex references will be resolved directly to `geom` /// Parent vertex references will be resolved directly to `geom`
/// with no mapping. /// with no mapping.
pub final_geom: Rc<MeshTemplate>, pub final_geom: Rc<MeshFunc>,
/// The child invocations (used if recursion continues). The /// The child invocations (used if recursion continues). The
/// 'parent' mesh, from the perspective of all geometry produced /// 'parent' mesh, from the perspective of all geometry produced
@ -69,7 +69,7 @@ pub struct Child<S> {
/// The parent vertex mapping: a mapping to apply to turn a /// The parent vertex mapping: a mapping to apply to turn a
/// Tag::Parent vertex reference into a vertex index of the parent /// Tag::Parent vertex reference into a vertex index of the parent
/// mesh. That is, if `rule` produces a `MeshTemplate` with a face /// mesh. That is, if `rule` produces a `MeshFunc` with a face
/// of `Tag::Parent(n)`, this will correspond to index `vmap[n]` /// of `Tag::Parent(n)`, this will correspond to index `vmap[n]`
/// in the parent mesh. /// in the parent mesh.
pub vmap: Vec<usize>, pub vmap: Vec<usize>,
@ -80,7 +80,7 @@ impl<S> Rule<S> {
/// Convert this `Rule` to mesh data, recursively (depth first). /// Convert this `Rule` to mesh data, recursively (depth first).
/// `iters_left` sets the maximum recursion depth. This returns /// `iters_left` sets the maximum recursion depth. This returns
/// (geometry, number of rule evaluations). /// (geometry, number of rule evaluations).
pub fn to_mesh(s: Rc<Rule<S>>, iters_left: usize) -> (MeshTemplate, usize) { pub fn to_mesh(s: Rc<Rule<S>>, iters_left: usize) -> (MeshFunc, usize) {
let mut evals = 1; let mut evals = 1;
@ -95,7 +95,7 @@ impl<S> Rule<S> {
// TODO: This logic is more or less right, but it // TODO: This logic is more or less right, but it
// could perhaps use some un-tupling or something. // could perhaps use some un-tupling or something.
let subgeom: Vec<(MeshTemplate, Vec<usize>)> = rs.children.iter().map(|sub| { let subgeom: Vec<(MeshFunc, Vec<usize>)> = rs.children.iter().map(|sub| {
// Get sub-geometry (still un-transformed): // Get sub-geometry (still un-transformed):
let (submesh, eval) = Rule::to_mesh(sub.rule.clone(), iters_left - 1); let (submesh, eval) = Rule::to_mesh(sub.rule.clone(), iters_left - 1);
// Tally up eval count: // Tally up eval count:
@ -114,7 +114,7 @@ impl<S> Rule<S> {
/// This should be identical to to_mesh, but implemented /// This should be identical to to_mesh, but implemented
/// iteratively with an explicit stack rather than with recursive /// iteratively with an explicit stack rather than with recursive
/// function calls. /// function calls.
pub fn to_mesh_iter(s: Rc<Rule<S>>, max_depth: usize) -> (MeshTemplate, usize) { pub fn to_mesh_iter(s: Rc<Rule<S>>, max_depth: usize) -> (MeshFunc, usize) {
struct State<S> { struct State<S> {
// The set of rules we're currently handling: // The set of rules we're currently handling:
@ -187,7 +187,7 @@ impl<S> Rule<S> {
let mut m_ = 0; let mut m_ = 0;
for v in &final_geom.verts { for v in &final_geom.verts {
match *v { match *v {
VertexUnion::Alias(a) => { VertexUnion::Arg(a) => {
if a > m_ { if a > m_ {
m_ = a; m_ = a;
} }
@ -262,17 +262,17 @@ impl<S> Rule<S> {
} }
impl<S> RuleEval<S> { impl<S> RuleEval<S> {
/// Turn an iterator of (MeshTemplate, Child) into a single 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 `vmap` in each child has the
/// correct offsets applied to account for this merge. /// correct offsets applied to account for this merge.
/// ///
/// (`final_geom` is passed through to the RuleEval unmodified.) /// (`final_geom` is passed through to the RuleEval unmodified.)
pub fn from_pairs<T, U>(m: T, final_geom: MeshTemplate) -> RuleEval<S> pub fn from_pairs<T, U>(m: T, final_geom: MeshFunc) -> RuleEval<S>
where U: Borrow<MeshTemplate>, where U: Borrow<MeshFunc>,
T: IntoIterator<Item = (U, Child<S>)> T: IntoIterator<Item = (U, Child<S>)>
{ {
let (meshes, children): (Vec<_>, Vec<_>) = m.into_iter().unzip(); let (meshes, children): (Vec<_>, Vec<_>) = m.into_iter().unzip();
let (mesh, offsets) = MeshTemplate::append(meshes); let (mesh, offsets) = MeshFunc::append(meshes);
// Patch up vmap in each child, and copy everything else: // Patch up vmap in each child, and copy everything else:
let children2: Vec<Child<S>> = children.iter().zip(offsets.iter()).map(|(c,off)| { let children2: Vec<Child<S>> = children.iter().zip(offsets.iter()).map(|(c,off)| {

View File

@ -1,5 +1,5 @@
use std::ops::Range; use std::ops::Range;
use crate::mesh::{Mesh, MeshTemplate, VertexUnion}; use crate::mesh::{Mesh, MeshFunc, VertexUnion};
use crate::xform::{Vertex}; use crate::xform::{Vertex};
//use crate::rule::{Rule, Child}; //use crate::rule::{Rule, Child};
@ -19,6 +19,21 @@ macro_rules! vec_indexed {
}}; }};
} }
pub trait VecExt<T> {
fn append_indexed(&mut self, other: &mut Vec<T>) -> (usize, usize);
}
impl<T> VecExt<T> for Vec<T> {
// Like `append`, but returning `(a, b)` which give the range of
// elements just inserted.
fn append_indexed(&mut self, other: &mut Vec<T>) -> (usize, usize) {
let a = self.len();
self.append(other);
let b = self.len();
(a, b)
}
}
/// Linearly subdivides a list of points that are to be treated as a /// Linearly subdivides a list of points that are to be treated as a
/// cycle. This produces 'count' points for every element of 'p' /// cycle. This produces 'count' points for every element of 'p'
/// (thus, the returned length will be `count*p.len()`). /// (thus, the returned length will be `count*p.len()`).
@ -60,8 +75,8 @@ pub fn parallel_zigzag_faces(r1: Range<usize>, r2: Range<usize>) -> Vec<usize> {
}).flatten().collect() }).flatten().collect()
} }
pub fn zigzag_to_parent(verts: Vec<VertexUnion>, main: Range<usize>, parent: Range<usize>) -> MeshTemplate { pub fn parallel_zigzag(verts: Vec<VertexUnion>, main: Range<usize>, parent: Range<usize>) -> MeshFunc {
MeshTemplate { MeshFunc {
verts: verts, verts: verts,
faces: parallel_zigzag_faces(main, parent), faces: parallel_zigzag_faces(main, parent),
} }