Sierpinski ish thing working

This commit is contained in:
Chris Hodapp 2020-10-02 11:38:53 -04:00
parent 35daf01b8a
commit 8146d4fea8
4 changed files with 174 additions and 30 deletions

View File

@ -21,6 +21,13 @@ from a 'parent' rule, besides being able to connect to its
vertices - and sometimes the "refining" part of things vertices - and sometimes the "refining" part of things
required this in order to work right. 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 Also, I did this in order to learn the Rust language, and I
repeatedly kept bumping into the conclusion that Rust was repeatedly kept bumping into the conclusion that Rust was
just not the right language for this. I was in need of things just not the right language for this. I was in need of things

View File

@ -166,36 +166,52 @@ pub fn barbs(random: bool) -> Rule<()> {
pub fn pyramid() -> 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 rt3 = (3.0).sqrt();
let rt6 = (6.0).sqrt(); let rt6 = (6.0).sqrt();
let base_verts: Vec<VertexUnion> = vec_indexed![
@b0 VertexUnion::Vertex(vertex( rt3/3.0, 0.0, 0.0)), // base_verts are for a unit-sidelength tetrahedron and its midpoints.
VertexUnion::Vertex(vertex( -rt3/6.0, -1.0/2.0, 0.0)), // Its *base* sits in the XY plane, centered at (0,0,0).
VertexUnion::Vertex(vertex( -rt3/6.0, 1.0/2.0, 0.0)), // Indices:
VertexUnion::Vertex(vertex( 0.0, 0.0, rt6/3.0)), // b0,b1,b2 = base vertices; t = 'top' vertex.
@bn, // 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<VertexUnion> = {
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 test = rule_fn!(() => |_s, base_verts| {
let rt3 = (3.0).sqrt(); // Mnemonics for args:
let (a0, a1, a2); let b0 = 0; // Base
let next_verts: Vec<VertexUnion> = vec_indexed![ let b1 = 1; // Adjacent base
VertexUnion::Vertex(vertex( rt3/12.0, -1.0/4.0, 0.0)), let t = 2; // 'Top'
VertexUnion::Vertex(vertex( rt3/12.0, 1.0/4.0, 0.0)), let m01 = 3; // Midpoint between b0 & b1
VertexUnion::Vertex(vertex(-rt3/6.0, 0.0, 0.0)), let bm0 = 4; // Midpoint between b0 & t
@a0 VertexUnion::Arg(0), let bm1 = 5; // Midpoint between b1 & t
@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?
];
RuleEval { RuleEval {
geom: Rc::new(MeshFunc { geom: Rc::new(MeshFunc {
verts: next_verts, verts: vert_args(0..6),
faces: vec![ a0, 0, 2, a1, 1, 0, a2, 2, 1, 0, 1, 2 ], faces: vec![
b0, m01, bm0,
b1, bm1, m01,
t, bm0, bm1,
m01, bm1, bm0, // middle
],
}), }),
final_geom: Rc::new(MeshFunc { final_geom: Rc::new(MeshFunc {
verts: vec![], verts: vec![],
@ -224,16 +240,137 @@ pub fn pyramid() -> Rule<()> {
RuleEval { RuleEval {
geom: Rc::new(MeshFunc { geom: Rc::new(MeshFunc {
verts: base_verts, 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 { final_geom: Rc::new(MeshFunc {
verts: vec![], verts: vec![],
faces: vec![], faces: vec![],
}), }),
children: vec![ children: vec![
child!(rule!(test, ()), base_to_side(0), 1, 0, 3), child!(rule!(test, ()), base_to_side(0), b1, b0, t, m01, bm1, bm0),
child!(rule!(test, ()), base_to_side(1), 0, 2, 3), child!(rule!(test, ()), base_to_side(1), b0, b2, t, m20, bm0, bm2),
child!(rule!(test, ()), base_to_side(2), 2, 1, 3), 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<VertexUnion> = {
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),
], ],
} }
}); });

View File

@ -80,7 +80,7 @@ mod tests {
fn barbs_random() { run_test(examples::barbs(true), 80, "barbs_random", false); } fn barbs_random() { run_test(examples::barbs(true), 80, "barbs_random", false); }
#[test] #[test]
fn pyramid() { run_test(examples::pyramid(), 3, "pyramid", false); } fn pyramid() { run_test(examples::pyramid2(), 3, "pyramid2", false); }
/* /*
#[test] #[test]
fn twist() { fn twist() {

View File

@ -85,7 +85,7 @@ pub struct Child<S> {
macro_rules! child { macro_rules! child {
( $Rule:expr, $Xform:expr, $( $Arg:expr ),* ) => { ( $Rule:expr, $Xform:expr, $( $Arg:expr ),* ) => {
Child { Child {
rule: /*std::rc::Rc::new*/($Rule), rule: /*std::rc::Rc::new*/($Rule).clone(),
xf: $Xform, xf: $Xform,
arg_vals: vec![$($Arg,)*], arg_vals: vec![$($Arg,)*],
} }