Mesh stuff ugly-refactored but untested
This commit is contained in:
parent
0ad03ac77d
commit
7626f1a089
168
src/examples.rs
168
src/examples.rs
@ -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)]
|
||||
|
||||
@ -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;
|
||||
@ -63,6 +64,7 @@ mod tests {
|
||||
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
|
||||
|
||||
@ -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,19 +40,11 @@ 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));
|
||||
|
||||
@ -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();
|
||||
let offset = verts.len();
|
||||
|
||||
// Copy all vertices from 'child':
|
||||
verts.append(&mut child.verts.clone());
|
||||
|
||||
// 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,
|
||||
};
|
||||
34
src/prim.rs
34
src/prim.rs
@ -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))
|
||||
}
|
||||
|
||||
36
src/rule.rs
36
src/rule.rs
@ -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)| {
|
||||
|
||||
81
src/util.rs
81
src/util.rs
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user