Mesh stuff ugly-refactored but untested

This commit is contained in:
Chris Hodapp 2020-05-12 15:46:03 -04:00
parent 0ad03ac77d
commit 7626f1a089
6 changed files with 306 additions and 225 deletions

View File

@ -1,14 +1,15 @@
use std::rc::Rc;
use nalgebra::*;
use rand::Rng;
//pub mod examples;
use crate::openmesh::{OpenMesh, Tag};
use crate::xform::{Transform, vertex, Mat4};
use crate::util;
use crate::mesh::{Mesh, MeshTemplate};
use crate::xform::{Transform, Vertex, vertex, Mat4};
use crate::rule::{Rule, RuleFn, RuleEval, Child};
use crate::prim;
use crate::util;
/*
pub fn cube_thing() -> Rule<()> {
// Quarter-turn in radians:
@ -47,11 +48,12 @@ pub fn cube_thing() -> Rule<()> {
pub fn barbs() -> Rule<()> {
let base_verts = vec![
vertex(-0.5, -0.5, 0.0),
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),
vertex( 0.5, -0.5, 0.0),
@a1: vertex( 0.5, -0.5, 0.0),
];
let n = base_verts.len();
@ -64,10 +66,11 @@ pub fn barbs() -> Rule<()> {
let barb = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
let next_verts = incr.transform(&b);
let geom = Rc::new(util::zigzag_to_parent(next_verts.clone(), n));
let geom = Rc::new(util::zigzag_to_parent(next_verts.clone(), 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,
});
@ -93,6 +96,7 @@ pub fn barbs() -> Rule<()> {
let (vc, faces) = util::connect_convex(&next_verts, true);
let final_geom = Rc::new(OpenMesh {
verts: vec![vc],
alias_verts: vec![],
faces: faces,
});
@ -114,9 +118,10 @@ pub fn barbs() -> Rule<()> {
RuleEval {
geom: Rc::new(OpenMesh {
verts: base_verts.clone(),
alias_verts: vec![],
faces: vec![
Tag::Body(0), Tag::Body(1), Tag::Body(2),
Tag::Body(0), Tag::Body(2), Tag::Body(3),
0, 1, 2,
0, 1, 3,
],
}),
final_geom: Rc::new(prim::empty_mesh()),
@ -173,6 +178,7 @@ pub fn twist(f: f32, subdiv: usize) -> Rule<()> {
let (vc, faces) = util::connect_convex(&seed_next, true);
let final_geom = Rc::new(OpenMesh {
verts: vec![vc],
alias_verts: vec![],
faces: faces,
});
@ -212,7 +218,7 @@ pub fn twist(f: f32, subdiv: usize) -> Rule<()> {
// and in the process, generate faces for these seeds:
let (centroid, f) = util::connect_convex(&vs, false);
vs.push(centroid);
(OpenMesh { verts: vs, faces: f }, c)
(OpenMesh { verts: vs, faces: f, alias_verts: vec![] }, c)
};
// Generate 'count' children, shifted/rotated differently:
@ -247,6 +253,7 @@ pub fn nest_spiral_2() -> Rule<NestSpiral2Ctxt> {
let (vc, faces) = util::connect_convex(&seed, true);
let final_geom = Rc::new(OpenMesh {
verts: vec![vc],
alias_verts: vec![],
faces: faces,
});
@ -276,7 +283,7 @@ pub fn nest_spiral_2() -> Rule<NestSpiral2Ctxt> {
let (centroid, f) = util::connect_convex(&s2, false);
s2.push(centroid);
let n2 = s2.len();
let g = OpenMesh { verts: s2, faces: f };
let g = OpenMesh { verts: s2, faces: f, alias_verts: vec![] };
RuleEval {
geom: Rc::new(g.transform(&xf)),
final_geom: Rc::new(prim::empty_mesh()),
@ -369,6 +376,7 @@ pub fn twisty_torus() -> Rule<TorusCtxt> {
let (vc, faces) = util::connect_convex(&seed, true);
let final_geom = Rc::new(OpenMesh {
verts: vec![vc],
alias_verts: (0..(n+1)).collect(),
faces: faces,
});
@ -404,7 +412,7 @@ pub fn twisty_torus() -> Rule<TorusCtxt> {
let (centroid, f) = util::connect_convex(&s2, false);
s2.push(centroid);
let n2 = s2.len();
let g = OpenMesh { verts: s2, faces: f };
let g = OpenMesh { verts: s2, faces: f, alias_verts: vec![] };
RuleEval {
geom: Rc::new(g.transform(&xf)),
final_geom: Rc::new(prim::empty_mesh()),
@ -469,6 +477,7 @@ pub fn twisty_torus_hardcode() -> Rule<()> {
let (vc, faces) = util::connect_convex(&next, true);
let final_geom = Rc::new(OpenMesh {
verts: vec![vc],
alias_verts: (0..(n+1)).collect(), // TODO: Fix parent/connect_convex
faces: faces,
});
@ -497,7 +506,7 @@ pub fn twisty_torus_hardcode() -> Rule<()> {
let (centroid, f) = util::connect_convex(&s2, false);
s2.push(centroid);
let n2 = s2.len();
let g = OpenMesh { verts: s2, faces: f };
let g = OpenMesh { verts: s2, faces: f, alias_verts: vec![] };
RuleEval {
geom: Rc::new(g.transform(&xf)),
final_geom: Rc::new(prim::empty_mesh()),
@ -540,6 +549,7 @@ pub fn wind_chime_mistake_thing() -> Rule<WindChimeCtxt> {
let (vc, faces) = util::connect_convex(&seed, true);
let final_geom = Rc::new(OpenMesh {
verts: vec![vc],
alias_verts: (0..(n + 1)).collect(), // TODO: Check with parents (zigzag/connect_convex)
faces: faces,
});
@ -572,7 +582,7 @@ pub fn wind_chime_mistake_thing() -> Rule<WindChimeCtxt> {
let (centroid, f) = util::connect_convex(&s2, false);
s2.push(centroid);
let n2 = s2.len();
let g = OpenMesh { verts: s2, faces: f };
let g = OpenMesh { verts: s2, faces: f, alias_verts: vec![] };
RuleEval {
geom: Rc::new(g.transform(&xf)),
final_geom: Rc::new(prim::empty_mesh()),
@ -629,23 +639,25 @@ pub fn ramhorn() -> Rule<()> {
];
let next = incr.transform(&seed);
let geom = Rc::new(OpenMesh {
alias_verts: vec![0, 1, 2, 3],
verts: next,
faces: vec![
Tag::Body(1), Tag::Parent(0), Tag::Body(0),
Tag::Parent(1), Tag::Parent(0), Tag::Body(1),
Tag::Body(2), Tag::Parent(1), Tag::Body(1),
Tag::Parent(2), Tag::Parent(1), Tag::Body(2),
Tag::Body(3), Tag::Parent(2), Tag::Body(2),
Tag::Parent(3), Tag::Parent(2), Tag::Body(3),
Tag::Body(0), Tag::Parent(3), Tag::Body(3),
Tag::Parent(0), Tag::Parent(3), Tag::Body(0),
5, 0, 4,
1, 0, 5,
6, 1, 5,
2, 1, 6,
7, 2, 6,
3, 2, 7,
4, 3, 7,
0, 3, 4,
],
});
let final_geom = Rc::new(OpenMesh {
verts: vec![],
alias_verts: vec![0, 1, 2, 3],
faces: vec![
Tag::Parent(0), Tag::Parent(2), Tag::Parent(1),
Tag::Parent(0), Tag::Parent(3), Tag::Parent(2),
0, 2, 1,
0, 3, 2,
],
});
@ -695,27 +707,28 @@ pub fn ramhorn() -> Rule<()> {
vertex( 0.5, 0.5, 0.0), // 11
vertex( 0.5, -0.5, 0.0), // 12
],
alias_verts: vec![],
faces: vec![
// bottom face:
Tag::Body(9), Tag::Body(10), Tag::Body(11),
Tag::Body(9), Tag::Body(11), Tag::Body(12),
9, 10, 11,
9, 11, 12,
// two faces straddling edge from vertex 0:
Tag::Body(9), Tag::Body(0), Tag::Body(4),
Tag::Body(9), Tag::Body(7), Tag::Body(0),
9, 0, 4,
9, 7, 0,
// two faces straddling edge from vertex 1:
Tag::Body(10), Tag::Body(1), Tag::Body(5),
Tag::Body(10), Tag::Body(4), Tag::Body(1),
10, 1, 5,
10, 4, 1,
// two faces straddling edge from vertex 2:
Tag::Body(11), Tag::Body(2), Tag::Body(6),
Tag::Body(11), Tag::Body(5), Tag::Body(2),
11, 2, 6,
11, 5, 2,
// two faces straddling edge from vertex 3:
Tag::Body(12), Tag::Body(3), Tag::Body(7),
Tag::Body(12), Tag::Body(6), Tag::Body(3),
// four faces from edge (0,1), (1,2), (2,3), (3,0):
Tag::Body(9), Tag::Body(4), Tag::Body(10),
Tag::Body(10), Tag::Body(5), Tag::Body(11),
Tag::Body(11), Tag::Body(6), Tag::Body(12),
Tag::Body(12), Tag::Body(7), Tag::Body(9),
12, 3, 7,
12, 6, 3,
// four faces from edge (0,1, (1,2, (2,3, (3,0):
9, 4, 10,
10, 5, 11,
11, 6, 12,
12, 7, 9,
],
}),
final_geom: Rc::new(prim::empty_mesh()),
@ -772,13 +785,16 @@ pub fn ramhorn_branch(depth: usize, f: f32) -> Rule<RamHornCtxt> {
let next = incr.transform(&seed);
let geom = Rc::new(OpenMesh {
verts: next,
alias_verts: vec![],
faces: util::parallel_zigzag_faces(4),
// TODO: Fix this (parallel_zigzag_faces has parents)
});
let final_geom = Rc::new(OpenMesh {
verts: vec![],
alias_verts: vec![0, 1, 2, 3],
faces: vec![
Tag::Parent(0), Tag::Parent(2), Tag::Parent(1),
Tag::Parent(0), Tag::Parent(3), Tag::Parent(2),
0, 2, 1,
0, 3, 2,
],
});
@ -807,24 +823,25 @@ pub fn ramhorn_branch(depth: usize, f: f32) -> Rule<RamHornCtxt> {
];
let trans_faces = vec![
// two faces straddling edge from vertex 0:
Tag::Parent(0), Tag::Body(0), Tag::Body(4),
Tag::Parent(0), Tag::Body(7), Tag::Body(0),
0, 4, 8,
0, 11, 4,
// two faces straddling edge from vertex 1:
Tag::Parent(1), Tag::Body(1), Tag::Body(5),
Tag::Parent(1), Tag::Body(4), Tag::Body(1),
1, 5, 9,
1, 8, 5,
// two faces straddling edge from vertex 2:
Tag::Parent(2), Tag::Body(2), Tag::Body(6),
Tag::Parent(2), Tag::Body(5), Tag::Body(2),
2, 6, 10,
2, 9, 6,
// two faces straddling edge from vertex 3:
Tag::Parent(3), Tag::Body(3), Tag::Body(7),
Tag::Parent(3), Tag::Body(6), Tag::Body(3),
3, 7, 11,
3, 10, 7,
// four faces from edge (0,1), (1,2), (2,3), (3,0):
Tag::Parent(0), Tag::Body(4), Tag::Parent(1),
Tag::Parent(1), Tag::Body(5), Tag::Parent(2),
Tag::Parent(2), Tag::Body(6), Tag::Parent(3),
Tag::Parent(3), Tag::Body(7), Tag::Parent(0),
0, 8, 1,
1, 9, 2,
2, 10, 3,
3, 11, 0,
];
let trans_geom = Rc::new(OpenMesh {
alias_verts: vec![0, 1, 2, 3],
verts: trans_verts.clone(),
faces: trans_faces.clone(),
});
@ -899,9 +916,10 @@ pub fn ramhorn_branch(depth: usize, f: f32) -> Rule<RamHornCtxt> {
RuleEval {
geom: Rc::new(OpenMesh {
verts: Transform::new().translate(0.0, 0.0, -0.5).transform(&seed),
alias_verts: vec![],
faces: vec![
Tag::Body(0), Tag::Body(1), Tag::Body(2),
Tag::Body(0), Tag::Body(2), Tag::Body(3),
0, 1, 2,
0, 2, 3,
],
}),
final_geom: Rc::new(prim::empty_mesh()),
@ -941,12 +959,15 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule<RamHornCtxt2> {
let geom = Rc::new(OpenMesh {
verts: next,
faces: util::parallel_zigzag_faces(4),
alias_verts: vec![],
// TODO: Fix parents with parallel_zigzag
});
let final_geom = Rc::new(OpenMesh {
verts: vec![],
alias_verts: vec![0, 1, 2, 3],
faces: vec![
Tag::Parent(0), Tag::Parent(2), Tag::Parent(1),
Tag::Parent(0), Tag::Parent(3), Tag::Parent(2),
0, 2, 1,
0, 3, 2,
],
});
@ -975,24 +996,25 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule<RamHornCtxt2> {
];
let trans_faces = vec![
// two faces straddling edge from vertex 0:
Tag::Parent(0), Tag::Body(0), Tag::Body(4),
Tag::Parent(0), Tag::Body(7), Tag::Body(0),
0, 4, 8,
0, 11, 4,
// two faces straddling edge from vertex 1:
Tag::Parent(1), Tag::Body(1), Tag::Body(5),
Tag::Parent(1), Tag::Body(4), Tag::Body(1),
1, 5, 9,
1, 8, 5,
// two faces straddling edge from vertex 2:
Tag::Parent(2), Tag::Body(2), Tag::Body(6),
Tag::Parent(2), Tag::Body(5), Tag::Body(2),
2, 6, 10,
2, 9, 6,
// two faces straddling edge from vertex 3:
Tag::Parent(3), Tag::Body(3), Tag::Body(7),
Tag::Parent(3), Tag::Body(6), Tag::Body(3),
3, 7, 11,
3, 10, 7,
// four faces from edge (0,1), (1,2), (2,3), (3,0):
Tag::Parent(0), Tag::Body(4), Tag::Parent(1),
Tag::Parent(1), Tag::Body(5), Tag::Parent(2),
Tag::Parent(2), Tag::Body(6), Tag::Parent(3),
Tag::Parent(3), Tag::Body(7), Tag::Parent(0),
0, 8, 1,
1, 9, 2,
2, 10, 3,
3, 11, 0,
];
let trans_geom = Rc::new(OpenMesh {
alias_verts: vec![0, 1, 2, 3],
verts: trans_verts.clone(),
faces: trans_faces.clone(),
});
@ -1068,9 +1090,10 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule<RamHornCtxt2> {
RuleEval {
geom: Rc::new(OpenMesh {
verts: Transform::new().translate(0.0, 0.0, -0.5).transform(&seed),
alias_verts: vec![],
faces: vec![
Tag::Body(0), Tag::Body(1), Tag::Body(2),
Tag::Body(0), Tag::Body(2), Tag::Body(3),
0, 1, 2,
0, 2, 3,
],
}),
final_geom: Rc::new(prim::empty_mesh()),
@ -1086,6 +1109,7 @@ pub fn ramhorn_branch_random(depth: usize, f: f32) -> Rule<RamHornCtxt2> {
Rule { eval: Rc::new(start), ctxt: RamHornCtxt2 { depth } }
}
*/
/*
#[derive(Copy, Clone)]

View File

@ -1,9 +1,10 @@
pub mod examples;
pub mod openmesh;
pub mod mesh;
pub mod rule;
pub mod prim;
#[macro_use]
pub mod util;
pub mod xform;
pub mod examples;
//pub use crate::examples;
//pub use crate::openmesh::test_thing;
@ -62,7 +63,8 @@ mod tests {
geom.transform(&(trans * rot)).write_stl_file("xform_mul_trans_rot.stl").unwrap();
geom.transform(&xf1).write_stl_file("xform_trans_rot.stl").unwrap();
}
/*
// TODO: These tests don't test any conditions, so this is useful
// short-hand to run, but not very meaningful as a test.
#[test]
@ -127,6 +129,7 @@ mod tests {
fn ramhorn_branch_random() {
run_test(examples::ramhorn_branch_random(24, 0.25), 32, "ram_horn_branch_random", false);
}
*/
}
// need this for now:
// cargo test -- --nocapture

