Add heuristic

This commit is contained in:
Arne Keller 2019-03-22 19:13:48 +01:00
parent b0425e73ef
commit 0094cfa2d5
4 changed files with 240 additions and 166 deletions

3
.gitignore vendored
View File

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

View File

@ -8,28 +8,27 @@ use std::fs;
use super::*; use super::*;
pub(crate) fn save_tri(filename: &str, tri: Triangle<f64>) { pub(crate) fn save_tri(filename: &str, tri: Triangle<f32>) {
fs::write( fs::write(filename, generate_svg(&[tri])).unwrap();
filename,
generate_svg(&[tri]),
)
.unwrap();
} }
pub(crate) fn save_world(filename: &str, world: &World) { pub(crate) fn save_world(filename: &str, world: &World) {
fs::write( fs::write(
filename, filename,
generate_svg(&world.tris.iter().map(|(_idx, tri)| *tri).collect::<Vec<_>>()), generate_svg(
&world
.tris
.iter()
.map(|(_idx, tri)| *tri)
.collect::<Vec<_>>(),
),
) )
.unwrap(); .unwrap();
} }
pub(crate) fn generate_svg(tris: &[Triangle<f64>]) -> String { pub(crate) fn generate_svg(tris: &[Triangle<f32>]) -> 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", (-30.0, -30.0, 60.0, 30.0))
"viewBox",
(-30.0, -30.0, 60.0, 30.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 {
@ -38,16 +37,20 @@ pub(crate) fn generate_svg(tris: &[Triangle<f64>]) -> String {
.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", 0.4) .set("stroke-width", 0.4)
.set("d", data)); .set("d", data),
document.append(Circle::new() );
document.append(
Circle::new()
.set("fill", "red") .set("fill", "red")
.set("cx", tri.0.x) .set("cx", tri.0.x)
.set("cy", -tri.0.y) .set("cy", -tri.0.y)
.set("r", 0.3)); .set("r", 0.3),
);
} }
document.to_string() document.to_string()

View File

