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
|
/target
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
tri*.svg
|
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::*;
|
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()
|
||||||
|
210
src/main.rs
210
src/main.rs
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user