Make Transform struct

This commit is contained in:
Chris Hodapp 2020-04-01 12:03:13 -04:00
parent e26b528464
commit 84711d67c0
8 changed files with 102 additions and 57 deletions

View File

@ -16,8 +16,6 @@
- Elegance & succinctness (my recent closure work may help with this): - Elegance & succinctness (my recent closure work may help with this):
- Why must I repeat myself so much in these definitions? - Why must I repeat myself so much in these definitions?
- The notation for transforms is really cumbersome. Some syntactic
sugar might go far.
- What patterns can I factor out? I do some things regularly, like: - What patterns can I factor out? I do some things regularly, like:
the clockwise boundaries, the zigzag connections, the iterating over the clockwise boundaries, the zigzag connections, the iterating over
a `Vec<Vertex>` to transform each element and make another vector. a `Vec<Vertex>` to transform each element and make another vector.

View File

@ -2,7 +2,8 @@ use std::rc::Rc;
use nalgebra::*; use nalgebra::*;
//pub mod examples; //pub mod examples;
use crate::openmesh::{OpenMesh, Mat4, vertex, transform}; use crate::openmesh::{OpenMesh};
use crate::xform::{Transform, vertex};
use crate::rule::{Rule, RuleFn, RuleEval, Child}; use crate::rule::{Rule, RuleFn, RuleEval, Child};
use crate::prim; use crate::prim;
use crate::util; use crate::util;
@ -16,19 +17,18 @@ fn cube_thing() -> Rule {
let z = &Vector3::z_axis(); let z = &Vector3::z_axis();
// Each element of this turns to a branch for the recursion: // Each element of this turns to a branch for the recursion:
let turns: Vec<Mat4> = vec![ let id = Transform::new();
geometry::Transform3::identity().to_homogeneous(), let turns: Vec<Transform> = vec![
geometry::Rotation3::from_axis_angle(y, qtr).to_homogeneous(), id.clone(),
geometry::Rotation3::from_axis_angle(y, qtr * 2.0).to_homogeneous(), id.rotate(y, qtr),
geometry::Rotation3::from_axis_angle(y, qtr * 3.0).to_homogeneous(), id.rotate(y, qtr * 2.0),
geometry::Rotation3::from_axis_angle(z, qtr).to_homogeneous(), id.rotate(y, qtr * 3.0),
geometry::Rotation3::from_axis_angle(z, -qtr).to_homogeneous(), id.rotate(z, qtr),
id.rotate(z, -qtr),
]; ];
let gen_xform = |rot: &Mat4| -> Mat4 { let gen_xform = |rot: &Transform| -> Transform {
(rot * rot.scale(0.5).translate(6.0, 0.0, 0.0)
Matrix4::new_scaling(0.5) *
geometry::Translation3::new(6.0, 0.0, 0.0).to_homogeneous())
}; };
let rec = move |self_: Rc<Rule>| -> RuleEval { let rec = move |self_: Rc<Rule>| -> RuleEval {
@ -367,13 +367,13 @@ impl RamHorn {
fn twist(f: f32, subdiv: usize) -> Rule { fn twist(f: f32, subdiv: usize) -> Rule {
// TODO: Clean this code up. It was a very naive conversion from // TODO: Clean this code up. It was a very naive conversion from
// the non-closure version. // the non-closure version.
let xf = geometry::Rotation3::from_axis_angle(&Vector3::x_axis(), -0.7).to_homogeneous(); let xf = Transform::new().rotate(&Vector3::x_axis(), -0.7);
let seed = { let seed = {
let s = vec![vertex(-0.5, 0.0, -0.5), let s = 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), vertex( 0.5, 0.0, 0.5),
vertex(-0.5, 0.0, 0.5)]; vertex(-0.5, 0.0, 0.5)];
util::subdivide_cycle(&transform(&s, &xf), subdiv) util::subdivide_cycle(&xf.transform(&s), subdiv)
}; };
let n = seed.len(); let n = seed.len();
let dx0: f32 = 1.5; let dx0: f32 = 1.5;
@ -385,19 +385,14 @@ fn twist(f: f32, subdiv: usize) -> Rule {
let qtr = std::f32::consts::FRAC_PI_2; let qtr = std::f32::consts::FRAC_PI_2;
let y = Vector3::y_axis(); let y = Vector3::y_axis();
let incr_inner = geometry::Translation3::new(-dx0, 0.0, 0.0).to_homogeneous() * let incr_inner = Transform::new().translate(-dx0, 0.0, 0.0).rotate(&y, ang).translate(dx0, dy, 0.0);
geometry::Rotation3::from_axis_angle(&y, ang).to_homogeneous() * let incr_outer = Transform::new().translate(-dx0*2.0, 0.0, 0.0).rotate(&y, ang/2.0).translate(dx0*2.0, dy, 0.0);
geometry::Translation3::new(dx0, dy, 0.0).to_homogeneous();
let incr_outer = geometry::Translation3::new(-dx0*2.0, 0.0, 0.0).to_homogeneous() *
geometry::Rotation3::from_axis_angle(&y, ang/2.0).to_homogeneous() *
geometry::Translation3::new(dx0*2.0, dy, 0.0).to_homogeneous();
// TODO: Cleanliness fix - transforms?
let seed2 = seed.clone(); let seed2 = seed.clone();
// TODO: Why do I need the above? // TODO: Why do I need the above?
let recur = move |incr: Mat4| -> RuleFn { let recur = move |incr: Transform| -> RuleFn {
let seed_next = transform(&seed2, &incr); let seed_next = incr.transform(&seed2);
// TODO: Cleanliness fix - utility function to make a zigzag mesh? // TODO: Cleanliness fix - utility function to make a zigzag mesh?
let geom = OpenMesh { let geom = OpenMesh {
@ -437,11 +432,9 @@ fn twist(f: f32, subdiv: usize) -> Rule {
let start = move |_| -> RuleEval { let start = move |_| -> RuleEval {
let xform = |dx, i, ang0, div| -> Mat4 { let xform = |dx, i, ang0, div| -> Transform {
(geometry::Rotation3::from_axis_angle(&y, ang0 + (qtr / div * (i as f32))).to_homogeneous() * Transform::new().rotate(&y, ang0 + (qtr / div * (i as f32))).translate(dx, 0.0, 0.0)
geometry::Translation3::new(dx, 0.0, 0.0).to_homogeneous())
}; };
// TODO: Cleanliness fix - transforms?
let make_child = |incr, xform| -> (OpenMesh, Child) { let make_child = |incr, xform| -> (OpenMesh, Child) {
@ -452,7 +445,7 @@ fn twist(f: f32, subdiv: usize) -> Rule {
vmap: (0..(n+1)).collect(), vmap: (0..(n+1)).collect(),
// N.B. n+1, not n. the +1 is for the centroid below. // N.B. n+1, not n. the +1 is for the centroid below.
}; };
let mut vs = transform(&seed, &xform); let mut vs = xform.transform(&seed);
// and in the process, generate faces for these seeds: // and in the process, generate faces for these seeds:
let (centroid, f) = util::connect_convex(&vs, false); let (centroid, f) = util::connect_convex(&vs, false);
vs.push(centroid); vs.push(centroid);

View File

@ -3,6 +3,7 @@ pub mod openmesh;
pub mod rule; pub mod rule;
pub mod prim; pub mod prim;
pub mod util; pub mod util;
pub mod xform;
//pub use crate::examples; //pub use crate::examples;
//pub use crate::openmesh::test_thing; //pub use crate::openmesh::test_thing;

View File

@ -1,24 +1,8 @@
//pub mod openmesh;
use nalgebra::*;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io; use std::io;
use std::borrow::Borrow; use std::borrow::Borrow;
/// A type for mesh vertices. Initialize with [vertex][self::vertex]. use crate::xform::{Vertex, Transform};
pub type Vertex = Vector4<f32>;
/// A type for homogeneous transforms
pub type Mat4 = Matrix4<f32>;
/// Initializes a vertex:
pub fn vertex(x: f32, y: f32, z: f32) -> Vertex {
Vertex::new(x, y, z, 1.0)
}
/// Transforms a vector of vertices:
pub fn transform(verts: &Vec<Vertex>, xf: &Mat4) -> Vec<Vertex> {
verts.iter().map(|v| xf * v).collect()
}
/// A type for a 'tagged' vertex index referring either to an index of /// A type for a 'tagged' vertex index referring either to an index of
/// a mesh, or of its parent. /// a mesh, or of its parent.
@ -81,9 +65,9 @@ impl OpenMesh {
} }
/// Returns a new `OpenMesh` whose vertices have been transformed. /// Returns a new `OpenMesh` whose vertices have been transformed.
pub fn transform(&self, xfm: &Mat4) -> OpenMesh { pub fn transform(&self, xfm: &Transform) -> OpenMesh {
OpenMesh { OpenMesh {
verts: self.verts.iter().map(|v| xfm * v).collect(), verts: xfm.transform(&self.verts),
// TODO: Is the above faster if I pack vectors into a // TODO: Is the above faster if I pack vectors into a
// bigger matrix, and transform that? // bigger matrix, and transform that?
faces: self.faces.clone(), // TODO: Use Rc? faces: self.faces.clone(), // TODO: Use Rc?

View File

@ -1,5 +1,5 @@
use nalgebra::*; use crate::openmesh::{OpenMesh, Tag};
use crate::openmesh::{OpenMesh, Tag, vertex}; use crate::xform::{vertex, Transform};
/// Returns an empty mesh (no vertices, no faces). /// Returns an empty mesh (no vertices, no faces).
pub fn empty_mesh() -> OpenMesh { pub fn empty_mesh() -> OpenMesh {
@ -36,5 +36,5 @@ pub fn cube() -> OpenMesh {
Tag::Body(0), Tag::Body(1), Tag::Body(5), Tag::Body(0), Tag::Body(1), Tag::Body(5),
Tag::Body(0), Tag::Body(5), Tag::Body(4), Tag::Body(0), Tag::Body(5), Tag::Body(4),
], ],
}.transform(&geometry::Translation3::new(-0.5, -0.5, -0.5).to_homogeneous()) }.transform(&Transform::new().translate(-0.5, -0.5, -0.5))
} }

View File

@ -1,4 +1,5 @@
use crate::openmesh::{OpenMesh, Tag, Mat4}; use crate::openmesh::{OpenMesh, Tag};
use crate::xform::{Transform};
//use crate::prim; //use crate::prim;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::rc::Rc; use std::rc::Rc;
@ -62,7 +63,7 @@ pub struct Child {
/// The transform to apply to all geometry produced by `rule` /// The transform to apply to all geometry produced by `rule`
/// (including its own `geom` and `final_geom` if needed, as well /// (including its own `geom` and `final_geom` if needed, as well
/// as all sub-geometry produced recursively). /// as all sub-geometry produced recursively).
pub xf: Mat4, pub xf: Transform,
/// The parent vertex mapping: a mapping to apply to turn a /// The parent vertex mapping: a mapping to apply to turn a
/// Tag::Parent vertex reference into a vertex index of the parent /// Tag::Parent vertex reference into a vertex index of the parent
@ -127,7 +128,7 @@ impl Rule {
next: usize, next: usize,
// World transform of the *parent* of 'rules', that is, // World transform of the *parent* of 'rules', that is,
// not including any transform of any element of 'rules'. // not including any transform of any element of 'rules'.
xf: Mat4, xf: Transform,
// How many levels 'deeper' can we recurse? // How many levels 'deeper' can we recurse?
depth: usize, depth: usize,
} }
@ -143,7 +144,7 @@ impl Rule {
let mut stack: Vec<State> = vec![State { let mut stack: Vec<State> = vec![State {
rules: eval.children, rules: eval.children,
next: 0, next: 0,
xf: nalgebra::geometry::Transform3::identity().to_homogeneous(), xf: Transform::new(),
depth: max_depth, depth: max_depth,
}]; }];
let mut geom = eval.geom; let mut geom = eval.geom;

View File

@ -1,4 +1,5 @@
use crate::openmesh::{Tag, Vertex}; use crate::openmesh::{Tag};
use crate::xform::{Vertex};
//use crate::rule::{Rule, Child}; //use crate::rule::{Rule, Child};
/// Linearly subdivides a list of points that are to be treated as a /// Linearly subdivides a list of points that are to be treated as a

67
src/xform.rs Normal file
View File

@ -0,0 +1,67 @@
use nalgebra::*;
use std::ops::Mul;
/// A type for mesh vertices. Initialize with [vertex][self::vertex].
pub type Vertex = Vector4<f32>;
/// A type for homogeneous transforms
pub type Mat4 = Matrix4<f32>;
#[derive(Clone, Copy)]
pub struct Transform {
pub mtx: Mat4,
}
/// Initializes a vertex:
pub fn vertex(x: f32, y: f32, z: f32) -> Vertex {
Vertex::new(x, y, z, 1.0)
}
impl Transform {
pub fn new() -> Transform {
Transform {
mtx: geometry::Transform3::identity().to_homogeneous(),
}
}
pub fn rotate(&self, axis: &Unit<Vector3<f32>>, angle: f32) -> Transform {
Transform {
mtx: self.mtx * Matrix4::from_axis_angle(axis, angle),
}
}
pub fn translate(&self, x: f32, y: f32, z: f32) -> Transform {
let xf = geometry::Translation3::new(x, y, z);
Transform {
mtx: self.mtx * xf.to_homogeneous(),
}
}
pub fn scale(&self, f: f32) -> Transform {
let xf = Matrix4::new_scaling(f);
Transform {
mtx: self.mtx * xf,
}
}
/// Transforms a vector of vertices:
pub fn transform(&self, verts: &Vec<Vertex>) -> Vec<Vertex> {
verts.iter().map(|v| self.mtx * v).collect()
}
}
impl Mul for Transform {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
Transform { mtx: self.mtx * rhs.mtx }
}
}
/*
impl<'a> Mul for &'a Transform {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
&Transform { mtx: self.mtx * rhs.mtx }
}
}
*/