One example is building and running, mostly
This commit is contained in:
parent
7626f1a089
commit
19988a0b35
@ -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<()> {
|
||||
|
||||
@ -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);
|
||||
|
||||
53
src/mesh.rs
53
src/mesh.rs
@ -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,
|
||||
};
|
||||
|
||||
10
src/prim.rs
10
src/prim.rs
@ -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 {
|
||||
|
||||
24
src/rule.rs
24
src/rule.rs
@ -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)| {
|
||||
|
||||
21
src/util.rs
21
src/util.rs
@ -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),
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user