From 730bf3b77b45301ae0eed7ff8871d02b55854247 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Tue, 12 Feb 2019 18:46:39 +0100 Subject: [PATCH] Create worlds consisting of two triangles --- .gitignore | 1 + dreieckeM1.txt | 3 + src/display.rs | 102 ++++-------------------- src/main.rs | 210 ++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 220 insertions(+), 96 deletions(-) create mode 100644 dreieckeM1.txt diff --git a/.gitignore b/.gitignore index 84851a4..ea61568 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target **/*.rs.bk tri*.svg +world*.svg \ No newline at end of file diff --git a/dreieckeM1.txt b/dreieckeM1.txt new file mode 100644 index 0000000..49af39d --- /dev/null +++ b/dreieckeM1.txt @@ -0,0 +1,3 @@ +2 +3 0 0 3 0 0 4 +3 0 0 3 0 0 4 \ No newline at end of file diff --git a/src/display.rs b/src/display.rs index bc11e19..6a7bb39 100644 --- a/src/display.rs +++ b/src/display.rs @@ -8,84 +8,6 @@ use std::fs; use super::*; -/* -pub(crate) fn dump_latex_code(route: &[RunState], polys: &[Polygon]) { - const SCALE: f64 = 70.0; - let mut xmax = 0.0; - let mut ymax = 0.0; - for poly in polys { - for point in poly.exterior.points_iter() { - let x = point.x() / SCALE; - let y = point.y() / SCALE; - if x > xmax { - xmax = x; - } - if y > ymax { - ymax = y; - } - } - } - if route[route.len() - 1].pos.y() / SCALE > ymax { - ymax = route[route.len() - 1].pos.y() / SCALE; - } - println!("\\begin{{tikzpicture}}"); - println!("\\tkzInit[xmax={},ymax={}]", xmax + 0.3, ymax + 0.3); - println!("\\tkzAxeXY"); - println!("\\tkzGrid"); - for (idx, poly) in polys.iter().enumerate() { - print!("\\tkzDefPoints{{"); - for (poly_idx, point) in poly.exterior.points_iter().enumerate() { - let x = point.x() / SCALE; - let y = point.y() / SCALE; - print!("{}/{}/P{}_{}", x, y, idx, poly_idx); - if poly_idx != poly.exterior.0.len() - 1 { - print!(","); - } - if x > xmax { - xmax = x; - } - if y > ymax { - ymax = y; - } - } - println!("}}"); - print!("\\tkzDrawPolygon[fill=black,line width=1pt,opacity=0.5]("); - for (poly_idx, _) in poly.exterior.points_iter().enumerate() { - print!("P{}_{}", idx, poly_idx); - if poly_idx != poly.exterior.0.len() - 1 { - print!(","); - } - } - println!(")"); - } - for (idx, s) in route.iter().enumerate() { - println!( - "\\tkzDefPoint({},{}){{R{}}}", - s.pos.x() / SCALE, - s.pos.y() / SCALE, - idx - ); - } - for idx in 1..route.len() { - println!("\\tkzDrawSegment(R{},R{})", idx - 1, idx); - } - for idx in 0..route.len() { - println!("\\tkzDrawPoint[fill=red,color=black,size=13](R{})", idx); - } - println!("\\end{{tikzpicture}}"); -} -*/ - -/* -pub(crate) fn dump_route(house: Point, polys: &[Polygon], route: &Vec) { - let (points, lines, route1, route2_start) = gen_params(house, route); - print!( - "{}", - generate_svg(&points, &lines, polys, &route1, route2_start) - ); -} -*/ - pub(crate) fn save_tri(filename: &str, tri: Triangle) { fs::write( filename, @@ -93,29 +15,39 @@ pub(crate) fn save_tri(filename: &str, tri: Triangle) { ) .unwrap(); } +pub(crate) fn save_world(filename: &str, world: &World) { + fs::write( + filename, + generate_svg(&world.tris.iter().map(|(_idx, tri)| *tri).collect::>()), + ) + .unwrap(); +} pub(crate) fn generate_svg(tris: &[Triangle]) -> String { let mut document = Document::new() // view box at (x,y), (w,h) .set( "viewBox", - (-500.0, -500.0, 1000.0, 1000.0), + (-30.0, -30.0, 60.0, 30.0), ) - .set("transform", (1.0, -1.0)) .set("xmlns:xlink", "http://www.w3.org/1999/xlink"); for tri in tris { let data = Data::new() - .move_to((tri.0.x, tri.0.y)) - .line_to((tri.1.x, tri.1.y)) - .line_to((tri.2.x, tri.2.y)) + .move_to((tri.0.x, -tri.0.y)) + .line_to((tri.1.x, -tri.1.y)) + .line_to((tri.2.x, -tri.2.y)) .close(); document.append(Path::new() .set("fill", "none") .set("stroke", "black") - .set("stroke-width", 10.0) + .set("stroke-width", 0.4) .set("d", data)); - + document.append(Circle::new() + .set("fill", "red") + .set("cx", tri.0.x) + .set("cy", -tri.0.y) + .set("r", 0.3)); } document.to_string() diff --git a/src/main.rs b/src/main.rs index c297819..ba5602a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,9 @@ -use geo::Triangle; +use geo::{Coordinate, Triangle}; use std::cmp; use std::collections::BinaryHeap; +use std::f64; +use std::f64::consts::PI; mod display; mod input; @@ -9,7 +11,7 @@ mod input; #[derive(Debug, Clone)] struct World { /// Dreiecksgrundstücke - tris: Vec>, + tris: Vec<(usize, Triangle)>, /// Gesamtabstand width: f64, } @@ -33,22 +35,208 @@ impl cmp::PartialOrd for World { fn main() { let tris = input::read_input(); let tris = transformations(&tris); - - /* + let save_prefix = "tri_"; let mut save_counter = 0; - for t in tris { - display::save_tri(&format!("{}{}.svg", save_prefix, save_counter), t); + let mut normalized_tris = Vec::with_capacity(tris.len() * 2); + let mut left_tris = Vec::with_capacity(tris.len()); + for (mut idx, t) in tris.into_iter().enumerate() { + idx /= 6; + let prev_angle = angle_of(t, t.1); + let mut added = false; + let rotated = rotate(t, 0.5*PI - prev_angle); + if rotated.1.y >= -0.001 && rotated.2.y >= -0.001 && (rotated.1.y < 0.1 || rotated.2.y < 0.1) { + normalized_tris.push((idx, rotated)); + if rotated.1.x > 0.0 && rotated.2.x > 0.0 { + left_tris.push((idx, rotated)); + } + added = true; + } + let rotated = rotate(rotated, PI); + if !added && rotated.1.y >= -0.001 && rotated.2.y >= -0.001 && (rotated.1.y < 0.1 || rotated.2.y < 0.1) { + normalized_tris.push((idx, rotated)); + if rotated.1.x > 0.0 && rotated.2.x > 0.0 { + left_tris.push((idx, rotated)); + } + added = true; + } + let rotated = rotate(t, -0.5*PI + prev_angle); + if !added && rotated.1.y >= -0.001 && rotated.2.y >= -0.001 && (rotated.1.y < 0.1 || rotated.2.y < 0.1) { + normalized_tris.push((idx, rotated)); + if rotated.1.x > 0.0 && rotated.2.x > 0.0 { + left_tris.push((idx, rotated)); + } + added = true; + } + let rotated = rotate(rotated, PI); + if !added && rotated.1.y >= -0.001 && rotated.2.y >= -0.001 && (rotated.1.y < 0.1 || rotated.2.y < 0.1) { + normalized_tris.push((idx, rotated)); + if rotated.1.x > 0.0 && rotated.2.x > 0.0 { + left_tris.push((idx, rotated)); + } + } + let prev_angle = angle_of(t, t.2); + added = false; + let rotated = rotate(t, 0.5*PI - prev_angle); + if rotated.1.y >= -0.001 && rotated.2.y >= -0.001 && (rotated.1.y < 0.1 || rotated.2.y < 0.1) { + normalized_tris.push((idx, rotated)); + if rotated.1.x > 0.0 && rotated.2.x > 0.0 { + left_tris.push((idx, rotated)); + } + added = true; + } + let rotated = rotate(rotated, PI); + if !added && rotated.1.y >= -0.001 && rotated.2.y >= -0.001 && (rotated.1.y < 0.1 || rotated.2.y < 0.1) { + normalized_tris.push((idx, rotated)); + if rotated.1.x > 0.0 && rotated.2.x > 0.0 { + left_tris.push((idx, rotated)); + } + added = true; + } + let rotated = rotate(t, -0.5*PI + prev_angle); + if !added && rotated.1.y >= -0.001 && rotated.2.y >= -0.001 && (rotated.1.y < 0.1 || rotated.2.y < 0.1) { + normalized_tris.push((idx, rotated)); + if rotated.1.x > 0.0 && rotated.2.x > 0.0 { + left_tris.push((idx, rotated)); + } + added = true; + } + let rotated = rotate(rotated, PI); + if !added && rotated.1.y >= -0.001 && rotated.2.y >= -0.001 && (rotated.1.y < 0.1 || rotated.2.y < 0.1) { + normalized_tris.push((idx, rotated)); + if rotated.1.x > 0.0 && rotated.2.x > 0.0 { + left_tris.push((idx, rotated)); + } + } + } + for (_idx, t) in &normalized_tris { + display::save_tri(&format!("{}{}.svg", save_prefix, save_counter), *t); save_counter += 1; } - */ let mut worlds = BinaryHeap::new(); - worlds.push(World { tris: vec![], width: 0.0 }); + for t in &left_tris { + let mut world = World { + tris: vec![*t], + width: 0.0 + }; + world.normalize(); + worlds.push(world); + } - let mut best_width = f64::consts::MAX; - let mut best = vec![]; + let mut best_width = f64::MAX; + //let mut best = vec![]; + let save_prefix = "world_"; + let mut save_counter = 0; + while worlds.peek().map(|x| x.width < best_width) == Some(true) { + let w = worlds.pop().unwrap(); + println!("s: {:?}", w); + let mut new = vec![]; + for (next_idx, next_tri) in left_tris.iter() + .filter(|(idx1, _tri)| w.tris.iter().all(|(idx2, _tri)| idx1 != idx2)) { + println!("trying {:?}", next_idx); + let (_, last_tri) = *w.tris.last().unwrap(); + let last_vertex = if last_tri.1.y > 0.01 && !(last_tri.2.y > 0.01 && last_tri.2.x > last_tri.1.x) { + last_tri.1 + } else { + last_tri.2 + }; + let mut free_angle = angle_of(last_tri, last_vertex); + println!("angle of {:?}: {:?}", last_vertex, free_angle); + if last_vertex.x > 0.0 { + free_angle = 0.5*PI - free_angle; + } else { + free_angle = 0.5*PI + free_angle; + } + + let next_vertex = if next_tri.1.y > 0.01 { + next_tri.1 + } else { + next_tri.2 + }; + let mut next_angle = angle_of(*next_tri, next_vertex); + if next_vertex.x > 0.0 { + next_angle = 0.5*PI - next_angle; + } else { + next_angle = 0.5*PI + next_angle; + } + if next_angle <= free_angle { + // easy: just rotate to fit and put it below the last triangle + let mut w = w.clone(); + w.tris.push((*next_idx, rotate(*next_tri, free_angle - next_angle))); + println!("new {:?} {:?} {:?}: {:?}", save_counter, free_angle, next_angle, w); + w.normalize(); + w.calc_width(); + display::save_world(&format!("{}{}.svg", save_prefix, save_counter), &w); + new.push(w); + save_counter += 1; + } else { + // "hard": move it right till it fits + println!("error: doesn't fit"); + } + } + } +} + +impl World { + fn normalize(&mut self) { + let mut maxx = 0.0; + for (_, tri) in &self.tris { + if tri.0.x > maxx { + maxx = tri.0.x; + } + if tri.1.x > maxx { + maxx = tri.1.x; + } + if tri.2.x > maxx { + maxx = tri.2.x; + } + } + if maxx != 0.0 { + self.move_left(maxx); + } + } + fn move_left(&mut self, amount: f64) { + for (_, tri) in &mut self.tris { + tri.0.x -= amount; + tri.1.x -= amount; + tri.2.x -= amount; + } + } + fn calc_width(&mut self) { + let mut x = vec![]; + for (_, tri) in &self.tris { + if tri.0.y < 0.001 && tri.0.y > -0.001 { + x.push(tri.0.x); + } + if tri.1.y < 0.001 && tri.1.y > -0.001 { + x.push(tri.1.x); + } + if tri.2.y < 0.001 && tri.2.y > -0.001 { + x.push(tri.2.x); + } + } + x.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap()); + self.width = x[x.len()-2] - x[1]; + } +} + +fn rotate(mut tri: Triangle, angle: f64) -> Triangle { + let x1 = tri.1.x; + let y1 = tri.1.y; + tri.1.x = x1*angle.cos() - y1*angle.sin(); + tri.1.y = x1*angle.sin() + y1*angle.cos(); + let x2 = tri.2.x; + let y2 = tri.2.y; + tri.2.x = x2*angle.cos() - y2*angle.sin(); + tri.2.y = x2*angle.sin() + y2*angle.cos(); + tri +} + +fn angle_of(_tri: Triangle, point: Coordinate) -> f64 { + let d = (point.x.powi(2) + point.y.powi(2)).sqrt(); + (point.y / d).acos() } fn transformations(tris: &[Triangle]) -> Vec> { @@ -58,7 +246,7 @@ fn transformations(tris: &[Triangle]) -> Vec> { new.push(n); let n = [[-n.0.x, n.0.y], [-n.1.x, n.1.y], [-n.2.x, n.2.y]].into(); new.push(n); - let n = Triangle((0.0, 0.0).into(), (t.0.x - t.1.x, t.0.y - t.1.y).into(), (t.2.x - t.1.x, t.2.y - t.1.y).into()); + let n = Triangle((0.0, 0.0).into(), (t.2.x - t.1.x, t.2.y - t.1.y).into(), (t.0.x - t.1.x, t.0.y - t.1.y).into()); new.push(n); let n = [[-n.0.x, n.0.y], [-n.1.x, n.1.y], [-n.2.x, n.2.y]].into(); new.push(n);