View File

@ -4,69 +4,18 @@ use std::borrow::Borrow;
use crate::xform::{Vertex, Transform};
/// A type for a 'tagged' vertex index referring either to an index of
/// a mesh, or of its parent.
/// Basic face-vertex mesh. `faces` contains indices of `verts` and is
/// taken in groups of 3 for each triangle.
#[derive(Clone, Debug)]
pub enum Tag {
Body(usize),
Parent(usize),
}
// TODO: This is clumsy. Can I do this some other way, or at least
// phrase it better?
/// A face-vertex mesh whose faces indices can refer either to its own
/// vertices, or to some 'parent' mesh.
#[derive(Clone, Debug)]
pub struct OpenMesh {
/// Vertices of mesh
pub struct Mesh {
pub verts: Vec<Vertex>,
/// Indices of triangles (taken as every 3 values). `Tag::Body`
/// indices correspond to `verts`, while `Tag::Parent` indices
/// correspond to some parent mesh that must eventually be given
/// to complete this mesh.
pub faces: Vec<Tag>,
pub faces: Vec<usize>,
}
impl 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 {
let mesh = mesh_.borrow();
// 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());
// Append its faces, applying offset:
f.extend(mesh.faces.iter().map(|t| {
match t {
Tag::Body(n) => Tag::Body(n + offset),
Tag::Parent(_) => panic!("Cannot append() if mesh has parent references!"),
// TODO: Handle the above
}
}));
}
(OpenMesh { verts: v, faces: f }, offsets)
}
/// Returns a new `OpenMesh` whose vertices have been transformed.
pub fn transform(&self, xfm: &Transform) -> OpenMesh {
OpenMesh {
impl Mesh {
/// Returns a new `Mesh` whose vertices have been transformed.
pub fn transform(&self, xfm: &Transform) -> Mesh {
Mesh {
verts: xfm.transform(&self.verts),
// TODO: Is the above faster if I pack vectors into a
// bigger matrix, and transform that?
@ -91,20 +40,12 @@ impl OpenMesh {
vertices: [[0.0; 3]; 3],
}; num_faces];
let get_vert = |j| {
match self.faces[j] {
Tag::Body(n) => self.verts[n].xyz(),
Tag::Parent(_) => panic!("Cannot write_stl() if mesh has parent references!"),
}
};
// TODO: Handle this behavior
// Turn every face into an stl_io::Triangle:
for i in 0..num_faces {
let v0 = get_vert(3*i + 0);
let v1 = get_vert(3*i + 1);
let v2 = get_vert(3*i + 2);
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 normal = (v1-v0).cross(&(v2-v0));
triangles[i].normal.copy_from_slice(&normal.as_slice());
@ -121,6 +62,86 @@ impl OpenMesh {
stl_io::write_stl(writer, triangles.iter())
}
fn to_template(&self) -> MeshTemplate {
MeshTemplate {
faces: self.faces.clone(),
verts: self.verts.iter().map(|v| VertexUnion::Vertex(*v)).collect(),
}
}
}
#[derive(Clone, Debug)]
pub enum VertexUnion {
/// A concrete vertex
Vertex(Vertex),
/// An alias to some other vertex (by index)
Alias(usize),
}
/// A face-vertex mesh whose vertices can either be concrete values
/// (as in `Mesh`) or aliases (indices to other vertices of some
/// hypothetical mesh). This can be turned to `mesh` only if those
/// aliases are resolved to concrete vertices with a call like
/// `connect()`.
#[derive(Clone, Debug)]
pub struct MeshTemplate {
//
pub verts: Vec<VertexUnion>,
/// Indices of triangles (taken as every 3 values). Indices begin
/// with `alias_verts`, and then continue into `verts` - that is,
/// from `0..alias_verts.len()` they refer to `alias_verts`, and from
/// `alias_verts.len()..(alias_verts.len()+verts.len())` they refer to
/// `verts`.
pub faces: Vec<usize>,
}
impl MeshTemplate {
/// Returns a new `MeshTemplate` whose concrete vertices have
/// been transformed. Note that alias vertices are left untouched.
pub fn transform(&self, xfm: &Transform) -> MeshTemplate {
let v = self.verts.iter().map(|v| {
match v {
VertexUnion::Vertex(v) => VertexUnion::Vertex(xfm.mtx * v),
a@_ => a.clone(),
}
});
MeshTemplate {
verts: v.collect(),
faces: self.faces.clone(),
}
}
/// 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) -> (MeshTemplate, Vec<usize>)
where U: Borrow<MeshTemplate>,
T: IntoIterator<Item = U>
{
let mut offsets: Vec<usize> = vec![];
let mut v: Vec<VertexUnion> = vec![];
let mut f: Vec<usize> = vec![];
for mesh_ in meshes {
let mesh = mesh_.borrow();
// 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());
// Append its faces, applying offset:
f.extend(mesh.faces.iter().map(|n| n + offset));
}
(MeshTemplate { verts: v, faces: f }, offsets)
}
/// Treat this mesh as a 'parent' mesh to connect with any number
/// of 'child' meshes, all of them paired with their respective
/// parent vertex mappings. This returns a tuple of (new mesh,
@ -130,8 +151,8 @@ impl OpenMesh {
/// 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) -> (OpenMesh, Vec<usize>)
where U: Borrow<OpenMesh>,
pub fn connect<T, U>(&self, children: T) -> (MeshTemplate, Vec<usize>)
where U: Borrow<MeshTemplate>,
T: IntoIterator<Item = (U, Vec<usize>)>
//pub fn connect(&self, children: &Vec<(OpenMesh, Vec<usize>)>) -> (OpenMesh, Vec<usize>)
{
@ -139,7 +160,7 @@ impl OpenMesh {
// TODO: Clean up Vec<usize> stuff
// Copy body vertices & faces:
let mut verts: Vec<Vertex> = self.verts.clone();
let mut verts: Vec<VertexUnion> = self.verts.clone();
let mut faces = self.faces.clone();
let mut offsets: Vec<usize> = vec![];
@ -148,29 +169,33 @@ impl OpenMesh {
let child = child_.borrow();
// body_offset corresponds to the position in 'verts' at
// offset corresponds to the position in 'verts' at
// which we're appending everything in 'child.verts' -
// thus, the offset we shift all indices in 'children' by.
let body_offset = verts.len();
// Copy all vertices from 'child':
verts.append(&mut child.verts.clone());
let offset = verts.len();
// Append its faces:
faces.extend(child.faces.iter().map(|t| {
match t {
// Apply aforementioned shift to its body vertices:
Tag::Body(n) => Tag::Body(n + body_offset),
// Since 'self' vertices are in the same order,
// parent vertex references retain same index:
Tag::Parent(n) => Tag::Body(mapping[*n]),
// Concrete vertices in 'child.verts' need to be copied:
verts.extend(child.verts.iter().filter_map(|v| {
match v {
VertexUnion::Vertex(_) => Some(v.clone()),
VertexUnion::Alias(_) => None,
}
}));
offsets.push(body_offset);
// All faces need copied, but if if the index was to
// a concrete vertex, then it needs shifted by 'offset';
// if an alias, it needs remapped.
faces.extend(child.faces.iter().map(|n|
match child.verts[*n] {
VertexUnion::Vertex(_) => n + offset,
VertexUnion::Alias(m) => mapping[m],
}
));
offsets.push(offset);
}
let m = OpenMesh {
let m = MeshTemplate {
verts: verts,
faces: faces,
};

View File

@ -1,17 +1,17 @@
use crate::openmesh::{OpenMesh, Tag};
use crate::mesh::{Mesh};
use crate::xform::{vertex, Transform};
/// Returns an empty mesh (no vertices, no faces).
pub fn empty_mesh() -> OpenMesh {
OpenMesh {
pub fn empty_mesh() -> Mesh {
Mesh {
verts: vec![],
faces: vec![],
}
}
/// Returns a cube of sidelength one centered at (0,0,0).
pub fn cube() -> OpenMesh {
OpenMesh {
pub fn cube() -> Mesh {
Mesh {
verts: vec![
vertex(0.0, 0.0, 0.0),
vertex(1.0, 0.0, 0.0),
@ -23,18 +23,18 @@ pub fn cube() -> OpenMesh {
vertex(1.0, 1.0, 1.0),
],
faces: vec![
Tag::Body(0), Tag::Body(3), Tag::Body(1),
Tag::Body(0), Tag::Body(2), Tag::Body(3),
Tag::Body(1), Tag::Body(7), Tag::Body(5),
Tag::Body(1), Tag::Body(3), Tag::Body(7),
Tag::Body(5), Tag::Body(6), Tag::Body(4),
Tag::Body(5), Tag::Body(7), Tag::Body(6),
Tag::Body(4), Tag::Body(2), Tag::Body(0),
Tag::Body(4), Tag::Body(6), Tag::Body(2),
Tag::Body(2), Tag::Body(7), Tag::Body(3),
Tag::Body(2), Tag::Body(6), Tag::Body(7),
Tag::Body(0), Tag::Body(1), Tag::Body(5),
Tag::Body(0), Tag::Body(5), Tag::Body(4),
0, 3, 1,
0, 2, 3,
1, 7, 5,
1, 3, 7,
5, 6, 4,
5, 7, 6,
4, 2, 0,
4, 6, 2,
2, 7, 3,
2, 6, 7,
0, 1, 5,
0, 5, 4,
],
}.transform(&Transform::new().translate(-0.5, -0.5, -0.5))
}

View File

@ -1,4 +1,4 @@
use crate::openmesh::{OpenMesh, Tag};
use crate::mesh::{MeshTemplate, 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<OpenMesh>,
pub geom: Rc<MeshTemplate>,
/// 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<OpenMesh>,
pub final_geom: Rc<MeshTemplate>,
/// 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 an `OpenMesh` with a face
/// mesh. That is, if `rule` produces a `MeshTemplate` 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) -> (OpenMesh, usize) {
pub fn to_mesh(s: Rc<Rule<S>>, iters_left: usize) -> (MeshTemplate, 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<(OpenMesh, Vec<usize>)> = rs.children.iter().map(|sub| {
let subgeom: Vec<(MeshTemplate, 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) -> (OpenMesh, usize) {
pub fn to_mesh_iter(s: Rc<Rule<S>>, max_depth: usize) -> (MeshTemplate, usize) {
struct State<S> {
// The set of rules we're currently handling:
@ -185,14 +185,14 @@ impl<S> Rule<S> {
// actually need vmap.
let m = {
let mut m_ = 0;
for f in &final_geom.faces {
match f {
Tag::Parent(i) => {
if *i > m_ {
m_ = *i;
for v in &final_geom.verts {
match *v {
VertexUnion::Alias(a) => {
if a > m_ {
m_ = a;
}
}
_ => {}
},
VertexUnion::Vertex(_) => (),
}
}
m_ + 1
@ -262,17 +262,17 @@ impl<S> Rule<S> {
}
impl<S> RuleEval<S> {
/// Turn an iterator of (OpenMesh, Child) into a single RuleEval.
/// Turn an iterator of (MeshTemplate, 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<S>
where U: Borrow<OpenMesh>,
pub fn from_pairs<T, U>(m: T, final_geom: MeshTemplate) -> RuleEval<S>
where U: Borrow<MeshTemplate>,
T: IntoIterator<Item = (U, Child<S>)>
{
let (meshes, children): (Vec<_>, Vec<_>) = m.into_iter().unzip();
let (mesh, offsets) = OpenMesh::append(meshes);
let (mesh, offsets) = MeshTemplate::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,7 +1,24 @@
use crate::openmesh::{Tag, OpenMesh};
use std::ops::Range;
use crate::mesh::{Mesh, MeshTemplate, VertexUnion};
use crate::xform::{Vertex};
//use crate::rule::{Rule, Child};
/// This is like `vec!`, but it can handle elements that are given
/// with `@var: element` rather than `element`, e.g. like
/// `vec_indexed![foo, bar, @a: baz, quux]`. The variable (which must
/// already be declared and a `usize`) is then assigned the index of the
/// element it precedes. This can be used any number of times with
/// different elements and indices.
#[macro_export]
macro_rules! vec_indexed {
// Thank you to GhostOfSteveJobs and Rantanen in the Rust discord.
($( $(@ $Index:ident :)? $Value:expr,)*) => {{
let mut v = Vec::new();
$( $($Index = v.len();)? v.push($Value); )*
v
}};
}
/// 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()`).
@ -21,45 +38,57 @@ pub fn subdivide_cycle(p: &Vec<Vertex>, count: usize) -> Vec<Vertex> {
// TODO: This can be generalized to an iterator or to IntoIterator
// trait bound
pub fn parallel_zigzag_faces(count: usize) -> Vec<Tag> {
pub fn parallel_zigzag_faces(r1: Range<usize>, r2: Range<usize>) -> Vec<usize> {
let count = r1.end - r1.start;
if (r2.end - r2.start) != count {
panic!("Ranges must have the same size");
}
if (r2.end > r1.start && r2.end < r1.end) ||
(r1.end > r2.start && r1.end < r2.end) {
panic!("Ranges cannot overlap");
}
(0..count).map(|i0| {
let i1 = (i0+1) % count;
// i0 is an *offset* for the 'current' index.
// i1 is for the 'next' index, wrapping back to 0.
let i1 = (i0 + 1) % count;
vec![
Tag::Body(i1), Tag::Parent(i0), Tag::Body(i0),
Tag::Parent(i1), Tag::Parent(i0), Tag::Body(i1),
// Mind winding order!
r1.start + i1, r2.start + i0, r1.start + i0,
r2.start + i1, r2.start + i0, r1.start + i1,
]
}).flatten().collect()
}
pub fn zigzag_to_parent(verts: Vec<Vertex>, count: usize) -> OpenMesh {
OpenMesh {
pub fn zigzag_to_parent(verts: Vec<VertexUnion>, main: Range<usize>, parent: Range<usize>) -> MeshTemplate {
MeshTemplate {
verts: verts,
faces: parallel_zigzag_faces(count),
faces: parallel_zigzag_faces(main, parent),
}
}
pub fn connect_convex(verts: &Vec<Vertex>, as_parent: bool) -> (Vertex, Vec<Tag>) {
pub fn centroid(verts: &Vec<Vertex>) -> Vertex {
let n = verts.len();
let mut centroid = Vertex::new(0.0, 0.0, 0.0, 0.0);
for v in verts {
centroid += v;
}
centroid /= n as f32;
let faces: Vec<Tag> = {
if as_parent {
(0..n).map(|f1| {
let f2 = (f1 + 1) % n;
vec![Tag::Parent(f2), Tag::Parent(f1), Tag::Body(0)]
}).flatten().collect()
} else {
(0..n).map(|f1| {
let f2 = (f1 + 1) % n;
// n is used for new center vertex
vec![Tag::Body(f1), Tag::Body(f2), Tag::Body(n)]
}).flatten().collect()
}
};
(centroid, faces)
centroid
}
pub fn connect_convex(range: Range<usize>, target: usize, as_parent: bool) -> Vec<usize> {
let count = range.end - range.start;
if as_parent {
(0..count).map(|i0| {
let i1 = (i0 + 1) % count;
vec![range.start + i1, range.start + i0, target]
}).flatten().collect()
} else {
(0..count).map(|i0| {
let i1 = (i0 + 1) % count;
vec![range.start + i0, range.start + i1, target]
}).flatten().collect()
}
}