Added a happy accident?

This commit is contained in:
Chris Hodapp 2020-04-20 18:45:21 -04:00
parent 270435c4d6
commit 5a222dcc93
3 changed files with 143 additions and 7 deletions

View File

@ -2,6 +2,9 @@
## Highest priority: ## 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
- Adaptive subdivision - which means having to generalize past some - Adaptive subdivision - which means having to generalize past some
`vmap` stuff. `vmap` stuff.
- Try some non-deterministic examples - Try some non-deterministic examples
@ -56,3 +59,6 @@
- Would being able to name a rule node (perhaps conditionally under - Would being able to name a rule node (perhaps conditionally under
some compile-time flag) help for debugging? some compile-time flag) help for debugging?
- Use an actual logging framework. - Use an actual logging framework.
- Take a square. Wrap it around to a torus. Now add a twist (about
the axis that is normal to the square). This is simple, but it looks
pretty cool.

View File

@ -140,6 +140,7 @@ pub fn twist(f: f32, subdiv: usize) -> Rule<()> {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct TorusCtxt { pub struct TorusCtxt {
init: bool, init: bool,
count: usize,
stack: [Transform; 3], stack: [Transform; 3],
} }
@ -162,22 +163,25 @@ pub fn twisty_torus() -> Rule<TorusCtxt> {
}); });
let rad = 1.0; let rad = 1.0;
let rad2 = 5.0; let rad2 = 8.0;
let dx0 = 2.0; let dx0 = 2.0;
let ang = 0.1; let ang = 0.1;
let recur = move |self_: Rc<Rule<TorusCtxt>>| -> RuleEval<TorusCtxt> { let recur = move |self_: Rc<Rule<TorusCtxt>>| -> RuleEval<TorusCtxt> {
//let y = &Vector3::y_axis(); let x = &Vector3::x_axis();
let z = &Vector3::z_axis(); let z = &Vector3::z_axis();
let stack = self_.ctxt.stack; let stack = self_.ctxt.stack;
let count = self_.ctxt.count;
let next_rule = Rule { let next_rule = Rule {
eval: self_.eval.clone(), eval: self_.eval.clone(),
ctxt: TorusCtxt { ctxt: TorusCtxt {
init: false, init: false,
count: count + 1,
stack: [ stack: [
stack[0], Transform::new().translate(0.1, 0.0, 0.0).rotate(x, 0.01) * stack[0],
Transform::new().rotate(z, 0.05) * stack[1], // stack[0], //Transform::new().rotate(z, 0.05 * (count as f32)).translate(0.0, rad2, 0.0),
Transform::new().translate(0.0, 0.0, 0.1) * stack[2], Transform::new().rotate(z, 0.30) * stack[1],
stack[2],
], ],
}, },
}; };
@ -218,6 +222,103 @@ pub fn twisty_torus() -> Rule<TorusCtxt> {
eval: Rc::new(recur), eval: Rc::new(recur),
ctxt: TorusCtxt { ctxt: TorusCtxt {
init: true, init: true,
count: 0,
stack: [
Transform::new().translate(0.0, rad2, 0.0),
Transform::new().translate(rad, 0.0, 0.0),
Transform::new(), // .translate(dx0, 0.0, 0.0),
],
},
}
}
// This was a mistake that I'd like to understand later:
#[derive(Copy, Clone)]
pub struct WindChimeCtxt {
init: bool,
count: usize,
stack: [Transform; 3],
}
pub fn wind_chime_mistake_thing() -> Rule<WindChimeCtxt> {
let subdiv = 8;
let seed = 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),
];
let seed = util::subdivide_cycle(&seed, subdiv);
let n = seed.len();
let geom = Rc::new(util::zigzag_to_parent(seed.clone(), n));
let (vc, faces) = util::connect_convex(&seed, true);
let final_geom = Rc::new(OpenMesh {
verts: vec![vc],
faces: faces,
});
let rad = 1.0;
let rad2 = 8.0;
let dx0 = 2.0;
let ang = 0.1;
let recur = move |self_: Rc<Rule<WindChimeCtxt>>| -> RuleEval<WindChimeCtxt> {
let x = &Vector3::x_axis();
let z = &Vector3::z_axis();
let stack = self_.ctxt.stack;
let count = self_.ctxt.count;
let next_rule = Rule {
eval: self_.eval.clone(),
ctxt: WindChimeCtxt {
init: false,
count: count + 1,
stack: [
Transform::new().rotate(x, 0.01) * stack[0],
// stack[0], //Transform::new().rotate(z, 0.05 * (count as f32)).translate(0.0, rad2, 0.0),
Transform::new().rotate(z, 0.30) * stack[1],
Transform::new().translate(0.1, 0.0, 0.0) * stack[2],
],
},
};
let xf = stack.iter().fold(Transform::new(), |acc,m| acc * (*m));
if self_.ctxt.init {
let mut s2 = seed.clone();
let (centroid, f) = util::connect_convex(&s2, false);
s2.push(centroid);
let n2 = s2.len();
let g = OpenMesh { verts: s2, faces: f };
RuleEval {
geom: Rc::new(g.transform(&xf)),
final_geom: Rc::new(prim::empty_mesh()),
children: vec![
Child {
rule: Rc::new(next_rule),
xf: Transform::new(),
vmap: (0..n2).collect(),
},
],
}
} else {
RuleEval {
geom: Rc::new(geom.transform(&xf)),
final_geom: Rc::new(final_geom.transform(&xf)),
children: vec![
Child {
rule: Rc::new(next_rule),
xf: Transform::new(),
vmap: (0..n).collect(),
},
],
}
}
};
Rule {
eval: Rc::new(recur),
ctxt: WindChimeCtxt {
init: true,
count: 0,
stack: [ stack: [
Transform::new().translate(0.0, rad2, 0.0), Transform::new().translate(0.0, rad2, 0.0),
Transform::new().translate(rad, 0.0, 0.0), Transform::new().translate(rad, 0.0, 0.0),

View File

@ -14,6 +14,7 @@ mod tests {
use std::rc::Rc; use std::rc::Rc;
use std::time::Instant; use std::time::Instant;
use rule::Rule; use rule::Rule;
use nalgebra::*;
fn run_test<S>(rule: Rule<S>, iters: usize, name: &str, use_old: bool) { fn run_test<S>(rule: Rule<S>, iters: usize, name: &str, use_old: bool) {
let r = Rc::new(rule); let r = Rc::new(rule);
@ -37,9 +38,33 @@ mod tests {
mesh.write_stl_file(&fname).unwrap(); mesh.write_stl_file(&fname).unwrap();
} }
#[test]
fn xform_order() {
let geom = prim::cube();
let y = &Vector3::y_axis();
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);
let xf1 = trans.rotate(y, r);
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();
// 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();
}
// TODO: These tests don't test any conditions, so this is useful // TODO: These tests don't test any conditions, so this is useful
// short-hand to run, but not very meaningful as a test. // short-hand to run, but not very meaningful as a test.
#[test] #[test]
fn cube_thing() { fn cube_thing() {
run_test(examples::cube_thing(), 3, "cube_thing3", false); run_test(examples::cube_thing(), 3, "cube_thing3", false);
@ -52,7 +77,11 @@ mod tests {
#[test] #[test]
fn twisty_torus() { fn twisty_torus() {
run_test(examples::twisty_torus(), 50, "twisty_torus", false); run_test(examples::twisty_torus(), 400, "twisty_torus", false);
}
fn wind_chime_mistake_thing() {
run_test(examples::wind_chime_mistake_thing(), 400, "wind_chime_mistake_thing", false);
} }
// This one is very time-consuming to run: // This one is very time-consuming to run: