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 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::rule::{Rule, RuleFn, RuleEval, Child};
use crate::prim;
@ -45,15 +46,16 @@ pub fn cube_thing() -> Rule<()> {
Rule { eval: Rc::new(rec), ctxt: () }
}
*/
pub fn barbs() -> Rule<()> {
let (a0, a1);
let base_verts: Vec<Vertex> = vec_indexed![
@a0: vertex(-0.5, -0.5, 0.0),
vertex(-0.5, 0.5, 0.0),
vertex( 0.5, 0.5, 0.0),
@a1: vertex( 0.5, -0.5, 0.0),
let (b0, b1);
let base_verts: Vec<VertexUnion> = vec_indexed![
@b0: VertexUnion::Vertex(vertex(-0.5, -0.5, 0.0)),
VertexUnion::Vertex(vertex(-0.5, 0.5, 0.0)),
VertexUnion::Vertex(vertex( 0.5, 0.5, 0.0)),
@b1: VertexUnion::Vertex(vertex( 0.5, -0.5, 0.0)),
];
let n = base_verts.len();
@ -64,19 +66,24 @@ pub fn barbs() -> Rule<()> {
let b = base_verts.clone();
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 {
verts: vec![vc],
alias_verts: vec![],
faces: faces,
});
*/
RuleEval {
geom: geom,
final_geom: final_geom,
geom: Rc::new(geom.transform(&incr)),
final_geom: Rc::new(prim::empty_meshfunc()), // TODO
children: vec![
Child {
rule: self_.clone(),
@ -89,20 +96,24 @@ pub fn barbs() -> Rule<()> {
let b = base_verts.clone();
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
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 final_geom = Rc::new(OpenMesh {
let final_geom = Rc::new(MeshFunc {
verts: vec![vc],
alias_verts: vec![],
faces: faces,
});
*/
RuleEval {
geom: geom,
final_geom: final_geom,
geom: Rc::new(geom.transform(&incr)),
final_geom: Rc::new(prim::empty_meshfunc()), // TODO
children: vec![
Child {
rule: self_.clone(),
@ -116,15 +127,14 @@ pub fn barbs() -> Rule<()> {
let main_ = Rc::new(main);
let base = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
RuleEval {
geom: Rc::new(OpenMesh {
geom: Rc::new(MeshFunc {
verts: base_verts.clone(),
alias_verts: vec![],
faces: vec![
0, 1, 2,
0, 1, 3,
b0, b0 + 1, b0 + 2,
b0, b0 + 2, b0 + 3,
],
}),
final_geom: Rc::new(prim::empty_mesh()),
final_geom: Rc::new(prim::empty_meshfunc()),
children: vec![
Child {
rule: Rc::new(Rule { eval: main_.clone(), ctxt: () }),
@ -138,6 +148,7 @@ pub fn barbs() -> Rule<()> {
Rule { eval: Rc::new(base), ctxt: () }
}
/*
// Meant to be a copy of twist_from_gen from Python &
// automata_scratch, but has since acquired a sort of life of its own
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());
let fname = format!("{}.stl", name);
println!("Writing {}...", fname);
mesh.write_stl_file(&fname).unwrap();
mesh.to_mesh().write_stl_file(&fname).unwrap();
}
#[test]
@ -71,10 +71,12 @@ mod tests {
fn cube_thing() {
run_test(examples::cube_thing(), 3, "cube_thing3", false);
}
*/
#[test]
fn barbs() { run_test(examples::barbs(), 20, "barbs", false); }
/*
#[test]
fn twist() {
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:
for i in 0..num_faces {
let v0 = self.verts[3*i + 0].xyz();
let v1 = self.verts[3*i + 1].xyz();
let v2 = self.verts[3*i + 2].xyz();
let v0 = self.verts[self.faces[3*i + 0]].xyz();
let v1 = self.verts[self.faces[3*i + 1]].xyz();
let v2 = self.verts[self.faces[3*i + 2]].xyz();
let normal = (v1-v0).cross(&(v2-v0));
@ -62,8 +62,8 @@ impl Mesh {
stl_io::write_stl(writer, triangles.iter())
}
fn to_template(&self) -> MeshTemplate {
MeshTemplate {
fn to_meshfunc(&self) -> MeshFunc {
MeshFunc {
faces: self.faces.clone(),
verts: self.verts.iter().map(|v| VertexUnion::Vertex(*v)).collect(),
}
@ -72,10 +72,11 @@ impl Mesh {
#[derive(Clone, Debug)]
pub enum VertexUnion {
/// A concrete vertex
/// A concrete vertex.
Vertex(Vertex),
/// An alias to some other vertex (by index)
Alias(usize),
/// An 'unbound' vertex - something like an argument to a function with
/// the given positional index.
Arg(usize),
}
/// 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
/// `connect()`.
#[derive(Clone, Debug)]
pub struct MeshTemplate {
pub struct MeshFunc {
//
pub verts: Vec<VertexUnion>,
/// Indices of triangles (taken as every 3 values). Indices begin
@ -95,11 +96,21 @@ pub struct MeshTemplate {
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.
pub fn transform(&self, xfm: &Transform) -> MeshTemplate {
pub fn transform(&self, xfm: &Transform) -> MeshFunc {
let v = self.verts.iter().map(|v| {
match v {
VertexUnion::Vertex(v) => VertexUnion::Vertex(xfm.mtx * v),
@ -107,7 +118,7 @@ impl MeshTemplate {
}
});
MeshTemplate {
MeshFunc {
verts: v.collect(),
faces: self.faces.clone(),
}
@ -118,8 +129,8 @@ impl MeshTemplate {
/// 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) -> (MeshTemplate, Vec<usize>)
where U: Borrow<MeshTemplate>,
pub fn append<T, U>(meshes: T) -> (MeshFunc, Vec<usize>)
where U: Borrow<MeshFunc>,
T: IntoIterator<Item = U>
{
let mut offsets: Vec<usize> = vec![];
@ -139,7 +150,7 @@ impl MeshTemplate {
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
@ -151,8 +162,8 @@ impl MeshTemplate {
/// 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.
pub fn connect<T, U>(&self, children: T) -> (MeshTemplate, Vec<usize>)
where U: Borrow<MeshTemplate>,
pub fn connect<T, U>(&self, children: T) -> (MeshFunc, Vec<usize>)
where U: Borrow<MeshFunc>,
T: IntoIterator<Item = (U, 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| {
match v {
VertexUnion::Vertex(_) => Some(v.clone()),
VertexUnion::Alias(_) => None,
VertexUnion::Arg(_) => None,
}
}));
@ -188,14 +199,14 @@ impl MeshTemplate {
faces.extend(child.faces.iter().map(|n|
match child.verts[*n] {
VertexUnion::Vertex(_) => n + offset,
VertexUnion::Alias(m) => mapping[m],
VertexUnion::Arg(m) => mapping[m],
}
));
offsets.push(offset);
}
let m = MeshTemplate {
let m = MeshFunc {
verts: verts,
faces: faces,
};

View File

@ -1,4 +1,4 @@
use crate::mesh::{Mesh};
use crate::mesh::{Mesh, MeshFunc};
use crate::xform::{vertex, Transform};
/// 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).
pub fn cube() -> Mesh {
Mesh {

View File

@ -1,4 +1,4 @@
use crate::mesh::{MeshTemplate, VertexUnion};
use crate::mesh::{MeshFunc, VertexUnion};
use crate::xform::{Transform};
//use crate::prim;
use std::borrow::Borrow;
@ -38,7 +38,7 @@ pub struct Rule<S> {
/// `geom`.
pub struct RuleEval<S> {
/// The geometry generated at just this iteration
pub geom: Rc<MeshTemplate>,
pub geom: Rc<MeshFunc>,
/// The "final" geometry that is merged with `geom` via
/// `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`
/// with no mapping.
pub final_geom: Rc<MeshTemplate>,
pub final_geom: Rc<MeshFunc>,
/// The child invocations (used if recursion continues). The
/// '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
/// 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]`
/// in the parent mesh.
pub vmap: Vec<usize>,
@ -80,7 +80,7 @@ impl<S> Rule<S> {
/// Convert this `Rule` to mesh data, recursively (depth first).
/// `iters_left` sets the maximum recursion depth. This returns
/// (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;
@ -95,7 +95,7 @@ impl<S> Rule<S> {
// TODO: This logic is more or less right, but it
// 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):
let (submesh, eval) = Rule::to_mesh(sub.rule.clone(), iters_left - 1);
// Tally up eval count:
@ -114,7 +114,7 @@ impl<S> Rule<S> {
/// This should be identical to to_mesh, but implemented
/// iteratively with an explicit stack rather than with recursive
/// 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> {
// The set of rules we're currently handling:
@ -187,7 +187,7 @@ impl<S> Rule<S> {
let mut m_ = 0;
for v in &final_geom.verts {
match *v {
VertexUnion::Alias(a) => {
VertexUnion::Arg(a) => {
if a > m_ {
m_ = a;
}
@ -262,17 +262,17 @@ impl<S> Rule<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
/// 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: MeshTemplate) -> RuleEval<S>
where U: Borrow<MeshTemplate>,
pub fn from_pairs<T, U>(m: T, final_geom: MeshFunc) -> RuleEval<S>
where U: Borrow<MeshFunc>,
T: IntoIterator<Item = (U, Child<S>)>
{
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:
let children2: Vec<Child<S>> = children.iter().zip(offsets.iter()).map(|(c,off)| {

View File

@ -1,5 +1,5 @@
use std::ops::Range;
use crate::mesh::{Mesh, MeshTemplate, VertexUnion};
use crate::mesh::{Mesh, MeshFunc, VertexUnion};
use crate::xform::{Vertex};
//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
/// cycle. This produces 'count' points for every element of 'p'
/// (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()
}
pub fn zigzag_to_parent(verts: Vec<VertexUnion>, main: Range<usize>, parent: Range<usize>) -> MeshTemplate {
MeshTemplate {
pub fn parallel_zigzag(verts: Vec<VertexUnion>, main: Range<usize>, parent: Range<usize>) -> MeshFunc {
MeshFunc {
verts: verts,
faces: parallel_zigzag_faces(main, parent),
}