mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-29 04:35:51 +03:00
dramatically slash the one-time preparation time for the 3 VehiclePathfinders by using the node ordering from one for the other two. this actually also exposed a bug that would eventually muck with recalculating after edits (node IDs depending on the original state of the map)
This commit is contained in:
parent
7a49c585cf
commit
91cc74a30c
@ -17,27 +17,28 @@ pub struct VehiclePathfinder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VehiclePathfinder {
|
impl VehiclePathfinder {
|
||||||
pub fn new(map: &Map, lane_types: Vec<LaneType>) -> VehiclePathfinder {
|
pub fn new(
|
||||||
let mut input_graph = InputGraph::new();
|
map: &Map,
|
||||||
|
lane_types: Vec<LaneType>,
|
||||||
|
seed: Option<&VehiclePathfinder>,
|
||||||
|
) -> VehiclePathfinder {
|
||||||
|
// Insert every lane as a node. Even if the lane type is wrong now, it might change later,
|
||||||
|
// and we want the node in the graph. Do this first, so the IDs of all the nodes doesn't
|
||||||
|
// depend on lane types and turns and such.
|
||||||
let mut nodes = NodeMap::new();
|
let mut nodes = NodeMap::new();
|
||||||
|
|
||||||
for l in map.all_lanes() {
|
for l in map.all_lanes() {
|
||||||
// Insert every lane as a node. Even if the lane type is wrong now, it might change
|
nodes.get_or_insert(l.id);
|
||||||
// later, and we want the node in the graph.
|
|
||||||
let from = nodes.get_or_insert(l.id);
|
|
||||||
|
|
||||||
for (turn, next) in map.get_next_turns_and_lanes(l.id, l.dst_i).into_iter() {
|
|
||||||
if !map.is_turn_allowed(turn.id) || !lane_types.contains(&next.lane_type) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// TODO Speed limit or some other cost
|
|
||||||
let length = l.length() + turn.geom.length();
|
|
||||||
let length_cm = (length.inner_meters() * 100.0).round() as usize;
|
|
||||||
input_graph.add_edge(from, nodes.get_or_insert(next.id), length_cm);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
input_graph.freeze();
|
let input_graph = make_input_graph(map, &nodes, &lane_types);
|
||||||
let graph = fast_paths::prepare(&input_graph);
|
|
||||||
|
// All VehiclePathfinders have the same nodes (lanes), so if we're not the first being
|
||||||
|
// built, seed from the node ordering.
|
||||||
|
let graph = if let Some(seed) = seed {
|
||||||
|
let node_ordering = seed.graph.get_node_ordering();
|
||||||
|
fast_paths::prepare_with_order(&input_graph, &node_ordering).unwrap()
|
||||||
|
} else {
|
||||||
|
fast_paths::prepare(&input_graph)
|
||||||
|
};
|
||||||
|
|
||||||
VehiclePathfinder {
|
VehiclePathfinder {
|
||||||
graph,
|
graph,
|
||||||
@ -77,21 +78,37 @@ impl VehiclePathfinder {
|
|||||||
// ordering.
|
// ordering.
|
||||||
// TODO Make sure the result of this is deterministic and equivalent to computing from
|
// TODO Make sure the result of this is deterministic and equivalent to computing from
|
||||||
// scratch.
|
// scratch.
|
||||||
let mut input_graph = InputGraph::new();
|
let input_graph = make_input_graph(map, &self.nodes, &self.lane_types);
|
||||||
|
|
||||||
for l in map.all_lanes() {
|
|
||||||
for (turn, next) in map.get_next_turns_and_lanes(l.id, l.dst_i).into_iter() {
|
|
||||||
if !map.is_turn_allowed(turn.id) || !self.lane_types.contains(&next.lane_type) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// TODO Speed limit or some other cost
|
|
||||||
let length = l.length() + turn.geom.length();
|
|
||||||
let length_cm = (length.inner_meters() * 100.0).round() as usize;
|
|
||||||
input_graph.add_edge(self.nodes.get(l.id), self.nodes.get(next.id), length_cm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
input_graph.freeze();
|
|
||||||
let node_ordering = self.graph.get_node_ordering();
|
let node_ordering = self.graph.get_node_ordering();
|
||||||
self.graph = fast_paths::prepare_with_order(&input_graph, &node_ordering).unwrap();
|
self.graph = fast_paths::prepare_with_order(&input_graph, &node_ordering).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_input_graph(map: &Map, nodes: &NodeMap<LaneID>, lane_types: &Vec<LaneType>) -> InputGraph {
|
||||||
|
let mut input_graph = InputGraph::new();
|
||||||
|
let num_lanes = map.all_lanes().len();
|
||||||
|
for l in map.all_lanes() {
|
||||||
|
let from = nodes.get(l.id);
|
||||||
|
let mut any = false;
|
||||||
|
for (turn, next) in map.get_next_turns_and_lanes(l.id, l.dst_i).into_iter() {
|
||||||
|
if !map.is_turn_allowed(turn.id) || !lane_types.contains(&next.lane_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
any = true;
|
||||||
|
// TODO Speed limit or some other cost
|
||||||
|
let length = l.length() + turn.geom.length();
|
||||||
|
let length_cm = (length.inner_meters() * 100.0).round() as usize;
|
||||||
|
input_graph.add_edge(from, nodes.get(next.id), length_cm);
|
||||||
|
}
|
||||||
|
// The nodes in the graph MUST exactly be all of the lanes, so we can reuse node
|
||||||
|
// ordering later. If the last lane doesn't have any edges, then this won't work. So
|
||||||
|
// pretend like it points to some arbitrary other node. Since no paths will start from
|
||||||
|
// this unused node, this won't affect results.
|
||||||
|
// TODO Upstream a method in InputGraph to do this more clearly.
|
||||||
|
if !any && l.id.0 == num_lanes - 1 {
|
||||||
|
input_graph.add_edge(from, nodes.get(LaneID(0)), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input_graph.freeze();
|
||||||
|
input_graph
|
||||||
|
}
|
||||||
|
@ -329,15 +329,23 @@ pub struct Pathfinder {
|
|||||||
impl Pathfinder {
|
impl Pathfinder {
|
||||||
pub fn new_without_transit(map: &Map, timer: &mut Timer) -> Pathfinder {
|
pub fn new_without_transit(map: &Map, timer: &mut Timer) -> Pathfinder {
|
||||||
timer.start("prepare pathfinding for cars");
|
timer.start("prepare pathfinding for cars");
|
||||||
let car_graph = VehiclePathfinder::new(map, vec![LaneType::Driving]);
|
let car_graph = VehiclePathfinder::new(map, vec![LaneType::Driving], None);
|
||||||
timer.stop("prepare pathfinding for cars");
|
timer.stop("prepare pathfinding for cars");
|
||||||
|
|
||||||
timer.start("prepare pathfinding for bikes");
|
timer.start("prepare pathfinding for bikes");
|
||||||
let bike_graph = VehiclePathfinder::new(map, vec![LaneType::Driving, LaneType::Biking]);
|
let bike_graph = VehiclePathfinder::new(
|
||||||
|
map,
|
||||||
|
vec![LaneType::Driving, LaneType::Biking],
|
||||||
|
Some(&car_graph),
|
||||||
|
);
|
||||||
timer.stop("prepare pathfinding for bikes");
|
timer.stop("prepare pathfinding for bikes");
|
||||||
|
|
||||||
timer.start("prepare pathfinding for buses");
|
timer.start("prepare pathfinding for buses");
|
||||||
let bus_graph = VehiclePathfinder::new(map, vec![LaneType::Driving, LaneType::Bus]);
|
let bus_graph = VehiclePathfinder::new(
|
||||||
|
map,
|
||||||
|
vec![LaneType::Driving, LaneType::Bus],
|
||||||
|
Some(&car_graph),
|
||||||
|
);
|
||||||
timer.stop("prepare pathfinding for buses");
|
timer.stop("prepare pathfinding for buses");
|
||||||
|
|
||||||
timer.start("prepare pathfinding for pedestrians");
|
timer.start("prepare pathfinding for pedestrians");
|
||||||
|
Loading…
Reference in New Issue
Block a user