diff --git a/src/main.rs b/src/main.rs index 688a52f..3623041 100644 --- a/src/main.rs +++ b/src/main.rs @@ -202,7 +202,7 @@ fn main() { total_distance, }, ); - // Verbesserung anzeigen und evtl. speichern + // Verbesserung anzeigen eprintln!( "Verbesserung: {:?} ({:?}+ Möglichkeiten verbleiben)", calc_time(total_distance, line.end.y), @@ -212,6 +212,7 @@ fn main() { best.reverse(); best_bus = bus; if opt.save_intermediates { + // Zwischenlösung als SVG speichern display::save_svg( opt, &format!("{}{}.svg", save_prefix, save_counter), @@ -219,18 +220,24 @@ fn main() { &polys, &best, ); + save_counter += 1; } - save_counter += 1; } } // neu gefundene Routen speichern + // -> automatisch im BinaryHeap einsortiert states.extend(all); let end = Instant::now(); total_time += end - start; iterations += 1; } 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 eprintln!("Finale Lösung:"); @@ -263,36 +270,56 @@ fn main() { eprintln!("x={:.02} y={:.02}", s.pos.x(), s.pos.y()); } 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); // beste Route grafisch ausgeben if opt.tkz { + // als LaTeX-kompatibler Code display::dump_latex_code(&route, &polys); } else { + // oder als animiertes SVG 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! { + // R*-Baum zur Beschleunigung der Routenabschnitt-Hindernis-Überprüfungen static ref RTREE: RwLock> = RwLock::new(RTree::new()); + // Cache für die Funktion none_intersect static ref COLLISIONS: RwLock> = RwLock::new(HashMap::new()); } /// Schneidet die Linie keines der Polygone? /// (Berührungen erlaubt) 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) { let end = line.start; line.start = line.end; line.end = end; } + // Cache laden 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) { return r; } + // ansonsten: + // Polygone finden, die die AABB der Linie schneiden let rtree = RTREE.read().unwrap(); let polys = rtree.locate_in_envelope_intersecting(&line.envelope()); + // Mittelpunkt der Linie bestimmen let mut middle = line.start; middle.x += line.dx() / 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 } if l.intersects(&line) { + // Ergebnis im Cache speichern collisions.insert(id, false); return false; } } // falls Mittelpunkt in Polygon: if p.euclidean_distance(&middle) == 0.0 { - // schneidet Polygon + // schneidet Polygon, Ergebnis im Cache speichern 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! + // (natürlich auch im Cache speichern) collisions.insert(id, true); true }