Made a (half-broken and ugly) twisty torus
This commit is contained in:
parent
537dcd2f44
commit
e0baea62cc
33
README.md
33
README.md
@ -2,16 +2,31 @@
|
|||||||
|
|
||||||
## Highest priority:
|
## Highest priority:
|
||||||
|
|
||||||
- Clean up `ramhorn_branch` because it's fugly.
|
- Adaptive subdivision - which means having to generalize past some
|
||||||
|
`vmap` stuff.
|
||||||
|
- Try some non-deterministic examples
|
||||||
|
- Get identical or near-identical meshes to `ramhorn_branch` from
|
||||||
|
Python. (Should just be a matter of tweaking parameters.)
|
||||||
- See `automata_scratch/examples.py` and implement some of the tougher
|
- See `automata_scratch/examples.py` and implement some of the tougher
|
||||||
examples.
|
examples.
|
||||||
- `spiral_nested_2` & `spiral_nested_3` (how to compose
|
- `twisty_torus`, `spiral_nested_2`, & `spiral_nested_3` are all
|
||||||
efficiently?)
|
that remain. To do them, I need to compose transformations (not
|
||||||
- `twisty_torus`
|
in the matrix sense), but I also probably need to produce
|
||||||
|
RuleEvals which always have `xf` of identity transformation since
|
||||||
|
the Python code does not 'inherit' transforms unless I tell it to.
|
||||||
|
|
||||||
## Important but less critical:
|
## Important but less critical:
|
||||||
|
|
||||||
- Elegance & succinctness (my recent closure work may help with this):
|
- Look at performance.
|
||||||
|
- Start at `to_mesh_iter()`. The cost of small appends/connects
|
||||||
|
seems to be killing performance.
|
||||||
|
- `connect()` is a big performance hot-spot: 85% of total time in
|
||||||
|
one test, around 51% in `extend()`, 33% in `clone()`. It seems
|
||||||
|
like I should be able to share geometry with the `Rc` (like noted
|
||||||
|
above), defer copying until actually needed, and pre-allocate the
|
||||||
|
vector to its size (which should be easy to compute).
|
||||||
|
- Elegance & succinctness:
|
||||||
|
- Clean up `ramhorn_branch` because it's ugly.
|
||||||
- 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 clockwise boundaries, the zigzag connections.
|
||||||
- Declarative macro to shorten this `Tag::Parent`, `Tag::Body`
|
- Declarative macro to shorten this `Tag::Parent`, `Tag::Body`
|
||||||
@ -22,14 +37,6 @@
|
|||||||
things like my patterns with closures (e.g. the Y combinator like
|
things like my patterns with closures (e.g. the Y combinator like
|
||||||
method for recursive calls).
|
method for recursive calls).
|
||||||
- Docs on modules
|
- Docs on modules
|
||||||
- Look at performance.
|
|
||||||
- Start at `to_mesh_iter()`. The cost of small appends/connects
|
|
||||||
seems to be killing performance.
|
|
||||||
- `connect()` is a big performance hot-spot: 85% of total time in
|
|
||||||
one test, around 51% in `extend()`, 33% in `clone()`. It seems
|
|
||||||
like I should be able to share geometry with the `Rc` (like noted
|
|
||||||
above), defer copying until actually needed, and pre-allocate the
|
|
||||||
vector to its size (which should be easy to compute).
|
|
||||||
- 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)
|
||||||
- swept-isocontour stuff from
|
- swept-isocontour stuff from
|
||||||
|
|||||||
@ -44,7 +44,8 @@ pub fn cube_thing() -> Rule<()> {
|
|||||||
Rule { eval: Rc::new(rec), ctxt: () }
|
Rule { eval: Rc::new(rec), ctxt: () }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Meant to be a copy of twist_from_gen from Python & automata_scratch
|
// Meant to be a copy of twist_from_gen from Python &
|
||||||
|
// automata_scratch, but has since acquired a sort of life of its own
|
||||||
pub fn twist(f: f32, subdiv: usize) -> Rule<()> {
|
pub 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.
|
||||||
@ -71,6 +72,9 @@ pub fn twist(f: f32, subdiv: usize) -> Rule<()> {
|
|||||||
|
|
||||||
let seed2 = seed.clone();
|
let seed2 = seed.clone();
|
||||||
// TODO: Why do I need the above?
|
// TODO: Why do I need the above?
|
||||||
|
// TODO: Could a macro get rid of some of this or would it just be
|
||||||
|
// equally cumbersome because I'd have to sort of pass 'seed'
|
||||||
|
// explicitly?
|
||||||
let recur = move |incr: Transform| -> RuleFn<()> {
|
let recur = move |incr: Transform| -> RuleFn<()> {
|
||||||
|
|
||||||
let seed_next = incr.transform(&seed2);
|
let seed_next = incr.transform(&seed2);
|
||||||
@ -133,6 +137,96 @@ pub fn twist(f: f32, subdiv: usize) -> Rule<()> {
|
|||||||
Rule { eval: Rc::new(start), ctxt: () }
|
Rule { eval: Rc::new(start), ctxt: () }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct TorusCtxt {
|
||||||
|
xform1: Transform,
|
||||||
|
xform2: Transform,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn twisty_torus() -> Rule<TorusCtxt> {
|
||||||
|
let subdiv = 8;
|
||||||
|
let seed = vec![
|
||||||
|
vertex(-0.5, -0.5, 1.0),
|
||||||
|
vertex(-0.5, 0.5, 1.0),
|
||||||
|
vertex( 0.5, 0.5, 1.0),
|
||||||
|
vertex( 0.5, -0.5, 1.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 = 4.0;
|
||||||
|
let dx0 = 2.0;
|
||||||
|
let ang = 0.1;
|
||||||
|
|
||||||
|
let recur = move |self_: Rc<Rule<TorusCtxt>>| -> RuleEval<TorusCtxt> {
|
||||||
|
let y = &Vector3::y_axis();
|
||||||
|
let z = &Vector3::z_axis();
|
||||||
|
let xf1 = self_.ctxt.xform1;
|
||||||
|
let xf2 = self_.ctxt.xform2;
|
||||||
|
let next_rule = Rule {
|
||||||
|
eval: self_.eval.clone(),
|
||||||
|
ctxt: TorusCtxt {
|
||||||
|
xform1: xf1.rotate(y, 0.1),
|
||||||
|
xform2: xf2.rotate(z, ang),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let xf = xf1 * xf2;
|
||||||
|
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(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let start = move |self_: Rc<Rule<TorusCtxt>>| -> RuleEval<TorusCtxt> {
|
||||||
|
let xf1 = self_.ctxt.xform1;
|
||||||
|
let xf2 = self_.ctxt.xform2;
|
||||||
|
let xf = xf1 * xf2;
|
||||||
|
|
||||||
|
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 };
|
||||||
|
let fg = prim::empty_mesh();
|
||||||
|
RuleEval {
|
||||||
|
geom: Rc::new(g.transform(&xf)),
|
||||||
|
final_geom: Rc::new(fg),
|
||||||
|
children: vec![
|
||||||
|
Child {
|
||||||
|
rule: Rc::new(Rule {
|
||||||
|
eval: Rc::new(recur.clone()),
|
||||||
|
ctxt: self_.ctxt,
|
||||||
|
}),
|
||||||
|
xf: Transform::new(),
|
||||||
|
vmap: (0..n2).collect(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Rule {
|
||||||
|
eval: Rc::new(start),
|
||||||
|
ctxt: TorusCtxt {
|
||||||
|
xform1: Transform::new().translate(rad, 0.0, 0.0),
|
||||||
|
xform2: Transform::new().translate(dx0, 0.0, 0.0),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ramhorn() -> Rule<()> {
|
pub fn ramhorn() -> Rule<()> {
|
||||||
|
|
||||||
let v = Unit::new_normalize(Vector3::new(-1.0, 0.0, 1.0));
|
let v = Unit::new_normalize(Vector3::new(-1.0, 0.0, 1.0));
|
||||||
|
|||||||
@ -50,6 +50,11 @@ mod tests {
|
|||||||
run_test(examples::twist(1.0, 2), 200, "screw", false);
|
run_test(examples::twist(1.0, 2), 200, "screw", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn twisty_torus() {
|
||||||
|
run_test(examples::twisty_torus(), 50, "twisty_torus", false);
|
||||||
|
}
|
||||||
|
|
||||||
// This one is very time-consuming to run:
|
// This one is very time-consuming to run:
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user