My ramhorn_branch example finally works. It's just ugly.

Also, might be generating non-manifold geometry in certain cases.
This commit is contained in:
Chris Hodapp 2020-04-05 22:30:06 -04:00
parent 5f27239525
commit aba2e24e26
2 changed files with 117 additions and 136 deletions

View File

@ -2,13 +2,13 @@
## Highest priority:
- Clean up `ramhorn_branch` because it's fugly. Also, fix
non-manifold stuff at higher recursions.
- See `automata_scratch/examples.py` and implement some of the tougher
examples.
- `spiral_nested_2` & `spiral_nested_3` (how to compose
efficiently?)
- `twisty_torus`
- `ram_horn_branch` - Can I pass depth via a closure? Do I need
mutual recursion for this?
## Important but less critical:
@ -38,6 +38,10 @@
- the closure can move them
- Use an actual logging framework.
- Migrate tests to... well... actual tests.
- I am starting to see a pattern emerge in how I have to modularize
things around closures. What can a macro do for me here?
- swept-isocontour stuff from
`/mnt/dev/graphics_misc/isosurfaces_2018_2019/spiral*.py`
## If I'm bored:

View File

@ -278,11 +278,11 @@ struct RamHornCtxt {
depth: usize,
}
fn ramhorn_twist(depth: usize) -> Rule<RamHornCtxt> {
fn ramhorn_branch(depth: usize) -> Rule<RamHornCtxt> {
// Quarter-turn in radians:
let qtr = std::f32::consts::FRAC_PI_2;
let z = Vector3::z_axis();
//let qtr = std::f32::consts::FRAC_PI_2;
//let z = Vector3::z_axis();
let v = Unit::new_normalize(Vector3::new(-1.0, 0.0, 1.0));
let incr: Transform = Transform::new().
@ -318,56 +318,6 @@ fn ramhorn_twist(depth: usize) -> Rule<RamHornCtxt> {
],
});
let recur = move |self_: Rc<Rule<RamHornCtxt>>| -> RuleEval<RamHornCtxt> {
let children = if self_.ctxt.depth <= 0 {
let next_rule = Rc::new(Rule {
eval: self_.eval.clone(),
ctxt: RamHornCtxt { depth },
});
vec![
Child {
rule: next_rule.clone(),
xf: incr.scale(0.5).translate(1.0, 1.0, 2.0).rotate(&z, qtr*0.0),
vmap: vec![0,1,2,3],
},
Child {
rule: next_rule.clone(),
xf: incr.scale(0.5).translate(-1.0, 1.0, 2.0).rotate(&z, qtr*1.0),
vmap: vec![0,1,2,3],
},
Child {
rule: next_rule.clone(),
xf: incr.scale(0.5).translate(-1.0, -1.0, 2.0).rotate(&z, qtr*2.0),
vmap: vec![0,1,2,3],
},
Child {
rule: next_rule.clone(),
xf: incr.scale(0.5).translate(1.0, -1.0, 2.0).rotate(&z, qtr*3.0),
vmap: vec![0,1,2,3],
},
// TODO: Factor out repetition
// TODO: Produce midpoint/centroid vertices like 'start' does below
]
} else {
let next_rule = Rule {
eval: self_.eval.clone(),
ctxt: RamHornCtxt { depth: self_.ctxt.depth - 1 },
};
vec![
Child {
rule: Rc::new(next_rule),
xf: incr,
vmap: vec![0,1,2,3],
},
]
};
RuleEval {
geom: geom.clone(),
final_geom: final_geom.clone(),
children: children,
}
};
let opening_xform = |i| {
let r = std::f32::consts::FRAC_PI_2 * i;
Transform::new().
@ -377,11 +327,7 @@ fn ramhorn_twist(depth: usize) -> Rule<RamHornCtxt> {
translate(0.0, 0.0, -1.0)
};
let trans = move |self_: Rc<Rule<RamHornCtxt>>| -> RuleEval<RamHornCtxt> {
RuleEval {
geom: Rc::new(OpenMesh {
verts: vec![
let trans_verts = vec![
// 'Top' vertices:
vertex(-0.5, -0.5, 1.0), // 0 (above 9)
vertex(-0.5, 0.5, 1.0), // 1 (above 10)
@ -394,8 +340,8 @@ fn ramhorn_twist(depth: usize) -> Rule<RamHornCtxt> {
vertex( 0.0, -0.5, 1.0), // 7 (connects 3-0)
// Top middle:
vertex( 0.0, 0.0, 1.0), // 8
],
faces: vec![
];
let trans_faces = vec![
// two faces straddling edge from vertex 0:
Tag::Parent(0), Tag::Body(0), Tag::Body(4),
Tag::Parent(0), Tag::Body(7), Tag::Body(0),
@ -413,35 +359,72 @@ fn ramhorn_twist(depth: usize) -> Rule<RamHornCtxt> {
Tag::Parent(1), Tag::Body(5), Tag::Parent(2),
Tag::Parent(2), Tag::Body(6), Tag::Parent(3),
Tag::Parent(3), Tag::Body(7), Tag::Parent(0),
],
}),
final_geom: Rc::new(prim::empty_mesh()),
children: vec![
];
let trans_geom = Rc::new(OpenMesh {
verts: trans_verts.clone(),
faces: trans_faces.clone(),
});
let trans_children = move |recur: RuleFn<RamHornCtxt>, ctxt: RamHornCtxt| {
vec![
Child {
rule: Rc::new(Rule { eval: Rc::new(recur.clone()), ctxt: self_.ctxt }),
rule: Rc::new(Rule { eval: recur.clone(), ctxt }),
xf: opening_xform(0.0),
vmap: vec![5,2,6,8],
},
Child {
rule: Rc::new(Rule { eval: Rc::new(recur.clone()), ctxt: self_.ctxt }),
rule: Rc::new(Rule { eval: recur.clone(), ctxt }),
xf: opening_xform(1.0),
vmap: vec![4,1,5,8],
},
Child {
rule: Rc::new(Rule { eval: Rc::new(recur.clone()), ctxt: self_.ctxt }),
rule: Rc::new(Rule { eval: recur.clone(), ctxt }),
xf: opening_xform(2.0),
vmap: vec![7,0,4,8],
},
Child {
rule: Rc::new(Rule { eval: Rc::new(recur.clone()), ctxt: self_.ctxt }),
rule: Rc::new(Rule { eval: recur.clone(), ctxt }),
xf: opening_xform(3.0),
vmap: vec![6,3,7,8],
},
// TODO: These vertex mappings appear to be right.
// Explain *why* they are right.
// TODO: Factor out the repetition here.
]
};
let tg = trans_geom.clone();
let recur = move |self_: Rc<Rule<RamHornCtxt>>| -> RuleEval<RamHornCtxt> {
if self_.ctxt.depth <= 0 {
RuleEval {
geom: tg.clone(),
final_geom: Rc::new(prim::empty_mesh()),
children: trans_children(self_.eval.clone(), RamHornCtxt { depth }),
}
} else {
let next_rule = Rule {
eval: self_.eval.clone(),
ctxt: RamHornCtxt { depth: self_.ctxt.depth - 1 },
};
RuleEval {
geom: geom.clone(),
final_geom: final_geom.clone(),
children: vec![
Child {
rule: Rc::new(next_rule),
xf: incr,
vmap: vec![0,1,2,3],
},
],
}
}
};
let trans = move |self_: Rc<Rule<RamHornCtxt>>| -> RuleEval<RamHornCtxt> {
RuleEval {
geom: trans_geom.clone(),
final_geom: Rc::new(prim::empty_mesh()),
children: trans_children(Rc::new(recur.clone()), self_.ctxt),
}
};
let start = move |self_: Rc<Rule<RamHornCtxt>>| -> RuleEval<RamHornCtxt> {
@ -594,28 +577,22 @@ impl CurveHorn {
pub fn main() {
fn run_test<S>(r: &Rc<Rule<S>>, iters: usize, name: &str) {
println!("Running {}...", name);
let (mesh, nodes) = Rule::to_mesh(r.clone(), iters);
println!("Evaluated {} rules", nodes);
let fname = format!("{}.stl", name);
println!("Writing {}...", fname);
mesh.write_stl_file(&fname).unwrap();
}
fn run_test_iter<S>(r: &Rc<Rule<S>>, iters: usize, name: &str) {
println!("Running {}...", name);
fn run_test<S>(r: &Rc<Rule<S>>, iters: usize, name: &str, use_old: bool) {
println!("---------------------------------------------------");
println!("Running {} with {}...",
name, if use_old { "to_mesh" } else { "to_mesh_iter" });
if false {
let start = Instant::now();
let n = 5;
for i in 0..n {
for _ in 0..n {
Rule::to_mesh_iter(r.clone(), iters);
}
let elapsed = start.elapsed();
println!("DEBUG: {} ms per run", elapsed.as_millis() / n);
}
let (mesh, nodes) = Rule::to_mesh_iter(r.clone(), iters);
println!("Evaluated {} rules", nodes);
let mesh_fn = if use_old { Rule::to_mesh } else { Rule::to_mesh_iter };
let (mesh, nodes) = mesh_fn(r.clone(), iters);
println!("Evaluated {} rules to {} verts", nodes, mesh.verts.len());
let fname = format!("{}.stl", name);
println!("Writing {}...", fname);
mesh.write_stl_file(&fname).unwrap();
@ -643,8 +620,8 @@ pub fn main() {
// let f = 20;
// run_test_iter(Twist::init(f as f32, 32), 100*f, "twist2");
run_test_iter(&Rc::new(cube_thing()), 3, "cube_thing3");
run_test_iter(&Rc::new(twist(1.0, 2)), 200, "twist");
run_test_iter(&Rc::new(ramhorn()), 100, "ram_horn3");
run_test_iter(&Rc::new(ramhorn_twist(5)), 30, "ram_horn3b_bug");
run_test(&Rc::new(cube_thing()), 3, "cube_thing3", false);
run_test(&Rc::new(twist(1.0, 2)), 200, "twist", false);
run_test(&Rc::new(ramhorn()), 100, "ram_horn3", false);
run_test(&Rc::new(ramhorn_branch(4)), 22, "ram_horn_branch", false);
}