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:
|
## Highest priority:
|
||||||
|
|
||||||
- Make a series of guidelines for *exactly* how to order
|
- Continue to refine the 'barbs' example, which broke some new ground.
|
||||||
transformations so that I'm actually constructing things to be
|
- Implement the continuous parametric transformations from 2020-05-07
|
||||||
correct instead of just throwing shit at the wall.
|
in my notes. This will require some new abstractions.
|
||||||
See my "Composing Transformations" link in log.org.
|
|
||||||
- Adaptive subdivision - which means having to generalize past some
|
|
||||||
`arg_vals` stuff.
|
|
||||||
- Try some non-deterministic examples.
|
- Try some non-deterministic examples.
|
||||||
- Get identical or near-identical meshes to `ramhorn_branch` from
|
- Get identical or near-identical meshes to `ramhorn_branch` from
|
||||||
Python. (Should just be a matter of tweaking parameters.)
|
Python. (Should just be a matter of tweaking parameters.)
|
||||||
@ -42,7 +39,9 @@
|
|||||||
method for recursive calls).
|
method for recursive calls).
|
||||||
- Docs on modules
|
- Docs on modules
|
||||||
- Compute global scale factor, and perhaps pass it to a rule (to
|
- 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
|
- swept-isocontour stuff from
|
||||||
`/mnt/dev/graphics_misc/isosurfaces_2018_2019/spiral*.py`. This
|
`/mnt/dev/graphics_misc/isosurfaces_2018_2019/spiral*.py`. This
|
||||||
will probably require that I figure out parametric curves
|
will probably require that I figure out parametric curves
|
||||||
@ -83,7 +82,7 @@
|
|||||||
things too - this relates to dynamical systems and eigenvalues.)
|
things too - this relates to dynamical systems and eigenvalues.)
|
||||||
Later note: I have a feeling I was dead wrong about a bunch of this.
|
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
|
- My old Python version composed rules in the opposite order and I
|
||||||
think this made things more complicated. I didn't realize that 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
|
- Generalizing to space curves moves this away from the "discrete
|
||||||
automata" roots, but it still ends up needing the machinery I made
|
automata" roots, but it still ends up needing the machinery I made
|
||||||
for discrete automata.
|
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;
|
||||||
use crate::util::VecExt;
|
use crate::util::VecExt;
|
||||||
use crate::mesh::{Mesh, MeshFunc, VertexUnion};
|
use crate::mesh::{Mesh, MeshFunc, VertexUnion, vert_args};
|
||||||
use crate::xform::{Transform, Vertex, vertex, Mat4};
|
use crate::xform::{Transform, Vertex, vertex, Mat4, id};
|
||||||
use crate::rule::{Rule, RuleFn, RuleEval, Child};
|
use crate::rule::{Rule, RuleFn, RuleEval, Child};
|
||||||
use crate::prim;
|
use crate::prim;
|
||||||
|
|
||||||
@ -58,66 +58,49 @@ pub fn barbs() -> Rule<()> {
|
|||||||
VertexUnion::Vertex(vertex( 0.5, -0.5, 0.0)),
|
VertexUnion::Vertex(vertex( 0.5, -0.5, 0.0)),
|
||||||
@bn,
|
@bn,
|
||||||
];
|
];
|
||||||
let n = base_verts.len();
|
|
||||||
|
|
||||||
let barb_incr: Transform = Transform::new().
|
let barb_incr = id().translate(0.0, 0.0, 0.5).
|
||||||
translate(0.0, 0.0, 0.5).
|
|
||||||
rotate(&Vector3::y_axis(), -0.2).
|
rotate(&Vector3::y_axis(), -0.2).
|
||||||
scale(0.8);
|
scale(0.8);
|
||||||
|
|
||||||
let b = base_verts.clone();
|
let b = base_verts.clone();
|
||||||
let barb = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
|
let barb = rule_fn!((), self_ => {
|
||||||
let mut next_verts = b.clone();
|
let mut next_verts = b.clone();
|
||||||
let (a0, a1) = next_verts.append_indexed(
|
let (a0, a1) = next_verts.append_indexed(vert_args(0..4));
|
||||||
&mut (0..4).map(|i| VertexUnion::Arg(i)).collect()
|
|
||||||
);
|
|
||||||
|
|
||||||
let geom = util::parallel_zigzag(next_verts.clone(), b0..bn, a0..a1);
|
let geom = util::parallel_zigzag(next_verts.clone(), b0..bn, a0..a1);
|
||||||
let final_geom = MeshFunc {
|
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 ],
|
faces: vec![ 0, 2, 1, 0, 3, 2 ],
|
||||||
};
|
};
|
||||||
|
|
||||||
RuleEval {
|
RuleEval {
|
||||||
geom: Rc::new(geom.transform(&barb_incr)),
|
geom: Rc::new(geom.transform(&barb_incr)),
|
||||||
final_geom: Rc::new(final_geom), // no transform needed (no vertices)
|
final_geom: Rc::new(final_geom), // no transform needed (no vertices)
|
||||||
children: vec![
|
children: vec![ child_iter!(self_, barb_incr, b0..bn) ],
|
||||||
Child {
|
|
||||||
rule: self_.clone(),
|
|
||||||
xf: barb_incr,
|
|
||||||
arg_vals: (0..n).collect(),
|
|
||||||
}
|
}
|
||||||
]
|
});
|
||||||
}
|
|
||||||
};
|
|
||||||
let barb_ = Rc::new(barb);
|
|
||||||
|
|
||||||
let main_barb_trans = |i| {
|
let main_barb_xf = |i| {
|
||||||
Transform::new().
|
id().rotate(&Vector3::z_axis(), -std::f32::consts::FRAC_PI_2 * (i as f32)).
|
||||||
rotate(&Vector3::z_axis(), -std::f32::consts::FRAC_PI_2 * (i as f32)).
|
|
||||||
rotate(&Vector3::y_axis(), -std::f32::consts::FRAC_PI_2).
|
rotate(&Vector3::y_axis(), -std::f32::consts::FRAC_PI_2).
|
||||||
translate(0.5, 0.0, 0.5)
|
translate(0.5, 0.0, 0.5)
|
||||||
};
|
};
|
||||||
|
let main_incr = id().translate(0.0, 0.0, 1.0).
|
||||||
let main_incr: Transform = Transform::new().
|
|
||||||
translate(0.0, 0.0, 1.0).
|
|
||||||
rotate(&Vector3::z_axis(), 0.15).
|
rotate(&Vector3::z_axis(), 0.15).
|
||||||
rotate(&Vector3::x_axis(), 0.1).
|
rotate(&Vector3::x_axis(), 0.1).
|
||||||
scale(0.95);
|
scale(0.95);
|
||||||
|
|
||||||
let b = base_verts.clone();
|
let b = base_verts.clone();
|
||||||
let main = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
|
let main = rule_fn!((), self_ => {
|
||||||
let mut next_verts = b.clone();
|
let mut next_verts = b.clone();
|
||||||
let (a0, a1) = next_verts.append_indexed(
|
let (a0, a1) = next_verts.append_indexed(vert_args(0..4));
|
||||||
&mut (0..4).map(|i| VertexUnion::Arg(i)).collect()
|
|
||||||
);
|
|
||||||
|
|
||||||
// This contributes no faces of its own - just vertices.
|
// This contributes no faces of its own - just vertices.
|
||||||
let geom = MeshFunc {
|
let geom = MeshFunc { verts: next_verts.clone(), faces: vec![] };
|
||||||
verts: next_verts.clone(),
|
// (unless recursion ends here, of course)
|
||||||
faces: vec![],
|
|
||||||
};
|
|
||||||
let final_geom = MeshFunc {
|
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 ],
|
faces: vec![ 0, 2, 1, 0, 3, 2 ],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -125,59 +108,30 @@ pub fn barbs() -> Rule<()> {
|
|||||||
geom: Rc::new(geom),
|
geom: Rc::new(geom),
|
||||||
final_geom: Rc::new(final_geom),
|
final_geom: Rc::new(final_geom),
|
||||||
children: vec![
|
children: vec![
|
||||||
Child {
|
child_iter!(self_, main_incr, b0..bn),
|
||||||
rule: self_.clone(),
|
child!(rule!(barb, ()), main_barb_xf(0), b0 + 0, b0 + 1, a0 + 1, a0 + 0),
|
||||||
xf: main_incr,
|
child!(rule!(barb, ()), main_barb_xf(1), b0 + 1, b0 + 2, a0 + 2, a0 + 1),
|
||||||
arg_vals: (0..n).collect(),
|
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),
|
||||||
Child {
|
// TODO: Factor out repetition?
|
||||||
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
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
let main_ = Rc::new(main);
|
let base = rule_fn!((), _s => {
|
||||||
let base = move |self_: Rc<Rule<()>>| -> RuleEval<()> {
|
|
||||||
RuleEval {
|
RuleEval {
|
||||||
geom: Rc::new(MeshFunc {
|
geom: Rc::new(MeshFunc {
|
||||||
verts: base_verts.clone(),
|
verts: base_verts.clone(),
|
||||||
faces: vec![
|
faces: vec![ b0, b0 + 1, b0 + 2, b0, b0 + 2, b0 + 3 ],
|
||||||
b0, b0 + 1, b0 + 2,
|
|
||||||
b0, b0 + 2, b0 + 3,
|
|
||||||
],
|
|
||||||
}),
|
}),
|
||||||
// TODO: This might be buggy and leave some vertices lying around
|
// TODO: This might be buggy and leave some vertices lying around
|
||||||
final_geom: Rc::new(prim::empty_meshfunc()),
|
final_geom: Rc::new(prim::empty_meshfunc()),
|
||||||
children: vec![
|
children: vec![ child_iter!(rule!(main, ()), id(), b0..bn) ],
|
||||||
Child {
|
|
||||||
rule: Rc::new(Rule { eval: main_.clone(), ctxt: () }),
|
|
||||||
xf: Transform::new(),
|
|
||||||
arg_vals: (0..n).collect(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
Rule { eval: Rc::new(base), ctxt: () }
|
//rule!(Rc::new(base), ())
|
||||||
|
Rule { eval: base, ctxt: () }
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
pub mod mesh;
|
pub mod mesh;
|
||||||
|
#[macro_use]
|
||||||
pub mod rule;
|
pub mod rule;
|
||||||
pub mod prim;
|
pub mod prim;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|||||||
@ -82,6 +82,10 @@ pub enum VertexUnion {
|
|||||||
Arg(usize),
|
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
|
/// A face-vertex mesh whose vertices can either be concrete values
|
||||||
/// (as in `Mesh`) or aliases (indices to other vertices of some
|
/// (as in `Mesh`) or aliases (indices to other vertices of some
|
||||||
/// hypothetical mesh). This can be turned to `mesh` only if those
|
/// 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>,
|
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> {
|
impl<S> Rule<S> {
|
||||||
|
|
||||||
/// Convert this `Rule` to mesh data, recursively (depth first).
|
/// Convert this `Rule` to mesh data, recursively (depth first).
|
||||||
|
|||||||
@ -24,15 +24,15 @@ macro_rules! vec_indexed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait VecExt<T> {
|
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> {
|
impl<T> VecExt<T> for Vec<T> {
|
||||||
// Like `append`, but returning `(a, b)` which give the range of
|
// Like `append`, but returning `(a, b)` which give the range of
|
||||||
// elements just inserted.
|
// 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();
|
let a = self.len();
|
||||||
self.append(other);
|
self.append(&mut other);
|
||||||
let b = self.len();
|
let b = self.len();
|
||||||
(a, b)
|
(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 {
|
impl<'a> Mul for &'a Transform {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user