Working direct-function-call example for 'barbs'

This commit is contained in:
Chris Hodapp 2020-10-05 23:15:54 -04:00
parent 17fbd4d3a3
commit 004f665e4b
4 changed files with 155 additions and 2 deletions

View File

@ -50,6 +50,110 @@ pub fn cube_thing() -> Rule<()> {
Rule { eval: Rc::new(rec), ctxt: () } Rule { eval: Rc::new(rec), ctxt: () }
} }
#[derive(Clone)]
pub struct BarbsCtxt {
base_incr: Transform,
barb_incr: Transform,
sides: [Transform; 4],
base: Vec<Vertex>,
verts: Vec<Vertex>,
faces: Vec<usize>,
}
impl BarbsCtxt {
pub fn new() -> BarbsCtxt {
// Incremental transform from each stage to the next:
let base_incr = id().translate(0.0, 0.0, 1.0).
rotate(&Vector3::z_axis(), 0.15).
rotate(&Vector3::x_axis(), 0.1).
scale(0.95);
let barb_incr = id().translate(0.0, 0.0, 0.5).
rotate(&Vector3::y_axis(), -0.2).
scale(0.8);
// 'Base' vertices, used throughout:
let base = vec![
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),
];
// sides[i] gives transformation from a 'base' layer to the
// i'th side (0 to 3):
let mut sides: [Transform; 4] = [id(); 4];
for i in 0..4 {
sides[i] = id().
rotate(&Vector3::z_axis(), -FRAC_PI_2 * (i as f32)).
rotate(&Vector3::y_axis(), -FRAC_PI_2).
translate(0.5, 0.0, 0.5);// * barb_incr;
}
BarbsCtxt {
base_incr: base_incr,
barb_incr: barb_incr,
base: base,
sides: sides,
verts: vec![],
faces: vec![],
}
}
pub fn barb(&mut self, iters: usize, xform: Transform, bound: [usize; 4]) {
if iters <= 0 {
self.faces.extend_from_slice(&[
bound[0], bound[2], bound[1],
bound[0], bound[3], bound[2],
]);
return;
}
let xform2 = xform * self.barb_incr;
let g = xform2.transform(&self.base);
let (a0, a1) = self.verts.append_indexed(g);
self.faces.append(&mut util::parallel_zigzag2(bound.to_vec(), a0..a1));
self.barb(iters - 1, xform2, [a0, a0+1, a0+2, a0+3]);
}
pub fn main(&mut self, iters: usize, xform: Transform, bound: [usize; 4]) {
if iters <= 0 {
self.faces.extend_from_slice(&[
bound[0], bound[2], bound[1],
bound[0], bound[3], bound[2],
]);
return;
}
let xform2 = xform * self.base_incr;
let g = xform2.transform(&self.base);
let (a0, _) = self.verts.append_indexed(g);
// TODO: Isn't there some cleaner way?
self.main(iters - 1, xform2, [a0, a0+1, a0+2, a0+3]);
self.barb(iters - 1, xform * self.sides[0], [bound[0], bound[1], a0+1, a0+0]);
self.barb(iters - 1, xform * self.sides[1], [bound[1], bound[2], a0+2, a0+1]);
self.barb(iters - 1, xform * self.sides[2], [bound[2], bound[3], a0+3, a0+2]);
self.barb(iters - 1, xform * self.sides[3], [bound[3], bound[0], a0+0, a0+3]);
}
pub fn run(mut self, iters: usize) -> Mesh {
self.verts.append(&mut self.base.clone());
self.faces.extend_from_slice(&[
0, 1, 2,
0, 2, 3,
]);
self.main(iters, id(), [0,1,2,3]);
return Mesh {
verts: self.verts,
faces: self.faces,
}
}
}
pub fn barbs(random: bool) -> Rule<()> { pub fn barbs(random: bool) -> Rule<()> {
let (b0, bn); let (b0, bn);

View File

@ -76,6 +76,21 @@ mod tests {
#[test] #[test]
fn barbs() { run_test(examples::barbs(false), 80, "barbs", false); } fn barbs() { run_test(examples::barbs(false), 80, "barbs", false); }
#[test]
fn barbs_direct() {
let name = "barbs_test";
println!("---------------------------------------------------");
let b = examples::BarbsCtxt::new();
let m = b.run(100);
println!("Got {} verts...", m.verts.len());
let fname = format!("{}.stl", name);
println!("Writing {}...", fname);
m.write_stl_file(&fname).unwrap();
}
#[test] #[test]
fn barbs_random() { run_test(examples::barbs(true), 80, "barbs_random", false); } fn barbs_random() { run_test(examples::barbs(true), 80, "barbs_random", false); }

View File

@ -217,7 +217,12 @@ impl MeshFunc {
faces.extend(child.faces.iter().map(|n| { faces.extend(child.faces.iter().map(|n| {
let f = match child.verts[*n] { let f = match child.verts[*n] {
VertexUnion::Vertex(_) => remap[*n], VertexUnion::Vertex(_) => remap[*n],
VertexUnion::Arg(m) => arg_vals[m], VertexUnion::Arg(m) => {
println!("remap face: vert {} arg {} = vert {} ({:?})",
*n, m, arg_vals[m], verts[arg_vals[m]]
);
arg_vals[m]
},
}; };
if f >= verts.len() { if f >= verts.len() {
panic!("face >= num_verts") panic!("face >= num_verts")

View File

@ -1,5 +1,5 @@
use std::ops::Range; use std::ops::Range;
use crate::mesh::{MeshFunc, VertexUnion}; use crate::mesh::{Mesh, MeshFunc, VertexUnion};
use crate::xform::{Vertex}; use crate::xform::{Vertex};
/// This is like `vec!`, but it can handle elements that are given /// This is like `vec!`, but it can handle elements that are given
@ -85,6 +85,35 @@ pub fn parallel_zigzag(verts: Vec<VertexUnion>, main: Range<usize>, parent: Rang
} }
} }
pub fn parallel_zigzag_mesh(verts: Vec<Vertex>, main: Range<usize>, parent: Range<usize>) -> Mesh {
Mesh {
verts: verts,
faces: parallel_zigzag_faces(main, parent),
}
}
pub fn parallel_zigzag2<T,U>(main: T, parent: U) -> Vec<usize>
where T: IntoIterator<Item=usize>, U: IntoIterator<Item=usize>
{
let m: Vec<usize> = main.into_iter().collect();
let p: Vec<usize> = parent.into_iter().collect();
let l = m.len();
if l != p.len() {
panic!("Vectors must be the same size!")
}
(0..l).map(|i0| {
// i0 is an *offset* for the 'current' index.
// i1 is for the 'next' index, wrapping back to 0.
let i1 = (i0 + 1) % l;
vec![
// Mind winding order!
m[i1], p[i0], m[i0],
p[i1], p[i0], m[i1],
]
}).flatten().collect()
}
pub fn centroid(verts: &Vec<Vertex>) -> Vertex { pub fn centroid(verts: &Vec<Vertex>) -> Vertex {
let n = verts.len(); let n = verts.len();
let mut centroid = Vertex::new(0.0, 0.0, 0.0, 0.0); let mut centroid = Vertex::new(0.0, 0.0, 0.0, 0.0);