diff --git a/README.md b/README.md index 9fef1ca..45b3c62 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,8 @@ ## Highest priority: -- 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.) - Look at performance. @@ -26,17 +24,6 @@ ## Important but less critical: -- Elegance & succinctness: - - Clean up `ramhorn_branch` because it's ugly. - - What patterns can I factor out? I do some things regularly, like: - the clockwise boundaries, the zigzag connections. - - Declarative macro to shorten this `Tag::Parent`, `Tag::Body` - nonsense - and perhaps force to groups of 3? Does this have any - value, though, over just making helper functions like `p(...)` and - `b(...)`? - - I'm near certain a declarative macros can simplify some bigger - things like my patterns with closures (e.g. the Y combinator like - 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). Note that @@ -54,7 +41,6 @@ ## If I'm bored: -- Fix links in tri_mesh docs that use relative paths & do a PR? - Look in https://www.nalgebra.org/quick_reference/# for "pour obtain". Can I fix this somehow? Looks like a French-ism that made its way in. @@ -70,26 +56,8 @@ ## Research Areas -- When I have an iterated transform, that is basically transforming by - M, MM=M^2, MMM=M^3, ..., and it seems to me that I should be able to - compute its eigendecomposition and use this to compute fractional - powers of the matrix. Couldn't I then determine the continuous - function I'm approximating by taking the `d/di (M^i)V` - i.e. the - partial derivative of the result of transforming a vector `V` with - `M^i`? (See also: - https://en.wikipedia.org/wiki/Eigendecomposition_of_a_matrix#Functional_calculus - and my 2020-04-20 paper notes. My 2020-04-24 org notes have some - 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 & 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 - did it differently in this code, but it became much easier - - particularly, more "inner" transformations are much easier to write - because all that matters is that they work properly in the - coordinate space they inherit. - 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. diff --git a/src/examples.rs b/src/examples.rs index 8090c7f..f2071c9 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -49,7 +49,7 @@ pub fn cube_thing() -> Rule<()> { } */ -pub fn barbs() -> Rule<()> { +pub fn barbs(random: bool) -> Rule<()> { let (b0, bn); let base_verts: Vec = vec_indexed![ @@ -60,9 +60,24 @@ pub fn barbs() -> Rule<()> { @bn, ]; - let barb_incr = id().translate(0.0, 0.0, 0.5). - rotate(&Vector3::y_axis(), -0.2). - scale(0.8); + let barb_incr = |random| { + if random { + let t = rand::thread_rng().gen_range(0.45, 0.55); + let s = rand::thread_rng().gen_range(0.7, 0.9); + let ry = rand::thread_rng().gen_range(-0.3, -0.1); + let rx = rand::thread_rng().gen_range(-0.04, 0.04); + let rz = rand::thread_rng().gen_range(-0.04, 0.04); + id().translate(0.0, 0.0, t). + rotate(&Vector3::y_axis(), ry). + rotate(&Vector3::x_axis(), rx). + rotate(&Vector3::z_axis(), rz). + scale(s) + } else { + id().translate(0.0, 0.0, 0.5). + rotate(&Vector3::y_axis(), -0.2). + scale(0.8) + } + }; let barb = rule_fn!(() => |self_, base_verts| { let mut next_verts = base_verts; @@ -74,10 +89,12 @@ pub fn barbs() -> Rule<()> { faces: vec![ 0, 2, 1, 0, 3, 2 ], }; + let b = barb_incr(random); + RuleEval { - geom: Rc::new(geom.transform(&barb_incr)), + geom: Rc::new(geom.transform(&b)), final_geom: Rc::new(final_geom), // no transform needed (no vertices) - children: vec![ child_iter!(self_, barb_incr, b0..bn) ], + children: vec![ child_iter!(self_, b, b0..bn) ], } }); @@ -86,10 +103,23 @@ pub fn barbs() -> Rule<()> { rotate(&Vector3::y_axis(), -FRAC_PI_2). translate(0.5, 0.0, 0.5) }; - 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 main_incr = |random| { + if random { + let t = rand::thread_rng().gen_range(0.75, 1.25); + let s = rand::thread_rng().gen_range(0.85, 1.10); + let rz = rand::thread_rng().gen_range(0.05, 0.25); + let rx = rand::thread_rng().gen_range(0.08, 0.12); + id().translate(0.0, 0.0, 1.0). + rotate(&Vector3::z_axis(), rz). + rotate(&Vector3::x_axis(), rx). + scale(s) + } else { + id().translate(0.0, 0.0, 1.0). + rotate(&Vector3::z_axis(), 0.15). + rotate(&Vector3::x_axis(), 0.1). + scale(0.95) + } + }; let main = rule_fn!(() => |self_, base_verts| { let mut next_verts = base_verts; @@ -107,7 +137,7 @@ pub fn barbs() -> Rule<()> { geom: Rc::new(geom), final_geom: Rc::new(final_geom), children: vec![ - child_iter!(self_, main_incr, b0..bn), + child_iter!(self_, main_incr(random), 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), diff --git a/src/lib.rs b/src/lib.rs index 5830c6a..ace188b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,8 +75,10 @@ mod tests { */ #[test] - fn barbs() { run_test(examples::barbs(), 80, "barbs", false); } + fn barbs() { run_test(examples::barbs(false), 80, "barbs", false); } + #[test] + fn barbs_random() { run_test(examples::barbs(true), 80, "barbs_random", false); } /* #[test] fn twist() {