From 8146d4fea86653f79933caf329137892ef43aeb3 Mon Sep 17 00:00:00 2001 From: Chris Hodapp Date: Fri, 2 Oct 2020 11:38:53 -0400 Subject: [PATCH] Sierpinski ish thing working --- README.md | 7 ++ src/examples.rs | 193 +++++++++++++++++++++++++++++++++++++++++------- src/lib.rs | 2 +- src/rule.rs | 2 +- 4 files changed, 174 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 098e79b..b0db568 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,13 @@ from a 'parent' rule, besides being able to connect to its vertices - and sometimes the "refining" part of things required this in order to work right. +I've also disliked how much my model felt like it tied me +down to the "triangle mesh" representation. I haven't +found a good way to build up higher-level representations +to modularise and compose - but haven't given up yet on +this. In some sense it is a conflict of goals because +the aim was correct-by-construction triangle meshes. + Also, I did this in order to learn the Rust language, and I repeatedly kept bumping into the conclusion that Rust was just not the right language for this. I was in need of things diff --git a/src/examples.rs b/src/examples.rs index dcb35d7..bbd9e5c 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -166,36 +166,52 @@ pub fn barbs(random: bool) -> Rule<()> { pub fn pyramid() -> Rule<()> { - // base_verts are for a triangle in the XY plane, centered at - // (0,0,0), with unit sidelength: - let (b0, bn); let rt3 = (3.0).sqrt(); let rt6 = (6.0).sqrt(); - let base_verts: Vec = vec_indexed![ - @b0 VertexUnion::Vertex(vertex( rt3/3.0, 0.0, 0.0)), - VertexUnion::Vertex(vertex( -rt3/6.0, -1.0/2.0, 0.0)), - VertexUnion::Vertex(vertex( -rt3/6.0, 1.0/2.0, 0.0)), - VertexUnion::Vertex(vertex( 0.0, 0.0, rt6/3.0)), - @bn, - ]; + + // base_verts are for a unit-sidelength tetrahedron and its midpoints. + // Its *base* sits in the XY plane, centered at (0,0,0). + // Indices: + // b0,b1,b2 = base vertices; t = 'top' vertex. + // m01, m12, m20 = midpoints of (b0,b1), (b1,b2), (b2,b0). + // bm0, bm1, bm2 = midpoints of (b0,t), (b1,t), (b2,t). + let (b0, b1, b2, t, m01, m12, m20, bm0, bm1, bm2); + let base_verts: Vec = { + let v0 = vertex(rt3/3.0, 0.0, 0.0); + let v1 = vertex(-rt3/6.0, -1.0/2.0, 0.0); + let v2 = vertex(-rt3/6.0, 1.0/2.0, 0.0); + let vt = vertex(0.0, 0.0, rt6/3.0); + vec_indexed![ + @b0 VertexUnion::Vertex(v0), + @b1 VertexUnion::Vertex(v1), + @b2 VertexUnion::Vertex(v2), + @t VertexUnion::Vertex(vt), + @m01 VertexUnion::Vertex((v0+v1)/2.0), + @m12 VertexUnion::Vertex((v1+v2)/2.0), + @m20 VertexUnion::Vertex((v2+v0)/2.0), + @bm0 VertexUnion::Vertex((v0+vt)/2.0), + @bm1 VertexUnion::Vertex((v1+vt)/2.0), + @bm2 VertexUnion::Vertex((v2+vt)/2.0), + ] + }; let test = rule_fn!(() => |_s, base_verts| { - let rt3 = (3.0).sqrt(); - let (a0, a1, a2); - let next_verts: Vec = vec_indexed![ - VertexUnion::Vertex(vertex( rt3/12.0, -1.0/4.0, 0.0)), - VertexUnion::Vertex(vertex( rt3/12.0, 1.0/4.0, 0.0)), - VertexUnion::Vertex(vertex(-rt3/6.0, 0.0, 0.0)), - @a0 VertexUnion::Arg(0), - @a1 VertexUnion::Arg(1), - @a2 VertexUnion::Arg(2), - // TODO: Why do I have index-out-of-range crashes if I move - // the ::Vertex(...) to the end? - ]; + // Mnemonics for args: + let b0 = 0; // Base + let b1 = 1; // Adjacent base + let t = 2; // 'Top' + let m01 = 3; // Midpoint between b0 & b1 + let bm0 = 4; // Midpoint between b0 & t + let bm1 = 5; // Midpoint between b1 & t RuleEval { geom: Rc::new(MeshFunc { - verts: next_verts, - faces: vec![ a0, 0, 2, a1, 1, 0, a2, 2, 1, 0, 1, 2 ], + verts: vert_args(0..6), + faces: vec![ + b0, m01, bm0, + b1, bm1, m01, + t, bm0, bm1, + m01, bm1, bm0, // middle + ], }), final_geom: Rc::new(MeshFunc { verts: vec![], @@ -224,16 +240,137 @@ pub fn pyramid() -> Rule<()> { RuleEval { geom: Rc::new(MeshFunc { verts: base_verts, - faces: vec![ 0, 1, 2 ], + faces: vec![ + b0, m01, m20, + b1, m12, m01, + b2, m20, m12, + m12, m20, m01, + ], }), final_geom: Rc::new(MeshFunc { verts: vec![], faces: vec![], }), children: vec![ - child!(rule!(test, ()), base_to_side(0), 1, 0, 3), - child!(rule!(test, ()), base_to_side(1), 0, 2, 3), - child!(rule!(test, ()), base_to_side(2), 2, 1, 3), + child!(rule!(test, ()), base_to_side(0), b1, b0, t, m01, bm1, bm0), + child!(rule!(test, ()), base_to_side(1), b0, b2, t, m20, bm0, bm2), + child!(rule!(test, ()), base_to_side(2), b2, b1, t, m12, bm2, bm1), + ], + } + }); + + Rule { eval: base, ctxt: () } +} + +pub fn pyramid2() -> Rule<()> { + + let rt3 = (3.0).sqrt(); + + let dz = 0.05; + + // Indices: + // b+0,b+1,b+2 = base vertices + // t+0,t+1,t+2 = 'top' vertices above base + // bm01, bm12, bm20 = midpoints of (b0,b1), (b1,b2), (b2,b0). + // tm01, tm12, tm20 = midpoints of (t0,t1), (t1,t2), (t2,t0). + let (b, t, tm01, tm12, tm20); + let base_verts: Vec = { + let v0 = vertex(rt3/3.0, 0.0, 0.0); + let v1 = vertex(-rt3/6.0, 1.0/2.0, 0.0); + let v2 = vertex(-rt3/6.0, -1.0/2.0, 0.0); + let v0b = v0 + vertex(0.0, 0.0, dz); + let v1b = v1 + vertex(0.0, 0.0, dz); + let v2b = v2 + vertex(0.0, 0.0, dz); + vec_indexed![ + @b VertexUnion::Vertex(v0), + VertexUnion::Vertex(v1), + VertexUnion::Vertex(v2), + @t VertexUnion::Vertex(v0b), + VertexUnion::Vertex(v1b), + VertexUnion::Vertex(v2b), + @tm01 VertexUnion::Vertex((v0b+v1b)/2.0), + @tm12 VertexUnion::Vertex((v1b+v2b)/2.0), + @tm20 VertexUnion::Vertex((v2b+v0b)/2.0), + ] + }; + + let tri_split = move |i| { + let rt3 = (3.0).sqrt(); + let angle = 2.0 * FRAC_PI_3 * (i as f32); + id(). + rotate(&Vector3::z_axis(), angle). + translate(rt3/12.0, 0.0, 0.0). + scale(0.5). + translate(0.0, 0.0, dz) + }; + + let test = rule_fn!(() => |_s, base_verts| { + + let mut next_verts = base_verts; + let (a0, a1) = next_verts.append_indexed(vert_args(0..3)); + + RuleEval { + geom: Rc::new(MeshFunc { + verts: next_verts, + faces: vec![ + //a0, a0+1, a0+2, + // Outer: + tm01, a0+1, t+1, + tm01, t+0, a0+0, + tm01, a0+0, a0+1, + tm12, a0+2, t+2, + tm12, t+1, a0+1, + tm12, a0+1, a0+2, + tm20, a0+0, t+0, + tm20, t+2, a0+2, + tm20, a0+2, a0+0, + // Inner: + tm01, tm12, tm20, + // Bottom: + //b+2, b+1, b+0, + ], + }), + final_geom: Rc::new(MeshFunc { + verts: vec![], + faces: vec![], + }), + children: vec![ + child!(_s, tri_split(0), t+0, tm01, tm20), + child!(_s, tri_split(1), t+1, tm12, tm01), + child!(_s, tri_split(2), t+2, tm20, tm12), + ], + } + }); + + let base = rule_fn!(() => |_s, base_verts| { + RuleEval { + geom: Rc::new(MeshFunc { + verts: base_verts, + faces: vec![ + // Outer: + tm01, b+1, t+1, + tm01, t+0, b+0, + tm01, b+0, b+1, + tm12, b+2, t+2, + tm12, t+1, b+1, + tm12, b+1, b+2, + tm20, b+0, t+0, + tm20, t+2, b+2, + tm20, b+2, b+0, + // Inner: + tm01, tm12, tm20, + // Bottom: + b+2, b+1, b+0, + ], + }), + final_geom: Rc::new(MeshFunc { + verts: vec![], + faces: vec![], + }), + children: vec![ + child!(rule!(test, ()), tri_split(0), t+0, tm01, tm20), + child!(rule!(test, ()), tri_split(1), t+1, tm12, tm01), + child!(rule!(test, ()), tri_split(2), t+2, tm20, tm12), ], } }); diff --git a/src/lib.rs b/src/lib.rs index 87fc8f9..75defb2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,7 +80,7 @@ mod tests { fn barbs_random() { run_test(examples::barbs(true), 80, "barbs_random", false); } #[test] - fn pyramid() { run_test(examples::pyramid(), 3, "pyramid", false); } + fn pyramid() { run_test(examples::pyramid2(), 3, "pyramid2", false); } /* #[test] fn twist() { diff --git a/src/rule.rs b/src/rule.rs index dc89498..7c91da0 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -85,7 +85,7 @@ pub struct Child { macro_rules! child { ( $Rule:expr, $Xform:expr, $( $Arg:expr ),* ) => { Child { - rule: /*std::rc::Rc::new*/($Rule), + rule: /*std::rc::Rc::new*/($Rule).clone(), xf: $Xform, arg_vals: vec![$($Arg,)*], }