Comments, bug fixes and optimizations

This commit is contained in:
arnekeller 2019-04-02 19:18:06 +02:00
parent 5e7ba7e7eb
commit 22b262c292

View File

@ -202,7 +202,7 @@ fn main() {
total_distance, total_distance,
}, },
); );
// Verbesserung anzeigen und evtl. speichern // Verbesserung anzeigen
eprintln!( eprintln!(
"Verbesserung: {:?} ({:?}+ Möglichkeiten verbleiben)", "Verbesserung: {:?} ({:?}+ Möglichkeiten verbleiben)",
calc_time(total_distance, line.end.y), calc_time(total_distance, line.end.y),
@ -212,6 +212,7 @@ fn main() {
best.reverse(); best.reverse();
best_bus = bus; best_bus = bus;
if opt.save_intermediates { if opt.save_intermediates {
// Zwischenlösung als SVG speichern
display::save_svg( display::save_svg(
opt, opt,
&format!("{}{}.svg", save_prefix, save_counter), &format!("{}{}.svg", save_prefix, save_counter),
@ -219,18 +220,24 @@ fn main() {
&polys, &polys,
&best, &best,
); );
save_counter += 1;
} }
save_counter += 1;
} }
} }
// neu gefundene Routen speichern // neu gefundene Routen speichern
// -> automatisch im BinaryHeap einsortiert
states.extend(all); states.extend(all);
let end = Instant::now(); let end = Instant::now();
total_time += end - start; total_time += end - start;
iterations += 1; iterations += 1;
} }
if opt.debug { if opt.debug {
eprintln!("DEBUG: {}us/iteration", total_time.as_micros() / iterations); // Performanz-Schätzung anzeigen
eprintln!(
"DEBUG: {}μs/Iteration mit {} Iterationen",
total_time.as_micros() / iterations,
iterations
);
} }
// beste Lösung ausgeben // beste Lösung ausgeben
eprintln!("Finale Lösung:"); eprintln!("Finale Lösung:");
@ -263,36 +270,56 @@ fn main() {
eprintln!("x={:.02} y={:.02}", s.pos.x(), s.pos.y()); eprintln!("x={:.02} y={:.02}", s.pos.x(), s.pos.y());
} }
eprintln!("Länge: {:.0}m", last.total_distance); eprintln!("Länge: {:.0}m", last.total_distance);
let seconds = last.total_distance / (15.0 / 3.6); let seconds = last.total_distance / lisa_speed;
eprintln!("Dauer: {:02.0}:{:02.0}", seconds / 60.0, seconds % 60.0); eprintln!("Dauer: {:02.0}:{:02.0}", seconds / 60.0, seconds % 60.0);
// beste Route grafisch ausgeben // beste Route grafisch ausgeben
if opt.tkz { if opt.tkz {
// als LaTeX-kompatibler Code
display::dump_latex_code(&route, &polys); display::dump_latex_code(&route, &polys);
} else { } else {
// oder als animiertes SVG
display::dump_route(opt, house, &polys, &route); display::dump_route(opt, house, &polys, &route);
} }
// Prozess direkt beenden, ohne Variablen zu löschen
// (ca. 20% der Laufzeit..)
std::process::exit(0);
} }
// "Globale" und bei Bedarf initialisierte Variablen
lazy_static! { lazy_static! {
// R*-Baum zur Beschleunigung der Routenabschnitt-Hindernis-Überprüfungen
static ref RTREE: RwLock<RTree<Polygon>> = RwLock::new(RTree::new()); static ref RTREE: RwLock<RTree<Polygon>> = RwLock::new(RTree::new());
// Cache für die Funktion none_intersect
static ref COLLISIONS: RwLock<HashMap<[i16; 4], bool>> = RwLock::new(HashMap::new()); static ref COLLISIONS: RwLock<HashMap<[i16; 4], bool>> = RwLock::new(HashMap::new());
} }
/// Schneidet die Linie keines der Polygone? /// Schneidet die Linie keines der Polygone?
/// (Berührungen erlaubt) /// (Berührungen erlaubt)
fn none_intersect(mut line: Line) -> bool { fn none_intersect(mut line: Line) -> bool {
// Linie normalisieren
if line.start.y > line.end.y || (line.start.y == line.end.y && line.start.x > line.end.x) { if line.start.y > line.end.y || (line.start.y == line.end.y && line.start.x > line.end.x) {
let end = line.start; let end = line.start;
line.start = line.end; line.start = line.end;
line.end = end; line.end = end;
} }
// Cache laden
let mut collisions = COLLISIONS.write().unwrap(); 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]; // Liniendaten hashbar machen
let id = [
line.start.x as i16,
line.start.y as i16,
line.end.x as i16,
line.end.y as i16,
];
// evtl. gefundenes Ergebnis sofort zurückgeben
if let Some(&r) = collisions.get(&id) { if let Some(&r) = collisions.get(&id) {
return r; return r;
} }
// ansonsten:
// Polygone finden, die die AABB der Linie schneiden
let rtree = RTREE.read().unwrap(); let rtree = RTREE.read().unwrap();
let polys = rtree.locate_in_envelope_intersecting(&line.envelope()); let polys = rtree.locate_in_envelope_intersecting(&line.envelope());
// Mittelpunkt der Linie bestimmen
let mut middle = line.start; let mut middle = line.start;
middle.x += line.dx() / 2.0; middle.x += line.dx() / 2.0;
middle.y += line.dy() / 2.0; middle.y += line.dy() / 2.0;
@ -317,19 +344,21 @@ fn none_intersect(mut line: Line) -> bool {
continue; // Linie schneidet sich immer selbst continue; // Linie schneidet sich immer selbst
} }
if l.intersects(&line) { if l.intersects(&line) {
// Ergebnis im Cache speichern
collisions.insert(id, false); collisions.insert(id, false);
return false; return false;
} }
} }
// falls Mittelpunkt in Polygon: // falls Mittelpunkt in Polygon:
if p.euclidean_distance(&middle) == 0.0 { if p.euclidean_distance(&middle) == 0.0 {
// schneidet Polygon // schneidet Polygon, Ergebnis im Cache speichern
collisions.insert(id, false); collisions.insert(id, false);
return false; return false;
} }
// (dieser Fall tritt auf, wenn die Linie von einer Polygon-Ecke zu einer anderen Ecke verläuft) // (dieser Fall tritt auf, wenn die Linie von einer Polygon-Ecke zu einer anderen Ecke verläuft)
} }
// keine Überschneidung gefunden: der Weg ist frei! // keine Überschneidung gefunden: der Weg ist frei!
// (natürlich auch im Cache speichern)
collisions.insert(id, true); collisions.insert(id, true);
true true
} }