Misc formatting & not-yet-ready NestedSpiral example
This commit is contained in:
parent
a664dbba16
commit
51cab46299
@ -367,3 +367,94 @@ impl Sierpinski {
|
||||
return s < 0.01;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NestedSpiral {
|
||||
base: Vec<Vertex>,
|
||||
verts: Vec<Vertex>,
|
||||
faces: Vec<usize>,
|
||||
seeds: Vec<Transform>,
|
||||
incr: Vec<Transform>,
|
||||
max_count: usize,
|
||||
}
|
||||
|
||||
impl NestedSpiral {
|
||||
pub fn new() -> NestedSpiral {
|
||||
let d = vertex(0.5, 0.0, 0.5);
|
||||
// 'Base' vertices, used throughout:
|
||||
let mut base = vec![
|
||||
(vertex(-0.5, 0.0, -0.5)),
|
||||
(vertex(0.5, 0.0, -0.5)),
|
||||
(vertex(0.5, 0.0, 0.5)),
|
||||
(vertex(-0.5, 0.0, 0.5)),
|
||||
];
|
||||
base = id().scale(0.3).transform(&base);
|
||||
// TODO: Check winding order
|
||||
|
||||
let rot_y = |ang| id().rotate(&Vector3::y_axis(), ang);
|
||||
let rot_y_and_trans = |ang, dx| rot_y(ang).translate(dx, 0.0, 0.0);
|
||||
|
||||
// Pairs of (seed transform, incremental transform):
|
||||
let xforms: Vec<(Transform, Transform)> = vec![
|
||||
(id(), id().translate(0.0, 0.1, 0.0)),
|
||||
(rot_y_and_trans(0.0, 3.0), rot_y(-0.03)),
|
||||
(rot_y_and_trans(0.0, 1.0), rot_y(0.07)),
|
||||
(rot_y_and_trans(0.0, 0.5), rot_y(-0.2)),
|
||||
];
|
||||
// TODO: Does it make sense that this should be the reverse of the Python ones?
|
||||
|
||||
// TODO: I still need Cartesian product of various different seeds.
|
||||
// e.g. rot_y_and_trans(0.0, 0.5) should be N entries with various rotations
|
||||
// instead of 0.0.
|
||||
|
||||
let (seeds, incr) = xforms.iter().cloned().unzip();
|
||||
|
||||
NestedSpiral {
|
||||
base: base,
|
||||
verts: vec![],
|
||||
faces: vec![],
|
||||
incr: incr,
|
||||
seeds: seeds,
|
||||
max_count: 500,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn incr(&mut self, idx: usize, b: [usize; 4], xforms: Vec<Transform>) {
|
||||
|
||||
if idx >= self.max_count {
|
||||
self.faces.extend_from_slice(&[b[0], b[2], b[1], b[0], b[3], b[2]]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute global transform with product of all 'xforms':
|
||||
let global = xforms.iter().fold(id(), |acc, m| acc * (*m));
|
||||
|
||||
// Generate geometry:
|
||||
let g = global.transform(&self.base);
|
||||
let (n0, n1) = self.verts.append_indexed(g);
|
||||
self.faces.append(&mut util::parallel_zigzag2(b.to_vec(), n0..n1));
|
||||
|
||||
// Increment the individual transformations:
|
||||
let xforms_next: Vec<Transform> = xforms.iter()
|
||||
.zip(self.incr.iter())
|
||||
.map(|(m,incr)| ((*incr) * (*m)))
|
||||
.collect();
|
||||
|
||||
self.incr(idx + 1, [n0, n0 + 1, n0 + 2, n0 + 3], xforms_next);
|
||||
}
|
||||
|
||||
pub fn run(mut self) -> Mesh {
|
||||
// TODO: Generate all seed geometry & transforms
|
||||
|
||||
let global = self.seeds.iter().fold(id(), |acc, m| acc * (*m));
|
||||
let g = global.transform(&self.base);
|
||||
let (n0, n1) = self.verts.append_indexed(g);
|
||||
//let (n0, _) = self.verts.append_indexed(self.base.clone());
|
||||
|
||||
self.incr(0, [n0, n0 + 1, n0 + 2, n0 + 3], self.seeds.clone());
|
||||
|
||||
return Mesh {
|
||||
verts: self.verts,
|
||||
faces: self.faces,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
49
src/lib.rs
49
src/lib.rs
@ -3,8 +3,8 @@ pub mod mesh;
|
||||
pub mod prim;
|
||||
#[macro_use]
|
||||
pub mod util;
|
||||
pub mod xform;
|
||||
pub mod examples;
|
||||
pub mod xform;
|
||||
|
||||
//pub use crate::examples;
|
||||
//pub use crate::openmesh::test_thing;
|
||||
@ -12,9 +12,9 @@ pub mod examples;
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use nalgebra::*;
|
||||
use std::rc::Rc;
|
||||
use std::time::Instant;
|
||||
use nalgebra::*;
|
||||
|
||||
#[test]
|
||||
fn xform_order() {
|
||||
@ -24,7 +24,7 @@ mod tests {
|
||||
|
||||
let dx = 4.0;
|
||||
let r = -0.5;
|
||||
|
||||
|
||||
let trans = xform::Transform::new().translate(dx, 0.0, 0.0);
|
||||
let rot = xform::Transform::new().rotate(y, r);
|
||||
|
||||
@ -32,13 +32,27 @@ mod tests {
|
||||
let xf2 = rot.translate(dx, 0.0, 0.0);
|
||||
|
||||
// Rotate entire space, *then* translate in that rotated plane:
|
||||
geom.transform(&trans).transform(&rot).write_stl_file("xform_apply_trans_rot.stl").unwrap();
|
||||
geom.transform(&(rot * trans)).write_stl_file("xform_mul_rot_trans.stl").unwrap();
|
||||
geom.transform(&xf2).write_stl_file("xform_rot_trans.stl").unwrap();
|
||||
geom.transform(&trans)
|
||||
.transform(&rot)
|
||||
.write_stl_file("xform_apply_trans_rot.stl")
|
||||
.unwrap();
|
||||
geom.transform(&(rot * trans))
|
||||
.write_stl_file("xform_mul_rot_trans.stl")
|
||||
.unwrap();
|
||||
geom.transform(&xf2)
|
||||
.write_stl_file("xform_rot_trans.stl")
|
||||
.unwrap();
|
||||
// Translate cube, *then* rotate it:
|
||||
geom.transform(&rot).transform(&trans).write_stl_file("xform_apply_rot_trans.stl").unwrap();
|
||||
geom.transform(&(trans * rot)).write_stl_file("xform_mul_trans_rot.stl").unwrap();
|
||||
geom.transform(&xf1).write_stl_file("xform_trans_rot.stl").unwrap();
|
||||
geom.transform(&rot)
|
||||
.transform(&trans)
|
||||
.write_stl_file("xform_apply_rot_trans.stl")
|
||||
.unwrap();
|
||||
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
|
||||
@ -55,7 +69,6 @@ mod tests {
|
||||
let fname = format!("{}.stl", name);
|
||||
println!("Writing {}...", fname);
|
||||
m.write_stl_file(&fname).unwrap();
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -70,7 +83,6 @@ mod tests {
|
||||
let fname = format!("{}.stl", name);
|
||||
println!("Writing {}...", fname);
|
||||
m.write_stl_file(&fname).unwrap();
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -85,7 +97,6 @@ mod tests {
|
||||
let fname = format!("{}.stl", name);
|
||||
println!("Writing {}...", fname);
|
||||
m.write_stl_file(&fname).unwrap();
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -101,7 +112,21 @@ mod tests {
|
||||
let fname = format!("{}.stl", name);
|
||||
println!("Writing {}...", fname);
|
||||
m.write_stl_file(&fname).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_spiral() {
|
||||
let name = "nested_spiral";
|
||||
println!("---------------------------------------------------");
|
||||
let b = examples::NestedSpiral::new();
|
||||
//let b = examples::Sierpinski::new(0.51, 0.10, 0.1);
|
||||
let m = b.run();
|
||||
|
||||
println!("Got {} verts...", m.verts.len());
|
||||
|
||||
let fname = format!("{}.stl", name);
|
||||
println!("Writing {}...", fname);
|
||||
m.write_stl_file(&fname).unwrap();
|
||||
}
|
||||
}
|
||||
// need this for now:
|
||||
|
||||
28
src/mesh.rs
28
src/mesh.rs
@ -1,7 +1,7 @@
|
||||
use std::fs::OpenOptions;
|
||||
use std::io;
|
||||
|
||||
use crate::xform::{Vertex, Transform};
|
||||
use crate::xform::{Transform, Vertex};
|
||||
|
||||
/// Basic face-vertex mesh. `faces` contains indices of `verts` and is
|
||||
/// taken in groups of 3 for each triangle.
|
||||
@ -25,27 +25,33 @@ impl Mesh {
|
||||
/// Write this mesh as an STL file. This will fail if any element
|
||||
/// of `faces` is `Tag::Parent`.
|
||||
pub fn write_stl_file(&self, fname: &str) -> io::Result<()> {
|
||||
let mut file = OpenOptions::new().write(true).create(true).truncate(true).open(fname)?;
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(fname)?;
|
||||
self.write_stl(&mut file)
|
||||
}
|
||||
|
||||
fn write_stl<W: std::io::Write>(&self, writer: &mut W) -> io::Result<()> {
|
||||
|
||||
// Every group of 3 indices in self.faces is one triangle, so
|
||||
// pre-allocate in the format stl_io wants:
|
||||
let num_faces = self.faces.len() / 3;
|
||||
let mut triangles = vec![stl_io::Triangle {
|
||||
normal: [0.0; 3],
|
||||
vertices: [[0.0; 3]; 3],
|
||||
}; num_faces];
|
||||
let mut triangles = vec![
|
||||
stl_io::Triangle {
|
||||
normal: [0.0; 3],
|
||||
vertices: [[0.0; 3]; 3],
|
||||
};
|
||||
num_faces
|
||||
];
|
||||
|
||||
// Turn every face into an stl_io::Triangle:
|
||||
for i in 0..num_faces {
|
||||
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 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));
|
||||
let normal = (v1 - v0).cross(&(v2 - v0));
|
||||
|
||||
triangles[i].normal.copy_from_slice(&normal.as_slice());
|
||||
triangles[i].vertices[0].copy_from_slice(v0.as_slice());
|
||||
|
||||
19
src/prim.rs
19
src/prim.rs
@ -1,4 +1,4 @@
|
||||
use crate::mesh::{Mesh};
|
||||
use crate::mesh::Mesh;
|
||||
use crate::xform::{vertex, Transform};
|
||||
|
||||
/// Returns an empty mesh (no vertices, no faces).
|
||||
@ -23,18 +23,9 @@ pub fn cube() -> Mesh {
|
||||
vertex(1.0, 1.0, 1.0),
|
||||
],
|
||||
faces: vec![
|
||||
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,
|
||||
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))
|
||||
}
|
||||
.transform(&Transform::new().translate(-0.5, -0.5, -0.5))
|
||||
}
|
||||
|
||||
108
src/util.rs
108
src/util.rs
@ -1,6 +1,6 @@
|
||||
use crate::mesh::Mesh;
|
||||
use crate::xform::Vertex;
|
||||
use std::ops::Range;
|
||||
use crate::mesh::{Mesh};
|
||||
use crate::xform::{Vertex};
|
||||
|
||||
/// This is like `vec!`, but it can handle elements that are given
|
||||
/// with `@var element` rather than `element`, e.g. like
|
||||
@ -42,40 +42,49 @@ impl<T> VecExt<T> for Vec<T> {
|
||||
/// (thus, the returned length will be `count*p.len()`).
|
||||
pub fn subdivide_cycle(p: &Vec<Vertex>, count: usize) -> Vec<Vertex> {
|
||||
let n = p.len();
|
||||
(0..n).map(|i| {
|
||||
// The inner loop is interpolating between v1 and v2:
|
||||
let v1 = &p[i];
|
||||
let v2 = &p[(i+1) % n];
|
||||
(0..count).map(move |j| {
|
||||
// This is just lerping in count+1 equally spaced steps:
|
||||
let f = (j as f32) / (count as f32);
|
||||
v1*(1.0-f) + v2*f
|
||||
(0..n)
|
||||
.map(|i| {
|
||||
// The inner loop is interpolating between v1 and v2:
|
||||
let v1 = &p[i];
|
||||
let v2 = &p[(i + 1) % n];
|
||||
(0..count).map(move |j| {
|
||||
// This is just lerping in count+1 equally spaced steps:
|
||||
let f = (j as f32) / (count as f32);
|
||||
v1 * (1.0 - f) + v2 * f
|
||||
})
|
||||
})
|
||||
}).flatten().collect()
|
||||
.flatten()
|
||||
.collect()
|
||||
}
|
||||
// TODO: This can be generalized to an iterator or to IntoIterator
|
||||
// trait bound
|
||||
|
||||
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 {
|
||||
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) {
|
||||
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| {
|
||||
// i0 is an *offset* for the 'current' index.
|
||||
// i1 is for the 'next' index, wrapping back to 0.
|
||||
let i1 = (i0 + 1) % count;
|
||||
vec![
|
||||
// Mind winding order!
|
||||
r1.start + i1, r2.start + i0, r1.start + i0,
|
||||
r2.start + i1, r2.start + i0, r1.start + i1,
|
||||
]
|
||||
}).flatten().collect()
|
||||
(0..count)
|
||||
.map(|i0| {
|
||||
// i0 is an *offset* for the 'current' index.
|
||||
// i1 is for the 'next' index, wrapping back to 0.
|
||||
let i1 = (i0 + 1) % count;
|
||||
vec![
|
||||
// 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 parallel_zigzag_mesh(verts: Vec<Vertex>, main: Range<usize>, parent: Range<usize>) -> Mesh {
|
||||
@ -85,8 +94,10 @@ pub fn parallel_zigzag_mesh(verts: Vec<Vertex>, main: Range<usize>, parent: Rang
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parallel_zigzag2<T,U>(main: T, parent: U) -> Vec<usize>
|
||||
where T: IntoIterator<Item=usize>, U: IntoIterator<Item=usize>
|
||||
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();
|
||||
@ -95,16 +106,18 @@ where T: IntoIterator<Item=usize>, U: IntoIterator<Item=usize>
|
||||
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()
|
||||
(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 {
|
||||
@ -118,17 +131,22 @@ pub fn centroid(verts: &Vec<Vertex>) -> Vertex {
|
||||
}
|
||||
|
||||
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()
|
||||
(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()
|
||||
(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