diff --git a/README.md b/README.md index 17f27da..fd332d6 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,7 @@ - Grep for all TODOs in code, really. - Look at everything in README.md in automata_scratch. - Implement some of the tougher examples from the above too, e.g. the - triple nested spiral -- Lots of Rust-kosher refactoring (once I understand Rust better) + triple nested spiral. See `examples.py`. - Actual Rust-style docs! ## If I'm bored: diff --git a/src/examples.rs b/src/examples.rs index 6d05829..121df45 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -12,33 +12,21 @@ fn curve_horn_start() -> RuleStep { std::f32::consts::PI).to_homogeneous(); RuleStep { geom: OpenMesh { - verts: vec![], - faces: vec![ - Tag::Exit(1, 0), Tag::Exit(1, 2), Tag::Exit(0, 1), - Tag::Exit(1, 2), Tag::Exit(0, 3), Tag::Exit(0, 1), - Tag::Exit(0, 0), Tag::Exit(0, 2), Tag::Exit(1, 1), - Tag::Exit(0, 2), Tag::Exit(1, 3), Tag::Exit(1, 1), - Tag::Exit(0, 3), Tag::Exit(1, 2), Tag::Exit(0, 2), - Tag::Exit(1, 2), Tag::Exit(1, 3), Tag::Exit(0, 2), - Tag::Exit(1, 0), Tag::Exit(0, 1), Tag::Exit(0, 0), - Tag::Exit(1, 1), Tag::Exit(1, 0), Tag::Exit(0, 0), - // The above is connecting group 0 to group 1, - // straight across + with diagonal - but with group 1 - // being flipped 180, so we remap vertices (0,1,2,3) - // to (1,0,3,2) and then flip winding order. + verts: vec![ + vertex(-0.5, -0.5, 0.0), + vertex(-0.5, 0.5, 0.0), + vertex( 0.5, 0.5, 0.0), + vertex( 0.5, -0.5, 0.0), ], - exit_groups: vec![4, 4], + faces: vec![], }, final_geom: prim::empty_mesh(), children: vec![ - (Rule::Recurse(curve_horn_thing_rule), id), // exit group 0 - (Rule::Recurse(curve_horn_thing_rule), flip180), // exit group 1 + (Rule::Recurse(curve_horn_thing_rule), id), + (Rule::Recurse(curve_horn_thing_rule), flip180), ], } - // TODO: The starting vertices above are duplicated because I - // don't have any way for an exit vertex to stand in for multiple - // child vertices that happen to share the same location. I don't - // yet know a good way around this, so I am duplicating vertices. + // TODO: Fix the consequences of the 180 flip } fn curve_horn_thing_rule() -> RuleStep { @@ -51,49 +39,45 @@ fn curve_horn_thing_rule() -> RuleStep { let verts = vec![ vertex(-0.5, -0.5, 0.0), - vertex(0.5, -0.5, 0.0), - vertex(-0.5, 0.5, 0.0), - vertex(0.5, 0.5, 0.0), + vertex(-0.5, 0.5, 0.0), + vertex( 0.5, 0.5, 0.0), + vertex( 0.5, -0.5, 0.0), ]; - let final_verts: Vec = verts.iter().map(|v| m * v).collect(); + let next_verts: Vec = verts.iter().map(|v| m * v).collect(); let geom = OpenMesh { - verts: verts, + verts: next_verts.clone(), faces: vec![ // The below is just connecting two groups of 4 vertices - // each, straight across and then to the next. Note that - // since 'verts' doesn't go in a circle, it will look a - // little strange. - Tag::Body(1), Tag::Exit(0, 3), Tag::Exit(0, 1), - Tag::Body(1), Tag::Body(3), Tag::Exit(0, 3), - Tag::Exit(0, 0), Tag::Body(2), Tag::Body(0), - Tag::Exit(0, 0), Tag::Exit(0, 2), Tag::Body(2), - Tag::Body(2), Tag::Exit(0, 3), Tag::Body(3), - Tag::Body(2), Tag::Exit(0, 2), Tag::Exit(0, 3), - Tag::Body(0), Tag::Body(1), Tag::Exit(0, 1), - Tag::Body(0), Tag::Exit(0, 1), Tag::Exit(0, 0), + // each, straight across and then to the next. + Tag::Body(1), Tag::Parent(0), Tag::Body(0), + Tag::Parent(1), Tag::Parent(0), Tag::Body(1), + Tag::Body(2), Tag::Parent(1), Tag::Body(1), + Tag::Parent(2), Tag::Parent(1), Tag::Body(2), + Tag::Body(3), Tag::Parent(2), Tag::Body(2), + Tag::Parent(3), Tag::Parent(2), Tag::Body(3), + Tag::Body(0), Tag::Parent(3), Tag::Body(3), + Tag::Parent(0), Tag::Parent(3), Tag::Body(0), // TODO: I should really generate these, not hard-code them. ], - exit_groups: vec![4], }; // TODO: This could be made slightly nicer by taking it to a peak // instead of just flattening it in XY, but this is a pretty minor // change. let final_geom = OpenMesh { - verts: final_verts, + verts: next_verts, faces: vec![ Tag::Body(0), Tag::Body(1), Tag::Body(3), Tag::Body(0), Tag::Body(3), Tag::Body(2), ], - exit_groups: vec![], }; RuleStep{ geom: geom, final_geom: final_geom, children: vec![ - (Rule::Recurse(curve_horn_thing_rule), m), // exit group 0 + (Rule::Recurse(curve_horn_thing_rule), m), ], } } @@ -127,11 +111,69 @@ fn cube_thing_rule() -> RuleStep { RuleStep { geom: mesh, - final_geom: prim::empty_mesh(), // no exit groups + final_geom: prim::empty_mesh(), children: turns.iter().map(gen_rulestep).collect(), } } +/* +// Conversion from Python & automata_scratch +fn ram_horn_start() -> RuleStep { + let id = nalgebra::geometry::Transform3::identity().to_homogeneous(); + let flip180 = nalgebra::geometry::Rotation3::from_axis_angle( + &nalgebra::Vector3::y_axis(), + std::f32::consts::PI).to_homogeneous(); + RuleStep { + geom: OpenMesh { + // 'Bottom' vertices: + verts: vec![ + vertex(-0.5, -0.5, -0.5), + vertex(-0.5, 0.5, -0.5), + vertex( 0.5, 0.5, -0.5), + vertex( 0.5, -0.5, -0.5), + ], + faces: vec![ + // bottom face: + Tag::Body(0), Tag::Body(1), Tag::Body(2), + Tag::Body(0), Tag::Body(2), Tag::Body(3), + // two faces straddling edge from vertex 0: + Tag::Body(0), Tag::Exit(0, 0), Tag::Exit(0, 1), + Tag::Body(0), Tag::Exit(0, 3), Tag::Exit(0, 0), + // two faces straddling edge from vertex 1: + Tag::Body(1), Tag::Exit(1, 0), Tag::Exit(1, 1), + Tag::Body(1), Tag::Exit(1, 3), Tag::Exit(1, 0), + // two faces straddling edge from vertex 2: + Tag::Body(2), Tag::Exit(2, 0), Tag::Exit(2, 1), + Tag::Body(2), Tag::Exit(2, 3), Tag::Exit(2, 0), + // two faces straddling edge from vertex 3: + Tag::Body(3), Tag::Exit(3, 0), Tag::Exit(3, 1), + Tag::Body(3), Tag::Exit(3, 3), Tag::Exit(3, 0), + // four faces from edge (0,1), (1,2), (2,3), (3,0): + Tag::Body(0), Tag::Exit(0, 1)/*=Tag::Exit(1, 3)*/, Tag::Body(1), + Tag::Body(1), Tag::Exit(1, 1)/*=Tag::Exit(2, 3)*/, Tag::Body(2), + Tag::Body(2), Tag::Exit(2, 1)/*=Tag::Exit(3, 3)*/, Tag::Body(3), + Tag::Body(3), Tag::Exit(3, 1)/*=Tag::Exit(0, 3)*/, Tag::Body(0), + ], + exit_groups: vec![4, 4, 4, 4], + }, + final_geom: prim::empty_mesh(), + children: vec![ + (Rule::Recurse(ram_horn), id), // exit group 0 + (Rule::Recurse(ram_horn), id), // exit group 1 + (Rule::Recurse(ram_horn), id), // exit group 2 + (Rule::Recurse(ram_horn), id), // exit group 3 + ], + } + // TODO: How do I handle *duplicated* exit vertices? In this + // instance, multiple children connect to some of them - e.g. all + // Tag::Exit(n,2) are together, and Tag::Exit(n,1) is the same as + // Tag::Exit((n+1)%4, 3). +} + +fn ram_horn() -> RuleStep { +} +*/ + pub fn main() { let run_test = |r: Rule, iters, name| { @@ -144,6 +186,6 @@ pub fn main() { }; run_test(Rule::Recurse(cube_thing_rule), 3, "cube_thing"); - run_test(Rule::Recurse(curve_horn_thing_rule), 100, "curve_horn_thing"); + //run_test(Rule::Recurse(curve_horn_thing_rule), 100, "curve_horn_thing"); run_test(Rule::Recurse(curve_horn_start), 100, "curve_horn2"); } diff --git a/src/openmesh.rs b/src/openmesh.rs index 925f63c..fafd8ca 100644 --- a/src/openmesh.rs +++ b/src/openmesh.rs @@ -16,7 +16,7 @@ pub fn vertex(x: f32, y: f32, z: f32) -> Vertex { #[derive(Clone, Debug)] pub enum Tag { Body(usize), - Exit(usize, usize), // (group, vertex) + Parent(usize), } #[derive(Clone, Debug)] @@ -26,7 +26,6 @@ pub struct OpenMesh { // Triangles, taken as every 3 values, treated each as indices // into 'verts': pub faces: Vec, - pub exit_groups: Vec, } impl OpenMesh { @@ -37,7 +36,6 @@ impl OpenMesh { // TODO: Is the above faster if I pack vectors into a // bigger matrix, and transform that? faces: self.faces.clone(), // TODO: Use Rc? - exit_groups: self.exit_groups.clone(), } } @@ -59,7 +57,7 @@ impl OpenMesh { let get_vert = |j| { match self.faces[j] { Tag::Body(n) => self.verts[n].xyz(), - Tag::Exit(_, _) => panic!("Cannot write_stl() if mesh has exit groups!"), + Tag::Parent(_) => panic!("Cannot write_stl() if mesh has parent references!"), } }; // TODO: Handle this behavior @@ -92,49 +90,31 @@ impl OpenMesh { let mut verts: Vec = self.verts.clone(); let mut faces = self.faces.clone(); - let mut exit_groups: Vec = vec![]; - - let mut body_offset = self.verts.len(); - let mut exit_offset = 0; - let mut offsets: Vec = vec![0; others.len()]; - for (i,other) in others.iter().enumerate() { + for other in others { - // Append body vertices & exit vertices directly: - verts.append(&mut other.verts.clone()); + // body_offset corresponds to the position in 'verts' at + // which we're appending everything in 'other.verts' - + // thus, the offset we shift all indices in 'others' by. + let body_offset = verts.len(); - // Append faces, shifting each kind by respective offset: + // Copy all vertices from 'other': + verts.append(&mut other.verts.clone()); + + // Append its faces: faces.extend(other.faces.iter().map(|t| { match t { + // Apply aforementioned shift to its body vertices: Tag::Body(n) => Tag::Body(n + body_offset), - Tag::Exit(g, n) => Tag::Exit(g + exit_groups.len(), n + exit_offset), + // Since 'self' vertices are in the same order, + // parent vertex references retain same index: + Tag::Parent(n) => Tag::Body(*n), } })); - if i < self.exit_groups.len() { - exit_offset += self.exit_groups[i]; - } - exit_groups.append(&mut other.exit_groups.clone()); - - offsets[i] = body_offset; - // Increase offsets by the number of elements we appended: - body_offset += other.verts.len(); - } - - // All of the Exit face indices from 'self' need to be - // modified to refer to Body vertices of something in - // 'others': - for i in 0..faces.len() { - match faces[i] { - Tag::Exit(g, n) => { - faces[i] = Tag::Body(n + offsets[g]); - }, - _ => { }, - }; } OpenMesh { verts: verts, faces: faces, - exit_groups: exit_groups, } } } diff --git a/src/prim.rs b/src/prim.rs index 1f2915c..ceb0d55 100644 --- a/src/prim.rs +++ b/src/prim.rs @@ -6,7 +6,6 @@ pub fn empty_mesh() -> OpenMesh { OpenMesh { verts: vec![], faces: vec![], - exit_groups: vec![], } } @@ -36,6 +35,5 @@ pub fn cube() -> OpenMesh { Tag::Body(0), Tag::Body(1), Tag::Body(5), Tag::Body(0), Tag::Body(5), Tag::Body(4), ], - exit_groups: vec![], }.transform(geometry::Translation3::new(-0.5, -0.5, -0.5).to_homogeneous()) } diff --git a/src/rule.rs b/src/rule.rs index 986d2e7..7d2aec8 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -40,8 +40,6 @@ impl Rule { pub fn to_mesh(&self, iters_left: u32) -> (OpenMesh, u32) { - - let mut nodes: u32 = 1; if iters_left <= 0 {