Create worlds consisting of two triangles

This commit is contained in:
Arne Keller 2019-02-12 18:46:39 +01:00
parent d12cef3a4f
commit 730bf3b77b
4 changed files with 220 additions and 96 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/target /target
**/*.rs.bk **/*.rs.bk
tri*.svg tri*.svg
world*.svg

3
dreieckeM1.txt Normal file
View File

@ -0,0 +1,3 @@
2
3 0 0 3 0 0 4
3 0 0 3 0 0 4

View File

@ -8,84 +8,6 @@ use std::fs;
use super::*; 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<RunState>) {
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<f64>) { pub(crate) fn save_tri(filename: &str, tri: Triangle<f64>) {
fs::write( fs::write(
filename, filename,
@ -93,29 +15,39 @@ pub(crate) fn save_tri(filename: &str, tri: Triangle<f64>) {
) )
.unwrap(); .unwrap();
} }
pub(crate) fn save_world(filename: &str, world: &World) {
fs::write(
filename,
generate_svg(&world.tris.iter().map(|(_idx, tri)| *tri).collect::<Vec<_>>()),
)
.unwrap();
}
pub(crate) fn generate_svg(tris: &[Triangle<f64>]) -> String { pub(crate) fn generate_svg(tris: &[Triangle<f64>]) -> String {
let mut document = Document::new() let mut document = Document::new()
// view box at (x,y), (w,h) // view box at (x,y), (w,h)
.set( .set(
"viewBox", "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"); .set("xmlns:xlink", "http://www.w3.org/1999/xlink");
for tri in tris { for tri in tris {
let data = Data::new() let data = Data::new()
.move_to((tri.0.x, tri.0.y)) .move_to((tri.0.x, -tri.0.y))
.line_to((tri.1.x, tri.1.y)) .line_to((tri.1.x, -tri.1.y))
.line_to((tri.2.x, tri.2.y)) .line_to((tri.2.x, -tri.2.y))
.close(); .close();
document.append(Path::new() document.append(Path::new()
.set("fill", "none") .set("fill", "none")
.set("stroke", "black") .set("stroke", "black")
.set("stroke-width", 10.0) .set("stroke-width", 0.4)
.set("d", data)); .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() document.to_string()

View File

@ -1,7 +1,9 @@
use geo::Triangle; use geo::{Coordinate, Triangle};
use std::cmp; use std::cmp;
use std::collections::BinaryHeap; use std::collections::BinaryHeap;
use std::f64;
use std::f64::consts::PI;
mod display; mod display;
mod input; mod input;
@ -9,7 +11,7 @@ mod input;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct World { struct World {
/// Dreiecksgrundstücke /// Dreiecksgrundstücke
tris: Vec<Triangle<f64>>, tris: Vec<(usize, Triangle<f64>)>,
/// Gesamtabstand /// Gesamtabstand
width: f64, width: f64,
} }
@ -33,22 +35,208 @@ impl cmp::PartialOrd for World {
fn main() { fn main() {
let tris = input::read_input(); let tris = input::read_input();
let tris = transformations(&tris); let tris = transformations(&tris);
/*
let save_prefix = "tri_"; let save_prefix = "tri_";
let mut save_counter = 0; let mut save_counter = 0;
for t in tris { let mut normalized_tris = Vec::with_capacity(tris.len() * 2);
display::save_tri(&format!("{}{}.svg", save_prefix, save_counter), t); 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; save_counter += 1;
} }
*/
let mut worlds = BinaryHeap::new(); 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_width = f64::MAX;
let mut best = vec![]; //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<f64>, angle: f64) -> Triangle<f64> {
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<f64>, point: Coordinate<f64>) -> f64 {
let d = (point.x.powi(2) + point.y.powi(2)).sqrt();
(point.y / d).acos()
} }
fn transformations(tris: &[Triangle<f64>]) -> Vec<Triangle<f64>> { fn transformations(tris: &[Triangle<f64>]) -> Vec<Triangle<f64>> {
@ -58,7 +246,7 @@ fn transformations(tris: &[Triangle<f64>]) -> Vec<Triangle<f64>> {
new.push(n); new.push(n);
let n = [[-n.0.x, n.0.y], [-n.1.x, n.1.y], [-n.2.x, n.2.y]].into(); let n = [[-n.0.x, n.0.y], [-n.1.x, n.1.y], [-n.2.x, n.2.y]].into();
new.push(n); 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); new.push(n);
let n = [[-n.0.x, n.0.y], [-n.1.x, n.1.y], [-n.2.x, n.2.y]].into(); let n = [[-n.0.x, n.0.y], [-n.1.x, n.1.y], [-n.2.x, n.2.y]].into();
new.push(n); new.push(n);