WIP starting the great Path refactor... changing the API, but not impl,

of pathfind
This commit is contained in:
Dustin Carlino 2018-11-03 14:07:15 -07:00
parent 58025c027d
commit 74c60709a3
4 changed files with 74 additions and 15 deletions

View File

@ -65,6 +65,9 @@ And what about modeling shared left-turn lanes?
- Are these even that important to model? Usually used for turning into - Are these even that important to model? Usually used for turning into
parking lots or driveways, which we're not modeling at all. parking lots or driveways, which we're not modeling at all.
One-way sidewalk lanes would NOT solve the turn-chains:
- think about crossing N, then W at a 4-way. legitimately doing two turns in sequence. and this is fine!
An alternative: An alternative:
- in sim, pathfinding, map model trace, etc layers only, using some new - in sim, pathfinding, map model trace, etc layers only, using some new
abstraction instead of raw lanes and implied turns abstraction instead of raw lanes and implied turns
@ -77,3 +80,16 @@ An alternative:
- this abstraction can just say whether to go backwards on a sidewalk or not - this abstraction can just say whether to go backwards on a sidewalk or not
- whether or not sidewalks later get split into 2 lanes, I think this - whether or not sidewalks later get split into 2 lanes, I think this
would be helpful. would be helpful.
- places to change...
- map model pathfinding.
- proper type, backed by VecDeque
- backrefs can store the intermediate piece often
- complication with not crossing a sidewalk? maybe that can be
deduped there, in one spot
- trace_route should move to become part of this Path type
- no more partly duped code btwn walking/driving
- Traversable::slice can probably also go away, or only get
called by this one place?
- sim layer no longer needs to pick turns
- walking code no longer needs to calculate contraflow itself!
- maybe should plumb start/end dist_along into pathfinding too?

View File

@ -117,8 +117,14 @@ pub fn verify_bus_routes(map: &Map, routes: Vec<BusRoute>, timer: &mut Timer) ->
{ {
let bs1 = map.get_bs(*stop1); let bs1 = map.get_bs(*stop1);
let bs2 = map.get_bs(*stop2); let bs2 = map.get_bs(*stop2);
if Pathfinder::shortest_distance(map, bs1.driving_lane, bs2.driving_lane, false) if Pathfinder::shortest_distance(
.is_none() map,
bs1.driving_lane,
bs1.dist_along,
bs2.driving_lane,
bs2.dist_along,
false,
).is_none()
{ {
warn!( warn!(
"Removing route {} since {:?} and {:?} aren't connected", "Removing route {} since {:?} and {:?} aren't connected",

View File

@ -400,9 +400,8 @@ impl Map {
// Sidewalks are bidirectional // Sidewalks are bidirectional
if lane.is_sidewalk() { if lane.is_sidewalk() {
for t in &self.get_i(lane.src_i).turns { for t in &self.get_i(lane.src_i).turns {
let turn = self.get_t(*t); if t.src == l {
if turn.src == l { turns.push(self.get_t(*t));
turns.push(turn);
} }
} }
} }

View File

@ -1,7 +1,31 @@
use dimensioned::si;
use geom::{Line, Pt2D}; use geom::{Line, Pt2D};
use ordered_float::NotNaN; use ordered_float::NotNaN;
use std::collections::{BinaryHeap, HashMap, VecDeque}; use std::collections::{BinaryHeap, HashMap, VecDeque};
use {LaneID, LaneType, Map}; use {LaneID, LaneType, Map, TurnID};
#[derive(Debug, PartialEq)]
pub enum PathStep {
// Original direction
Lane(LaneID),
// Sidewalks only!
ContraflowLane(LaneID),
Turn(TurnID),
}
pub struct Path {
// TODO way to encode start/end dist? I think it's needed for trace_route later...
// actually not start dist -- that really changes all the time
steps: VecDeque<PathStep>,
}
impl Path {
fn new(steps: Vec<PathStep>) -> Path {
Path {
steps: VecDeque::from(steps),
}
}
}
pub enum Pathfinder { pub enum Pathfinder {
ShortestDistance { goal_pt: Pt2D, is_bike: bool }, ShortestDistance { goal_pt: Pt2D, is_bike: bool },
@ -15,13 +39,16 @@ impl Pathfinder {
pub fn shortest_distance( pub fn shortest_distance(
map: &Map, map: &Map,
start: LaneID, start: LaneID,
start_dist: si::Meter<f64>,
end: LaneID, end: LaneID,
end_dist: si::Meter<f64>,
is_bike: bool, is_bike: bool,
) -> Option<VecDeque<LaneID>> { ) -> Option<Path> {
// TODO using first_pt here and in heuristic_dist is particularly bad for walking // TODO using first_pt here and in heuristic_dist is particularly bad for walking
// directions // directions
let goal_pt = map.get_l(end).first_pt(); let goal_pt = map.get_l(end).first_pt();
Pathfinder::ShortestDistance { goal_pt, is_bike }.pathfind(map, start, end) Pathfinder::ShortestDistance { goal_pt, is_bike }
.pathfind(map, start, start_dist, end, end_dist)
} }
fn expand(&self, map: &Map, current: LaneID) -> Vec<(LaneID, NotNaN<f64>)> { fn expand(&self, map: &Map, current: LaneID) -> Vec<(LaneID, NotNaN<f64>)> {
@ -61,10 +88,21 @@ impl Pathfinder {
} }
} }
fn pathfind(&self, map: &Map, start: LaneID, end: LaneID) -> Option<VecDeque<LaneID>> { fn pathfind(
&self,
map: &Map,
start: LaneID,
start_dist: si::Meter<f64>,
end: LaneID,
end_dist: si::Meter<f64>,
) -> Option<Path> {
assert_eq!(map.get_l(start).lane_type, map.get_l(end).lane_type); assert_eq!(map.get_l(start).lane_type, map.get_l(end).lane_type);
if start == end { if start == end {
return Some(VecDeque::from(vec![start])); if start_dist > end_dist {
assert_eq!(map.get_l(start).lane_type, LaneType::Sidewalk);
return Some(Path::new(vec![PathStep::ContraflowLane(start)]));
}
return Some(Path::new(vec![PathStep::Lane(start)]));
} }
// This should be deterministic, since cost ties would be broken by LaneID. // This should be deterministic, since cost ties would be broken by LaneID.
@ -78,14 +116,14 @@ impl Pathfinder {
// Found it, now produce the path // Found it, now produce the path
if current == end { if current == end {
let mut path: VecDeque<LaneID> = VecDeque::new(); let mut steps: VecDeque<PathStep> = VecDeque::new();
let mut lookup = current; let mut lookup = current;
loop { loop {
path.push_front(lookup); steps.push_front(PathStep::Lane(lookup));
if lookup == start { if lookup == start {
assert_eq!(path[0], start); assert_eq!(steps[0], PathStep::Lane(start));
assert_eq!(*path.back().unwrap(), end); assert_eq!(*steps.back().unwrap(), PathStep::Lane(end));
return Some(path); return Some(Path { steps });
} }
lookup = backrefs[&lookup]; lookup = backrefs[&lookup];
} }