@ -3,11 +3,11 @@ use super::*;
use std::io; use std::io;
use std::io::prelude::*; use std::io::prelude::*;
pub(crate) fn read_input() -> Vec<Triangle<f64>> { pub(crate) fn read_input() -> Vec<Triangle<f32>> {
read_stdin() read_stdin()
} }
fn read_stdin() -> Vec<Triangle<f64>> { fn read_stdin() -> Vec<Triangle<f32>> {
let stdin = io::stdin(); let stdin = io::stdin();
let stdin = stdin.lock(); let stdin = stdin.lock();
@ -21,9 +21,9 @@ fn read_stdin() -> Vec<Triangle<f64>> {
.trim() .trim()
.split(' ') .split(' ')
.skip(1) .skip(1)
.map(|x| x.parse::<f64>().unwrap()) .map(|x| x.parse::<f32>().unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
tris.push([[n[0],n[1]],[n[2],n[3]],[n[4],n[5]]].into()); tris.push([[n[0], n[1]], [n[2], n[3]], [n[4], n[5]]].into());
} }
tris tris

View File

@ -1,10 +1,10 @@
use geo::{Coordinate, Triangle};
use geo::prelude::*; use geo::prelude::*;
use geo::{Coordinate, Triangle};
use std::cmp; use std::cmp;
use std::collections::BinaryHeap; use std::collections::BinaryHeap;
use std::f64; use std::f32;
use std::f64::consts::PI; use std::f32::consts::PI;
mod display; mod display;
mod input; mod input;
@ -12,9 +12,9 @@ mod input;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct World { struct World {
/// Dreiecksgrundstücke /// Dreiecksgrundstücke
tris: Vec<(usize, Triangle<f64>)>, tris: Vec<(usize, Triangle<f32>)>,
/// Gesamtabstand /// Gesamtabstand
width: f64, width: f32,
} }
impl cmp::PartialEq for World { impl cmp::PartialEq for World {
fn eq(&self, _other: &Self) -> bool { fn eq(&self, _other: &Self) -> bool {
@ -46,67 +46,97 @@ fn main() {
idx /= 6; idx /= 6;
let prev_angle = angle_of(t, t.1); let prev_angle = angle_of(t, t.1);
let mut added = false; let mut added = false;
let rotated = rotate(t, 0.5*PI - prev_angle); 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) { 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)); normalized_tris.push((idx, rotated));
if rotated.1.x > 0.0 && rotated.2.x > 0.0 { if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
left_tris.push((idx, rotated)); left_tris.push((idx, rotated));
} }
added = true; added = true;
} }
let rotated = rotate(rotated, PI); 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) { 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)); normalized_tris.push((idx, rotated));
if rotated.1.x > 0.0 && rotated.2.x > 0.0 { if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
left_tris.push((idx, rotated)); left_tris.push((idx, rotated));
} }
added = true; added = true;
} }
let rotated = rotate(t, -0.5*PI + prev_angle); 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) { 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)); normalized_tris.push((idx, rotated));
if rotated.1.x > 0.0 && rotated.2.x > 0.0 { if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
left_tris.push((idx, rotated)); left_tris.push((idx, rotated));
} }
added = true; added = true;
} }
let rotated = rotate(rotated, PI); 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) { 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)); normalized_tris.push((idx, rotated));
if rotated.1.x > 0.0 && rotated.2.x > 0.0 { if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
left_tris.push((idx, rotated)); left_tris.push((idx, rotated));
} }
} }
let prev_angle = angle_of(t, t.2); let prev_angle = angle_of(t, t.2);
added = false; added = false;
let rotated = rotate(t, 0.5*PI - prev_angle); 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) { 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)); normalized_tris.push((idx, rotated));
if rotated.1.x > 0.0 && rotated.2.x > 0.0 { if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
left_tris.push((idx, rotated)); left_tris.push((idx, rotated));
} }
added = true; added = true;
} }
let rotated = rotate(rotated, PI); 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) { 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)); normalized_tris.push((idx, rotated));
if rotated.1.x > 0.0 && rotated.2.x > 0.0 { if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
left_tris.push((idx, rotated)); left_tris.push((idx, rotated));
} }
added = true; added = true;
} }
let rotated = rotate(t, -0.5*PI + prev_angle); 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) { 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)); normalized_tris.push((idx, rotated));
if rotated.1.x > 0.0 && rotated.2.x > 0.0 { if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
left_tris.push((idx, rotated)); left_tris.push((idx, rotated));
} }
added = true; added = true;
} }
let rotated = rotate(rotated, PI); 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) { 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)); normalized_tris.push((idx, rotated));
if rotated.1.x > 0.0 && rotated.2.x > 0.0 { if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
left_tris.push((idx, rotated)); left_tris.push((idx, rotated));
} }
} }
@ -115,58 +145,80 @@ fn main() {
display::save_tri(&format!("{}{}.svg", save_prefix, save_counter), *t); display::save_tri(&format!("{}{}.svg", save_prefix, save_counter), *t);
save_counter += 1; save_counter += 1;
} }
let save_prefix = "start_";
save_counter = 0;
let mut worlds = BinaryHeap::new(); let mut worlds = BinaryHeap::new();
for t in &left_tris { for t in &left_tris {
let mut world = World { let mut world = World {
tris: vec![*t], tris: vec![*t],
width: 0.0 width: 0.0,
}; };
world.normalize(); world.normalize();
display::save_world(&format!("{}{}.svg", save_prefix, save_counter), &world);
save_counter += 1;
worlds.push(world); worlds.push(world);
} }
let mut best = World { tris: vec![], width: f64::MAX }; let mut best = World {
tris: vec![],
width: f32::MAX,
};
let save_prefix = "world_"; let save_prefix = "world_";
let mut save_counter = 0; save_counter = 0;
while worlds.peek().map(|x| x.width <= best.width) == Some(true) { while worlds.peek().map(|x| x.width <= best.width) == Some(true) {
let w = worlds.pop().unwrap(); let w = worlds.pop().unwrap();
//println!("s: {:?}", w); //println!("s: {:?}", w);
let mut new = vec![]; let mut new = vec![];
for (next_idx, next_tri) in left_tris.iter() for (next_idx, next_tri) in left_tris
.filter(|(idx1, _tri)| w.tris.iter().all(|(idx2, _tri)| idx1 != idx2)) { .iter()
.filter(|(idx1, _tri)| w.tris.iter().all(|(idx2, _tri)| idx1 != idx2))
{
//println!("trying {:?}", next_idx); //println!("trying {:?}", next_idx);
let (_, last_tri) = *w.tris.last().unwrap(); 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) { 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 last_tri.1
} else { } else {
last_tri.2 last_tri.2
}; };
let mut free_angle = angle_of(last_tri, last_vertex); let mut free_angle = angle_of(last_tri, last_vertex);
//println!("angle of {:?}: {:?}", last_vertex, free_angle); //println!("angle of {:?}: {:?}", last_vertex, free_angle);
if last_vertex.x > 0.0 { if last_vertex.x > 0.0 {
free_angle = 0.5*PI - free_angle; free_angle = 0.5 * PI - free_angle;
} else { } else {
free_angle = 0.5*PI + free_angle; free_angle = 0.5 * PI + free_angle;
} }
let next_vertex = if next_tri.1.y > 0.01 { let next_vertex = if next_tri.1.y < 0.001 && next_tri.1.y > -0.001 {
next_tri.2
} else if next_tri.2.y < 0.001 && next_tri.2.y > -0.001 {
next_tri.1
} else if next_tri.1.x < next_tri.2.x {
next_tri.1 next_tri.1
} else { } else {
next_tri.2 next_tri.2
}; };
let mut next_angle = angle_of(*next_tri, next_vertex); let next_angle = PI - angle_of(*next_tri, next_vertex);
if next_vertex.x > 0.0 {
next_angle = 0.5*PI - next_angle; for angle in 0..=150 {
let angle = (1.0 * angle as f32).to_radians();
let next_angle = next_angle - angle;
let mut tri = rotate(*next_tri, angle);
let dx = if last_tri.intersects(&tri) {
0.005
} else { } else {
next_angle = 0.5*PI + next_angle; -0.005
};
while last_tri.intersects(&tri) {
tri.0.x += dx;
tri.1.x += dx;
tri.2.x += dx;
} }
if next_angle <= free_angle {
// easy: just rotate to fit and put it below the last triangle
let mut w = w.clone(); let mut w = w.clone();
w.tris.push((*next_idx, rotate(*next_tri, free_angle - next_angle))); w.tris.push((*next_idx, tri));
//println!("new {:?} {:?} {:?}: {:?}", save_counter, free_angle, next_angle, w);
w.normalize(); w.normalize();
w.calc_width(); w.calc_width();
if save_counter < 100 { if save_counter < 100 {
@ -175,36 +227,15 @@ fn main() {
if w.tris.len() == count_tris { if w.tris.len() == count_tris {
if w.width < best.width { if w.width < best.width {
println!("new best: {}", w.width); println!("new best: {}", w.width);
println!("{:?}", w.tris);
display::save_world(
&format!("{}best_{}.svg", save_prefix, save_counter),
&w,
);
best = w; best = w;
} }
} else { } else {
new.push(w); w.width -= (2.0 * PI - free_angle - next_angle) * 0.003 * w.tris.len() as f32;
}
save_counter += 1;
} else {
// "hard": move it right till it fits
print!("error: doesn't fit [S{} {}]", w.tris.len(), save_counter);
assert!(last_tri.intersects(next_tri));
let mut next_tri = *next_tri;
while last_tri.intersects(&next_tri) {
next_tri.0.x += 0.005;
next_tri.1.x += 0.005;
next_tri.2.x += 0.005;
}
let mut w = w.clone();
w.tris.push((*next_idx, next_tri));
w.normalize();
w.calc_width();
println!(" -> width = {}", w.width);
if save_counter < 100 {
display::save_world(&format!("{}{}.svg", save_prefix, save_counter), &w);
}
if w.tris.len() == count_tris {
if w.width < best.width {
println!("new best: {}", w.width);
best = w;
}
} else {
new.push(w); new.push(w);
} }
save_counter += 1; save_counter += 1;
@ -234,7 +265,7 @@ impl World {
self.move_left(maxx); self.move_left(maxx);
} }
} }
fn move_left(&mut self, amount: f64) { fn move_left(&mut self, amount: f32) {
for (_, tri) in &mut self.tris { for (_, tri) in &mut self.tris {
tri.0.x -= amount; tri.0.x -= amount;
tri.1.x -= amount; tri.1.x -= amount;
@ -242,55 +273,96 @@ impl World {
} }
} }
fn calc_width(&mut self) { fn calc_width(&mut self) {
let mut x = vec![]; let mut minx = f32::MIN;
for (_, tri) in &self.tris { if (self.tris[0].1).0.y > -0.001 && (self.tris[0].1).0.y < 0.001 {
if tri.0.y < 0.001 && tri.0.y > -0.001 { minx = max((self.tris[0].1).0.x, minx);
x.push(tri.0.x);
} }
if tri.1.y < 0.001 && tri.1.y > -0.001 { if (self.tris[0].1).1.y > -0.001 && (self.tris[0].1).1.y < 0.001 {
x.push(tri.1.x); minx = max((self.tris[0].1).1.x, minx);
} }
if tri.2.y < 0.001 && tri.2.y > -0.001 { if (self.tris[0].1).2.y > -0.001 && (self.tris[0].1).2.y < 0.001 {
x.push(tri.2.x); minx = max((self.tris[0].1).2.x, minx);
} }
let mut maxx = f32::MAX;
if (self.tris[self.tris.len() - 1].1).0.y > -0.001
&& (self.tris[self.tris.len() - 1].1).0.y < 0.001
{
maxx = min((self.tris[self.tris.len() - 1].1).0.x, maxx);
} }
x.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap()); if (self.tris[self.tris.len() - 1].1).1.y > -0.001
self.width = x[x.len()-2] - x[1]; && (self.tris[self.tris.len() - 1].1).1.y < 0.001
{
maxx = min((self.tris[self.tris.len() - 1].1).1.x, maxx);
}
if (self.tris[self.tris.len() - 1].1).2.y > -0.001
&& (self.tris[self.tris.len() - 1].1).2.y < 0.001
{
maxx = min((self.tris[self.tris.len() - 1].1).2.x, maxx);
}
self.width = maxx - minx;
} }
} }
fn rotate(mut tri: Triangle<f64>, angle: f64) -> Triangle<f64> { fn rotate(mut tri: Triangle<f32>, angle: f32) -> Triangle<f32> {
let x1 = tri.1.x; let x1 = tri.1.x;
let y1 = tri.1.y; let y1 = tri.1.y;
tri.1.x = x1*angle.cos() - y1*angle.sin(); tri.1.x = x1 * angle.cos() - y1 * angle.sin();
tri.1.y = x1*angle.sin() + y1*angle.cos(); tri.1.y = x1 * angle.sin() + y1 * angle.cos();
let x2 = tri.2.x; let x2 = tri.2.x;
let y2 = tri.2.y; let y2 = tri.2.y;
tri.2.x = x2*angle.cos() - y2*angle.sin(); tri.2.x = x2 * angle.cos() - y2 * angle.sin();
tri.2.y = x2*angle.sin() + y2*angle.cos(); tri.2.y = x2 * angle.sin() + y2 * angle.cos();
tri tri
} }
fn angle_of(_tri: Triangle<f64>, point: Coordinate<f64>) -> f64 { fn angle_of(_tri: Triangle<f32>, point: Coordinate<f32>) -> f32 {
let d = (point.x.powi(2) + point.y.powi(2)).sqrt(); let d = (point.x.powi(2) + point.y.powi(2)).sqrt();
(point.y / d).acos() (point.y / d).acos()
} }
fn transformations(tris: &[Triangle<f64>]) -> Vec<Triangle<f64>> { fn transformations(tris: &[Triangle<f32>]) -> Vec<Triangle<f32>> {
let mut new = Vec::with_capacity(tris.len() * 6); let mut new = Vec::with_capacity(tris.len() * 6);
for t in tris { for t in tris {
let n = Triangle((0.0, 0.0).into(), (t.1.x - t.0.x, t.1.y - t.0.y).into(), (t.2.x - t.0.x, t.2.y - t.0.y).into()); let n = Triangle(
(0.0, 0.0).into(),
(t.1.x - t.0.x, t.1.y - t.0.y).into(),
(t.2.x - t.0.x, t.2.y - t.0.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);
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()); 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);
let n = Triangle((0.0, 0.0).into(), (t.0.x - t.2.x, t.0.y - t.2.y).into(), (t.1.x - t.2.x, t.1.y - t.2.y).into()); let n = Triangle(
(0.0, 0.0).into(),
(t.0.x - t.2.x, t.0.y - t.2.y).into(),
(t.1.x - t.2.x, t.1.y - t.2.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);
} }
new new
} }
fn min(a: f32, b: f32) -> f32 {
if a < b {
a
} else {
b
}
}
fn max(a: f32, b: f32) -> f32 {
if a > b {
a
} else {
b
}
}