Overhaul algorithm, pt. 1

This commit is contained in:
Arne Keller 2019-04-04 16:32:47 +02:00
parent b9f646acf7
commit 25d9c6e29c
3 changed files with 280 additions and 26 deletions

View File

@ -8,7 +8,7 @@ use std::fs;
use super::*;
pub(crate) fn save_tri(filename: &str, tri: Triangle<f32>) {
pub(crate) fn save_tri(filename: &str, tri: Triangle) {
fs::write(filename, generate_svg(&[tri])).unwrap();
}
pub(crate) fn save_world(filename: &str, world: &World) {
@ -25,7 +25,7 @@ pub(crate) fn save_world(filename: &str, world: &World) {
.unwrap();
}
pub(crate) fn generate_svg(tris: &[Triangle<f32>]) -> String {
pub(crate) fn generate_svg(tris: &[Triangle]) -> String {
let mut document = Document::new()
// view box at (x,y), (w,h)
.set("viewBox", (-350.0, -150.0, 360.0, 150.0))

View File

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

View File

@ -1,5 +1,4 @@
use geo::prelude::*;
use geo::{Coordinate, Triangle};
use std::cmp;
use std::collections::BinaryHeap;
@ -9,10 +8,13 @@ use std::f32::consts::PI;
mod display;
mod input;
type Coordinate = geo::Coordinate<f32>;
type Triangle = geo::Triangle<f32>;
#[derive(Debug, Clone)]
struct World {
/// Dreiecksgrundstücke
tris: Vec<(usize, Triangle<f32>)>,
tris: Vec<(usize, Triangle)>,
/// Gesamtabstand
width: f32,
}
@ -148,6 +150,258 @@ fn main() {
let save_prefix = "start_";
save_counter = 0;
let mut worlds = BinaryHeap::new();
for t in &left_tris {
let mut world = World {
tris: vec![*t],
width: 0.0,
};
world.normalize();
display::save_world(&format!("{}{}.svg", save_prefix, save_counter), &world);
save_counter += 1;
worlds.push(world);
}
let mut best = World {
tris: vec![],
width: f32::MAX,
};
let save_prefix = "world_";
save_counter = 0;
let mut counter = 0;
while !worlds.is_empty() {
counter += 1;
if counter % 10000 == 0 {
println!("{}/∞", counter);
}
let w = worlds.pop().unwrap();
//println!("working");
if w.width >= best.width {
continue;
}
//println!("s: {:?}", w);
/*
if save_counter < 1000000 {
display::save_world(&format!("{}a_{}.svg", save_prefix, save_counter), &w);
}
*/
let save_iterations = false;
let mut new = vec![];
for (next_idx, next_tri) in left_tris
.iter()
.filter(|(idx1, _tri)| w.tris.iter().all(|(idx2, _tri)| idx1 != idx2))
{
let next_tri = *next_tri;
//println!("trying {:?}", next_idx);
let (last_idx, last_tri) = *w.tris.last().unwrap();
let free_angle = right_of(last_tri);
let next_angle = left_of(next_tri);
//println!("{:?} -> {:?}: {:?} {:?}", last_idx, next_idx, free_angle.to_degrees(), next_angle.to_degrees());
let target = (next_angle - PI + free_angle).to_degrees();
for angle in [0.0] {
//println!("angle {:?}", angle);
let radians = angle.to_radians();
let next_angle = next_angle - radians;
let mut tri = rotate(next_tri, radians);
// "binary search"-like optimization here
for &delta in &[
/*80.0, 30.0, 10.0, 5.0,*/ 1.0, 0.6, 0.32, 0.18, 0.1, 0.06, 0.03, 0.01,
0.003,
] {
let initial_state = last_tri.intersects(&tri);
let dx = if initial_state { delta } else { -delta };
while last_tri.intersects(&tri) == initial_state {
tri.0.x += dx;
tri.1.x += dx;
tri.2.x += dx;
}
}
let mut w = w.clone();
w.tris.push((*next_idx, tri));
w.normalize();
w.calc_width();
if save_iterations {
display::save_world(&format!("{}b_{}.svg", save_prefix, save_counter), &w);
}
if w.tris.len() == count_tris {
if w.width < best.width {
println!("[{}] new best: {}", save_counter, w.width);
//println!("{:?}", w.tris);
display::save_world(
&format!("{}best_{}.svg", save_prefix, save_counter),
&w,
);
best = w;
}
} else if w.width < best.width {
w.width -= (2.0 * PI - free_angle - next_angle) * 0.01;
//if (angle > 50 && angle < 55) || (angle > 88 && angle < 92) {
//println!("{:?} -> {:?}", angle, w.width);
//}
new.push(w);
}
save_counter += 1;
}
}
worlds.extend(new);
}
println!("best width = {:?}", best.width);
display::save_world("world_best.svg", &best);
}
fn left_of(tri: Triangle) -> f32 {
let vertex1 = tri.1;
let vertex2 = tri.2;
let next_angle = if vertex1.y > 0.001 && vertex2.y > 0.001 {
let angle1 = 0.5 * PI + vertex1.x.signum() * (vertex1.x.abs() / vertex1.y).atan();
let angle2 = 0.5 * PI + vertex2.x.signum() * (vertex2.x.abs() / vertex2.y).atan();
min(angle1, angle2)
} else if vertex1.y < 0.001 {
0.5 * PI + vertex2.x.signum() * (vertex2.x.abs() / vertex2.y).atan()
} else {
0.5 * PI + vertex1.x.signum() * (vertex1.x.abs() / vertex1.y).atan()
};
next_angle
}
fn right_of(tri: Triangle) -> f32 {
let vertex1 = tri.1;
let vertex2 = tri.2;
let free_angle = if vertex1.y > 0.001 && vertex2.y < 0.001 {
PI - (vertex1.y / (vertex2.x - vertex1.x).abs()).atan()
} else if vertex2.y > 0.001 && vertex1.y < 0.001 {
PI - (vertex2.y / (vertex2.x - vertex1.x).abs()).atan()
} else {
let angle1 = 0.5 * PI - vertex1.x.signum() * (vertex1.x.abs() / vertex1.y).atan();
let angle2 = 0.5 * PI - vertex2.x.signum() * (vertex2.x.abs() / vertex2.y).atan();
min(angle1, angle2)
};
free_angle
}
fn main2() {
let tris = input::read_input();
let count_tris = tris.len();
let tris = transformations(&tris);
let save_prefix = "tri_";
let mut save_counter = 0;
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.001 && rotated.2.x > -0.001 {
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.001 && rotated.2.x > -0.001 {
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.001 && rotated.2.x > -0.001 {
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.001 && rotated.2.x > -0.001 {
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.001 && rotated.2.x > -0.001 {
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.001 && rotated.2.x > -0.001 {
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.001 && rotated.2.x > -0.001 {
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.001 && rotated.2.x > -0.001 {
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 save_prefix = "start_";
save_counter = 0;
let mut worlds = BinaryHeap::new();
//let left_tris = vec![left_tris[1], left_tris[11], left_tris[17], left_tris[22], left_tris[28]];
for t in &left_tris {
let mut world = World {
@ -361,7 +615,7 @@ impl World {
}
}
fn rotate(mut tri: Triangle<f32>, angle: f32) -> Triangle<f32> {
fn rotate(mut tri: Triangle, angle: f32) -> Triangle {
let x1 = tri.1.x;
let y1 = tri.1.y;
tri.1.x = x1 * angle.cos() - y1 * angle.sin();
@ -373,35 +627,35 @@ fn rotate(mut tri: Triangle<f32>, angle: f32) -> Triangle<f32> {
tri
}
fn angle_of(_tri: Triangle<f32>, point: Coordinate<f32>) -> f32 {
fn angle_of(_tri: Triangle, point: Coordinate) -> f32 {
let d = (point.x.powi(2) + point.y.powi(2)).sqrt();
(point.y / d).acos()
}
fn transformations(tris: &[Triangle<f32>]) -> Vec<Triangle<f32>> {
let mut new = Vec::with_capacity(tris.len() * 6);
fn transformations(tris: &[Triangle]) -> Vec<Triangle> {
let mut new: Vec<Triangle> = Vec::with_capacity(tris.len() * 6);
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 = [
(0.0, 0.0),
(t.1.x - t.0.x, t.1.y - t.0.y),
(t.2.x - t.0.x, t.2.y - t.0.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);
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 = [
(0.0, 0.0),
(t.2.x - t.1.x, t.2.y - t.1.y),
(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);
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 = [
(0.0, 0.0),
(t.0.x - t.2.x, t.0.y - t.2.y),
(t.1.x - t.2.x, t.1.y - t.2.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);