BwInf37-Runde2-Aufgabe1/src/display.rs
2019-03-31 18:02:07 +02:00

273 lines
6.2 KiB
Rust

use svg::node::element::path::Data;
use svg::node::element::Path;
use svg::node::element::{AnimateMotion, Circle, MotionPath};
use svg::Document;
use svg::Node;
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() {
let color = if idx == 0 || idx == route.len() - 1 { "green" } else { "red" };
println!("\\tkzDrawPoint[fill={},color=black,size=13](R{})", color, idx);
}
println!("\\end{{tikzpicture}}");
}
pub(crate) fn dump_route(opt: Opt, house: Point, polys: &[Polygon], route: &[RunState]) {
let (points, lines, route1, route2_start) = gen_params(opt, house, route);
print!(
"{}",
generate_svg(&points, &lines, polys, &route1, route2_start)
);
}
pub(crate) fn save_svg(
opt: Opt,
filename: &str,
house: Point,
polys: &[Polygon],
route: &[RunState],
) {
let (points, lines, route1, route2_start) = gen_params(opt, house, route);
fs::write(
filename,
generate_svg(&points, &lines, polys, &route1, route2_start),
)
.unwrap();
}
#[allow(clippy::type_complexity)]
fn gen_params(
opt: Opt,
house: Point,
route: &[RunState],
) -> (
Vec<(Point, &'static str)>,
Vec<(Line, &'static str)>,
Vec<Point>,
Point,
) {
let last = route.last().unwrap();
let points = vec![(house, "red")];
let lines = route
.iter()
.map(|x| x.pos)
.collect::<LineString>()
.lines()
.map(|x| (x, "gray"))
.collect::<Vec<_>>();
let route1 = route.iter().map(|x| x.pos).collect::<Vec<_>>();
let route2_start = last
.pos
.translate(0.0, -last.total_distance * (opt.bus / opt.lisa));
(points, lines, route1, route2_start)
}
pub(crate) fn generate_svg(
points: &[(Point, &'static str)],
lines: &[(Line, &'static str)],
polys: &[Polygon],
route1: &[Point],
route2_start: Point,
) -> String {
let dot_radius = 25.2;
let width = route1
.iter()
.map(|p| p.x())
.chain(
polys
.iter()
.map(|x| x.exterior().0.iter().map(|p| p.x))
.flatten(),
)
.max_by(|a, b| a.partial_cmp(b).unwrap())
.unwrap()
+ dot_radius * 2.0;
let upper_y = polys
.iter()
.map(|x| x.exterior().0.iter().map(|p| p.y))
.flatten()
.chain(Some(route1.last().unwrap().y()))
.max_by(|a, b| a.partial_cmp(b).unwrap())
.unwrap();
let mut document = Document::new()
// view box at (x,y), (w,h)
.set(
"viewBox",
(
-dot_radius,
-upper_y - dot_radius,
width,
-route2_start.y() + upper_y + dot_radius * 2.0,
),
)
.set("xmlns:xlink", "http://www.w3.org/1999/xlink");
for circle in points.iter().map(|(p, color)| {
Circle::new()
.set("cx", p.x())
.set("cy", -p.y())
.set("r", dot_radius)
.set("opacity", 0.5)
.set("fill", *color)
}) {
document.append(circle);
}
for path in lines.iter().map(|(l, color)| {
let data = Data::new()
.move_to((l.start.x, -l.start.y))
.line_to((l.end.x, -l.end.y))
.close();
Path::new()
.set("fill", "none")
.set("stroke", *color)
.set("stroke-width", 2.0)
.set("opacity", 0.5)
.set("d", data)
}) {
document.append(path);
}
for path in polys.iter().map(|poly| {
let coords = &poly.exterior().0;
let mut first = coords[0].x_y();
first.1 *= -1.0;
let mut data = Data::new().move_to(first);
for c in &coords[1..] {
let mut c = c.x_y();
c.1 *= -1.0;
data = data.line_to(c);
}
data = data.close();
Path::new()
.set("fill", "black")
.set("stroke", "black")
.set("stroke-width", 0)
.set("d", data)
}) {
document.append(path);
}
let mut first: (f64, f64) = (route1[0].x(), route1[0].y());
first.1 *= -1.0;
let mut data = Data::new().move_to(first);
for point in &route1[1..] {
let mut c = point.x_y();
c.1 *= -1.0;
data = data.line_to(c);
}
let path = Path::new()
.set("id", "route1")
.set("fill", "none")
.set("stroke", "none")
.set("d", data);
document.append(path);
let mut dot1 = Circle::new()
.set("cx", 0.0)
.set("cy", 0.0)
.set("r", dot_radius)
.set("opacity", 0.75)
.set("fill", "gray");
let mut motion1 = AnimateMotion::new()
.set("dur", "2s")
.set("repeatCount", "indefinite");
let path = MotionPath::new().set("xlink:href", "#route1");
motion1.append(path);
dot1.append(motion1);
document.append(dot1);
let mut first = (route2_start.x(), route2_start.y());
first.1 *= -1.0;
let mut data = Data::new().move_to(first);
let last = route1.last().unwrap();
data = data.line_to((last.x(), -last.y()));
let path = Path::new()
.set("id", "route2")
.set("fill", "none")
.set("stroke", "none")
.set("d", data);
document.append(path);
let mut dot1 = Circle::new()
.set("cx", 0.0)
.set("cy", 0.0)
.set("r", dot_radius)
.set("opacity", 0.75)
.set("fill", "gray");
let mut motion1 = AnimateMotion::new()
.set("dur", "2s")
.set("repeatCount", "indefinite");
let path = MotionPath::new().set("xlink:href", "#route2");
motion1.append(path);
dot1.append(motion1);
document.append(dot1);
document.to_string()
}