Add some macros to make things less verbose
This commit is contained in:
parent
b7da8bea41
commit
7b04b91746
18
README.md
18
README.md
@ -2,12 +2,9 @@
|
||||
|
||||
## Highest priority:
|
||||
|
||||
- Make a series of guidelines for *exactly* how to order
|
||||
transformations so that I'm actually constructing things to be
|
||||
correct instead of just throwing shit at the wall.
|
||||
See my "Composing Transformations" link in log.org.
|
||||
- Adaptive subdivision - which means having to generalize past some
|
||||
`arg_vals` stuff.
|
||||
- Continue to refine the 'barbs' example, which broke some new ground.
|
||||
- Implement the continuous parametric transformations from 2020-05-07
|
||||
in my notes. This will require some new abstractions.
|
||||
- Try some non-deterministic examples.
|
||||
- Get identical or near-identical meshes to `ramhorn_branch` from
|
||||
Python. (Should just be a matter of tweaking parameters.)
|
||||
@ -42,7 +39,9 @@
|
||||
method for recursive calls).
|
||||
- Docs on modules
|
||||
- Compute global scale factor, and perhaps pass it to a rule (to
|
||||
eventually be used for, perhaps, adaptive subdivision)
|
||||
eventually be used for, perhaps, adaptive subdivision). Note that
|
||||
one can find the scale factors by taking the length of the first 3
|
||||
columns of the transform matrix (supposedly).
|
||||
- swept-isocontour stuff from
|
||||
`/mnt/dev/graphics_misc/isosurfaces_2018_2019/spiral*.py`. This
|
||||
will probably require that I figure out parametric curves
|
||||
@ -83,7 +82,7 @@
|
||||
things too - this relates to dynamical systems and eigenvalues.)
|
||||
Later note: I have a feeling I was dead wrong about a bunch of this.
|
||||
|
||||
## Reflections
|
||||
## Reflections & Quick Notes
|
||||
|
||||
- My old Python version composed rules in the opposite order and I
|
||||
think this made things more complicated. I didn't realize that I
|
||||
@ -94,3 +93,6 @@
|
||||
- Generalizing to space curves moves this away from the "discrete
|
||||
automata" roots, but it still ends up needing the machinery I made
|
||||
for discrete automata.
|
||||
- If you *pre* multiply a transformation: you are transforming the
|
||||
entire global space. If you *post* multiply: you are transforming
|
||||
the current local space.
|
||||
106
src/examples.rs
106
src/examples.rs
@ -5,8 +5,8 @@ use rand::Rng;
|
||||
|
||||
use crate::util;
|
||||
use crate::util::VecExt;
|
||||
use crate::mesh::{Mesh, MeshFunc, VertexUnion};
|
||||
use crate::xform::{Transform, Vertex, vertex, Mat4};
|
||||
use crate::mesh::{Mesh, MeshFunc, VertexUnion, vert_args};
|
||||
use crate::xform::{Transform, Vertex, vertex, Mat4, id};
|
||||
use crate::rule::{Rule, RuleFn, RuleEval, Child};
|
||||
use crate::prim;
|
||||
|
||||
@ -58,66 +58,49 @@ pub fn barbs() -> Rule<()> {
|
||||
VertexUnion::Vertex(vertex( 0.5, -0.5, 0.0)),
|
||||
@bn,
|
||||
];
|
||||
let n = base_verts.len();
|
||||
|
||||
let barb_incr: Transform = Transform::new().
|
||||
translate(0.0, 0.0, 0.5).
|
||||
let barb_incr = id().translate(0.0, 0.0, 0.5).
|
||||
rotate(&Vector3::y_axis(), -0.2).
|
||||
scale(0.8);
|
||||
|
||||
let b = base_verts.clone();
|
||||
let barb = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
|
||||
let barb = rule_fn!((), self_ => {
|
||||
let mut next_verts = b.clone();
|
||||
let (a0, a1) = next_verts.append_indexed(
|
||||
&mut (0..4).map(|i| VertexUnion::Arg(i)).collect()
|
||||
);
|
||||
let (a0, a1) = next_verts.append_indexed(vert_args(0..4));
|
||||
|
||||
let geom = util::parallel_zigzag(next_verts.clone(), b0..bn, a0..a1);
|
||||
let final_geom = MeshFunc {
|
||||
verts: (0..4).map(|i| VertexUnion::Arg(i)).collect(),
|
||||
verts: vert_args(0..4),
|
||||
faces: vec![ 0, 2, 1, 0, 3, 2 ],
|
||||
};
|
||||
|
||||
RuleEval {
|
||||
geom: Rc::new(geom.transform(&barb_incr)),
|
||||
final_geom: Rc::new(final_geom), // no transform needed (no vertices)
|
||||
children: vec![
|
||||
Child {
|
||||
rule: self_.clone(),
|
||||
xf: barb_incr,
|
||||
arg_vals: (0..n).collect(),
|
||||
children: vec![ child_iter!(self_, barb_incr, b0..bn) ],
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
let barb_ = Rc::new(barb);
|
||||
});
|
||||
|
||||
let main_barb_trans = |i| {
|
||||
Transform::new().
|
||||
rotate(&Vector3::z_axis(), -std::f32::consts::FRAC_PI_2 * (i as f32)).
|
||||
let main_barb_xf = |i| {
|
||||
id().rotate(&Vector3::z_axis(), -std::f32::consts::FRAC_PI_2 * (i as f32)).
|
||||
rotate(&Vector3::y_axis(), -std::f32::consts::FRAC_PI_2).
|
||||
translate(0.5, 0.0, 0.5)
|
||||
};
|
||||
|
||||
let main_incr: Transform = Transform::new().
|
||||
translate(0.0, 0.0, 1.0).
|
||||
let main_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 b = base_verts.clone();
|
||||
let main = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
|
||||
let main = rule_fn!((), self_ => {
|
||||
let mut next_verts = b.clone();
|
||||
let (a0, a1) = next_verts.append_indexed(
|
||||
&mut (0..4).map(|i| VertexUnion::Arg(i)).collect()
|
||||
);
|
||||
let (a0, a1) = next_verts.append_indexed(vert_args(0..4));
|
||||
|
||||
// This contributes no faces of its own - just vertices.
|
||||
let geom = MeshFunc {
|
||||
verts: next_verts.clone(),
|
||||
faces: vec![],
|
||||
};
|
||||
let geom = MeshFunc { verts: next_verts.clone(), faces: vec![] };
|
||||
// (unless recursion ends here, of course)
|
||||
let final_geom = MeshFunc {
|
||||
verts: (0..4).map(|i| VertexUnion::Arg(i)).collect(),
|
||||
verts: vert_args(0..4),
|
||||
faces: vec![ 0, 2, 1, 0, 3, 2 ],
|
||||
};
|
||||
|
||||
@ -125,59 +108,30 @@ pub fn barbs() -> Rule<()> {
|
||||
geom: Rc::new(geom),
|
||||
final_geom: Rc::new(final_geom),
|
||||
children: vec![
|
||||
Child {
|
||||
rule: self_.clone(),
|
||||
xf: main_incr,
|
||||
arg_vals: (0..n).collect(),
|
||||
},
|
||||
Child {
|
||||
rule: Rc::new(Rule { eval: barb_.clone(), ctxt: () }),
|
||||
xf: main_barb_trans(0),
|
||||
arg_vals: vec![b0 + 0, b0 + 1, a0 + 1, a0 + 0],
|
||||
},
|
||||
Child {
|
||||
rule: Rc::new(Rule { eval: barb_.clone(), ctxt: () }),
|
||||
xf: main_barb_trans(1),
|
||||
arg_vals: vec![b0 + 1, b0 + 2, a0 + 2, a0 + 1],
|
||||
},
|
||||
Child {
|
||||
rule: Rc::new(Rule { eval: barb_.clone(), ctxt: () }),
|
||||
xf: main_barb_trans(2),
|
||||
arg_vals: vec![b0 + 2, b0 + 3, a0 + 3, a0 + 2],
|
||||
},
|
||||
Child {
|
||||
rule: Rc::new(Rule { eval: barb_.clone(), ctxt: () }),
|
||||
xf: main_barb_trans(3),
|
||||
arg_vals: vec![b0 + 3, b0 + 0, a0 + 0, a0 + 3],
|
||||
},
|
||||
// TODO: Factor out repetition
|
||||
child_iter!(self_, main_incr, b0..bn),
|
||||
child!(rule!(barb, ()), main_barb_xf(0), b0 + 0, b0 + 1, a0 + 1, a0 + 0),
|
||||
child!(rule!(barb, ()), main_barb_xf(1), b0 + 1, b0 + 2, a0 + 2, a0 + 1),
|
||||
child!(rule!(barb, ()), main_barb_xf(2), b0 + 2, b0 + 3, a0 + 3, a0 + 2),
|
||||
child!(rule!(barb, ()), main_barb_xf(3), b0 + 3, b0 + 0, a0 + 0, a0 + 3),
|
||||
// TODO: Factor out repetition?
|
||||
],
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
let main_ = Rc::new(main);
|
||||
let base = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
|
||||
let base = rule_fn!((), _s => {
|
||||
RuleEval {
|
||||
geom: Rc::new(MeshFunc {
|
||||
verts: base_verts.clone(),
|
||||
faces: vec![
|
||||
b0, b0 + 1, b0 + 2,
|
||||
b0, b0 + 2, b0 + 3,
|
||||
],
|
||||
faces: vec![ b0, b0 + 1, b0 + 2, b0, b0 + 2, b0 + 3 ],
|
||||
}),
|
||||
// TODO: This might be buggy and leave some vertices lying around
|
||||
final_geom: Rc::new(prim::empty_meshfunc()),
|
||||
children: vec![
|
||||
Child {
|
||||
rule: Rc::new(Rule { eval: main_.clone(), ctxt: () }),
|
||||
xf: Transform::new(),
|
||||
arg_vals: (0..n).collect(),
|
||||
},
|
||||
],
|
||||
children: vec![ child_iter!(rule!(main, ()), id(), b0..bn) ],
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Rule { eval: Rc::new(base), ctxt: () }
|
||||
//rule!(Rc::new(base), ())
|
||||
Rule { eval: base, ctxt: () }
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
pub mod mesh;
|
||||
#[macro_use]
|
||||
pub mod rule;
|
||||
pub mod prim;
|
||||
#[macro_use]
|
||||
|
||||
@ -82,6 +82,10 @@ pub enum VertexUnion {
|
||||
Arg(usize),
|
||||
}
|
||||
|
||||
pub fn vert_args<T: IntoIterator<Item = usize>>(v: T) -> Vec<VertexUnion> {
|
||||
v.into_iter().map(|i| VertexUnion::Arg(i)).collect()
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
||||
44
src/rule.rs
44
src/rule.rs
@ -80,6 +80,50 @@ pub struct Child<S> {
|
||||
pub arg_vals: Vec<usize>,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! child {
|
||||
( $Rule:expr, $Xform:expr, $( $Arg:expr ),* ) => {
|
||||
Child {
|
||||
rule: /*std::rc::Rc::new*/($Rule),
|
||||
xf: $Xform,
|
||||
arg_vals: vec![$($Arg,)*],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! child_iter {
|
||||
( $Rule:expr, $Xform:expr, $Args:expr ) => {
|
||||
Child {
|
||||
rule: /*std::rc::Rc::new*/($Rule),
|
||||
xf: $Xform,
|
||||
arg_vals: $Args.collect(), // does this even need a macro?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! rule {
|
||||
( $RuleFn:expr, $Ctxt:expr ) => {
|
||||
std::rc::Rc::new(Rule {
|
||||
eval: $RuleFn.clone(),
|
||||
ctxt: $Ctxt,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! rule_fn {
|
||||
( $Ty:ty, $Self:ident => $Body:expr ) => {
|
||||
std::rc::Rc::new(move |$Self: std::rc::Rc<Rule<$Ty>>| -> RuleEval<$Ty> {
|
||||
let $Self = $Self.clone();
|
||||
$Body
|
||||
})
|
||||
}
|
||||
}
|
||||
// TODO: Shouldn't I fully-qualify Rule & RuleEval?
|
||||
// TODO: Document all of the above macros
|
||||
|
||||
impl<S> Rule<S> {
|
||||
|
||||
/// Convert this `Rule` to mesh data, recursively (depth first).
|
||||
|
||||
@ -24,15 +24,15 @@ macro_rules! vec_indexed {
|
||||
}
|
||||
|
||||
pub trait VecExt<T> {
|
||||
fn append_indexed(&mut self, other: &mut Vec<T>) -> (usize, usize);
|
||||
fn append_indexed(&mut self, other: Vec<T>) -> (usize, usize);
|
||||
}
|
||||
|
||||
impl<T> VecExt<T> for Vec<T> {
|
||||
// Like `append`, but returning `(a, b)` which give the range of
|
||||
// elements just inserted.
|
||||
fn append_indexed(&mut self, other: &mut Vec<T>) -> (usize, usize) {
|
||||
fn append_indexed(&mut self, mut other: Vec<T>) -> (usize, usize) {
|
||||
let a = self.len();
|
||||
self.append(other);
|
||||
self.append(&mut other);
|
||||
let b = self.len();
|
||||
(a, b)
|
||||
}
|
||||
|
||||
@ -57,6 +57,11 @@ impl Mul for Transform {
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience function for identity transformation
|
||||
pub fn id() -> Transform {
|
||||
Transform::new()
|
||||
}
|
||||
|
||||
/*
|
||||
impl<'a> Mul for &'a Transform {
|
||||
type Output = Self;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user