Create worlds consisting of two triangles
This commit is contained in:
parent
d12cef3a4f
commit
730bf3b77b
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
tri*.svg
|
||||
world*.svg
|
3
dreieckeM1.txt
Normal file
3
dreieckeM1.txt
Normal file
@ -0,0 +1,3 @@
|
||||
2
|
||||
3 0 0 3 0 0 4
|
||||
3 0 0 3 0 0 4
|
102
src/display.rs
102
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<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>) {
|
||||
fs::write(
|
||||
filename,
|
||||
@ -93,29 +15,39 @@ pub(crate) fn save_tri(filename: &str, tri: Triangle<f64>) {
|
||||
)
|
||||
.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 {
|
||||
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()
|
||||
|
208
src/main.rs
208
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<Triangle<f64>>,
|
||||
tris: Vec<(usize, Triangle<f64>)>,
|
||||
/// Gesamtabstand
|
||||
width: f64,
|
||||
}
|
||||
@ -34,21 +36,207 @@ 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<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>> {
|
||||
@ -58,7 +246,7 @@ fn transformations(tris: &[Triangle<f64>]) -> Vec<Triangle<f64>> {
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user