Add caching for intersection checks
This commit is contained in:
parent
551a0ba14c
commit
c13029c5e5
31
Cargo.lock
generated
31
Cargo.lock
generated
@ -5,7 +5,8 @@ name = "aufgabe1"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"geo 0.12.0",
|
||||
"geo 0.12.0 (git+https://github.com/FliegendeWurst/geo)",
|
||||
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rstar 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -45,6 +46,11 @@ name = "bitflags"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.32"
|
||||
@ -106,9 +112,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "geo"
|
||||
version = "0.12.0"
|
||||
source = "git+https://github.com/FliegendeWurst/geo#2b702bce790d918e09dbc6cb4f244312636a87b5"
|
||||
dependencies = [
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"geo-types 0.4.1",
|
||||
"geo-types 0.4.1 (git+https://github.com/FliegendeWurst/geo)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rstar 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -116,11 +123,21 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "geo-types"
|
||||
version = "0.4.1"
|
||||
source = "git+https://github.com/FliegendeWurst/geo#2b702bce790d918e09dbc6cb4f244312636a87b5"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rstar 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.1"
|
||||
@ -233,6 +250,11 @@ name = "rustc-demangle"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "simplecss"
|
||||
version = "0.1.0"
|
||||
@ -385,6 +407,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4"
|
||||
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
|
||||
"checksum cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ad0daef304fa0b4238f5f7ed7178774b43b06f6a9b6509f6642bef4ff1f7b9b2"
|
||||
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
|
||||
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
|
||||
@ -392,6 +415,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
|
||||
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
|
||||
"checksum float-cmp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "134a8fa843d80a51a5b77d36d42bc2def9edcb0262c914861d08129fd1926600"
|
||||
"checksum geo 0.12.0 (git+https://github.com/FliegendeWurst/geo)" = "<none>"
|
||||
"checksum geo-types 0.4.1 (git+https://github.com/FliegendeWurst/geo)" = "<none>"
|
||||
"checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da"
|
||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
||||
"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
|
||||
@ -408,6 +434,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum roxmltree 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "53b0200cbfa8b3f6cfd6076592717d697a1ddc57cb2a8fbfd3d133c06011b579"
|
||||
"checksum rstar 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "120bfe4837befb82c5a637a5a8c490a27d25524ac19fffec5b4e555ca6e36ee8"
|
||||
"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
|
||||
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
|
||||
"checksum simplecss 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "135685097a85a64067df36e28a243e94a94f76d829087ce0be34eeb014260c0e"
|
||||
"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
|
||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
|
@ -8,12 +8,14 @@ edition = "2018"
|
||||
codegen-units = 1
|
||||
opt-level = 3
|
||||
panic = "abort"
|
||||
debug = true
|
||||
|
||||
[dependencies]
|
||||
geo = { path = "/home/arne/Documents/Code/Github/geo/geo" }
|
||||
geo = { git = "https://github.com/FliegendeWurst/geo" }
|
||||
svg = "0.5.11"
|
||||
chrono = "0.4.6"
|
||||
structopt = { version = "0.2", default-features = false }
|
||||
svgdom = "0.16.1"
|
||||
rstar = "0.2.0"
|
||||
lazy_static = "1.3.0"
|
||||
hashbrown = "0.1.8"
|
||||
|
@ -239,7 +239,7 @@ Der Weg von Lisa und dem Bus ist animiert. Zusätzlich zu den unbedingt benötig
|
||||
\subsection{Optimierungen}
|
||||
Wie bereits in der Laufzeitanalyse kurz angesprochen, benutzt das Programm bestimmte Heuristiken, um die Suche zu beschleunigen. Eine davon ist die maximal mögliche Wartezeit für eine bestimmte Route. Dafür berechnet das Programm die höchstmögliche Position des Busses, was proportional zur gesuchten Größe ist.
|
||||
|
||||
Um zu überprüfen, ob ein Routenabschnitt die Hindernisse schneidet, wird unter anderem ein R*-Baum benutzt. Mit ca. 40 Polygonen ist diese Methode ca. 5-6x schneller als alle Polygone zu überprüfen. Die Geschwindigkeitsgewinne werden größer, je mehr Polygone vorhanden sind.
|
||||
Um zu überprüfen, ob ein Routenabschnitt die Hindernisse schneidet, wird unter anderem ein R*-Baum benutzt. Fûr ca. 40 Polygonen ist diese Methode ca. 5-6x schneller als alle Polygone zu überprüfen. Die Geschwindigkeitsgewinne werden größer, je mehr Polygone vorhanden sind. Zudem wird das Ergebnis in einer Hashtabelle gespeichert, was die insgesamte Performanz ca. 6-10x steigert ($\frac{n*(n-1)}{2}$ Berechnungen statt $n!$).
|
||||
|
||||
\section{Beispiele}
|
||||
Alle Beispiele sind im Maßstab 1:70m.
|
||||
|
@ -9,7 +9,7 @@ use std::fs;
|
||||
use super::*;
|
||||
|
||||
pub(crate) fn dump_latex_code(route: &[RunState], polys: &[Polygon]) {
|
||||
const SCALE: f64 = 70.0;
|
||||
const SCALE: f32 = 70.0;
|
||||
let mut xmax = 0.0;
|
||||
let mut ymax = 0.0;
|
||||
for poly in polys {
|
||||
@ -220,7 +220,7 @@ pub(crate) fn generate_svg(
|
||||
document.append(path);
|
||||
}
|
||||
|
||||
let mut first: (f64, f64) = (route1[0].x(), route1[0].y());
|
||||
let mut first: (f32, f32) = (route1[0].x(), route1[0].y());
|
||||
first.1 *= -1.0;
|
||||
let mut data = Data::new().move_to(first);
|
||||
for point in &route1[1..] {
|
||||
|
@ -85,16 +85,16 @@ fn read_svg(input: &str) -> Result<InputData, Box<Error>> {
|
||||
for p in &path.0 {
|
||||
match p {
|
||||
PathSegment::MoveTo { x, y, .. } => {
|
||||
points.push(Point::new(*x, -*y));
|
||||
points.push(Point::new(*x as f32, -*y as f32));
|
||||
}
|
||||
PathSegment::LineTo { x, y, .. } => {
|
||||
points.push(Point::new(*x, -*y));
|
||||
points.push(Point::new(*x as f32, -*y as f32));
|
||||
}
|
||||
PathSegment::VerticalLineTo { y, .. } => {
|
||||
points.push(Point::new(points.last().unwrap().x(), -*y));
|
||||
points.push(Point::new(points.last().unwrap().x(), -*y as f32));
|
||||
}
|
||||
PathSegment::HorizontalLineTo { x, .. } => {
|
||||
points.push(Point::new(*x, points.last().unwrap().y()));
|
||||
points.push(Point::new(*x as f32, points.last().unwrap().y()));
|
||||
}
|
||||
PathSegment::ClosePath { .. } => break,
|
||||
_ => unimplemented!("nicht unterstütztes SVG-Element: {:?}", p),
|
||||
|
41
src/main.rs
41
src/main.rs
@ -1,12 +1,13 @@
|
||||
use chrono::{Duration, NaiveTime};
|
||||
use geo::prelude::*;
|
||||
use hashbrown::HashMap;
|
||||
use lazy_static::lazy_static;
|
||||
use rstar::{RTree, RTreeObject};
|
||||
use structopt::StructOpt;
|
||||
|
||||
use std::cmp;
|
||||
use std::collections::BinaryHeap;
|
||||
use std::f64;
|
||||
use std::f32;
|
||||
use std::process::exit;
|
||||
use std::sync::RwLock;
|
||||
use std::time::{self, Instant};
|
||||
@ -14,10 +15,10 @@ use std::time::{self, Instant};
|
||||
mod display;
|
||||
mod input;
|
||||
|
||||
type Point = geo::Point<f64>;
|
||||
type Line = geo::Line<f64>;
|
||||
type LineString = geo::LineString<f64>;
|
||||
type Polygon = geo::Polygon<f64>;
|
||||
type Point = geo::Point<f32>;
|
||||
type Line = geo::Line<f32>;
|
||||
type LineString = geo::LineString<f32>;
|
||||
type Polygon = geo::Polygon<f32>;
|
||||
|
||||
/// Datenstruktur für Kommandozeilen-Argumente
|
||||
#[derive(StructOpt, Clone, Copy)]
|
||||
@ -34,21 +35,21 @@ struct Opt {
|
||||
tkz: bool,
|
||||
/// Geschwindigkeit von Lisa (in km/h)
|
||||
#[structopt(short = "l", long = "lisa", default_value = "15")]
|
||||
lisa: f64,
|
||||
lisa: f32,
|
||||
/// Geschwindigkeit vom Bus (in km/h)
|
||||
#[structopt(short = "b", long = "bus", default_value = "30")]
|
||||
bus: f64,
|
||||
bus: f32,
|
||||
}
|
||||
|
||||
/// Möglicher Zustand von Lisas Rennen
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
struct RunState {
|
||||
/// Theoretisch mögliche Startposition des Busses
|
||||
bus: f64,
|
||||
bus: f32,
|
||||
/// Lisas Position
|
||||
pos: Point,
|
||||
// Bisher zurückgelegte Strecke
|
||||
total_distance: f64,
|
||||
total_distance: f32,
|
||||
}
|
||||
/// Trait-Implementierung, damit die Struktur in BinaryHeaps passt
|
||||
impl cmp::Eq for RunState {}
|
||||
@ -134,7 +135,7 @@ fn main() {
|
||||
states.push(vec![start]);
|
||||
|
||||
// beste Lösung speichern
|
||||
let mut best_bus = f64::NEG_INFINITY;
|
||||
let mut best_bus = f32::NEG_INFINITY;
|
||||
let mut best = vec![];
|
||||
// Zwischenlösungen speichern
|
||||
let save_prefix = "route_";
|
||||
@ -274,11 +275,22 @@ fn main() {
|
||||
|
||||
lazy_static! {
|
||||
static ref RTREE: RwLock<RTree<Polygon>> = RwLock::new(RTree::new());
|
||||
static ref COLLISIONS: RwLock<HashMap<[i16; 4], bool>> = RwLock::new(HashMap::new());
|
||||
}
|
||||
|
||||
/// Schneidet die Linie keines der Polygone?
|
||||
/// (Berührungen erlaubt)
|
||||
fn none_intersect(line: Line) -> bool {
|
||||
fn none_intersect(mut line: Line) -> bool {
|
||||
if line.start.y > line.end.y || (line.start.y == line.end.y && line.start.x > line.end.x) {
|
||||
let end = line.start;
|
||||
line.start = line.end;
|
||||
line.end = end;
|
||||
}
|
||||
let mut collisions = COLLISIONS.write().unwrap();
|
||||
let id = [line.start.x as i16, line.start.y as i16, line.end.x as i16, line.end.y as i16];
|
||||
if let Some(&r) = collisions.get(&id) {
|
||||
return r;
|
||||
}
|
||||
let rtree = RTREE.read().unwrap();
|
||||
let polys = rtree.locate_in_envelope_intersecting(&line.envelope());
|
||||
let mut middle = line.start;
|
||||
@ -305,29 +317,32 @@ fn none_intersect(line: Line) -> bool {
|
||||
continue; // Linie schneidet sich immer selbst
|
||||
}
|
||||
if l.intersects(&line) {
|
||||
collisions.insert(id, false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// falls Mittelpunkt in Polygon:
|
||||
if p.euclidean_distance(&middle) == 0.0 {
|
||||
// schneidet Polygon
|
||||
collisions.insert(id, false);
|
||||
return false;
|
||||
}
|
||||
// (dieser Fall tritt auf, wenn die Linie von einer Polygon-Ecke zu einer anderen Ecke verläuft)
|
||||
}
|
||||
// keine Überschneidung gefunden: der Weg ist frei!
|
||||
collisions.insert(id, true);
|
||||
true
|
||||
}
|
||||
|
||||
/// Euklidische Distanz zweier Punkte
|
||||
fn distance(a: Point, b: Point) -> f64 {
|
||||
fn distance(a: Point, b: Point) -> f32 {
|
||||
((a.x() - b.x()).powi(2) + (a.y() - b.y()).powi(2)).sqrt()
|
||||
}
|
||||
|
||||
/// Mit dieser Funktion kann man bestimmen, wo der Bus zu Lisas Startzeit war.
|
||||
/// Die Funktion nimmt an, dass Lisa, von ihrer aktuellen Position aus, den Bus ohne Umwege erreichen kann.
|
||||
/// Sehr hilfreich als Heuristik, da die theoretisch beste Lösung nie schlechter als das eigentliche Ergebnis sein kann.
|
||||
fn best_bus_pos(opt: &Opt, total_distance: f64, lisa: Point) -> f64 {
|
||||
fn best_bus_pos(opt: &Opt, total_distance: f32, lisa: Point) -> f32 {
|
||||
let x_l = lisa.x(); // a
|
||||
let y_l = lisa.y(); // b
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user