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
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:
- in sim, pathfinding, map model trace, etc layers only, using some new
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
- whether or not sidewalks later get split into 2 lanes, I think this
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 bs2 = map.get_bs(*stop2);
if Pathfinder::shortest_distance(map, bs1.driving_lane, bs2.driving_lane, false)
.is_none()
if Pathfinder::shortest_distance(
map,
bs1.driving_lane,
bs1.dist_along,
bs2.driving_lane,
bs2.dist_along,
false,
).is_none()
{
warn!(
"Removing route {} since {:?} and {:?} aren't connected",

View File

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

View File

@ -1,7 +1,31 @@
use dimensioned::si;
use geom::{Line, Pt2D};
use ordered_float::NotNaN;
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 {
ShortestDistance { goal_pt: Pt2D, is_bike: bool },
@ -15,13 +39,16 @@ impl Pathfinder {
pub fn shortest_distance(
map: &Map,
start: LaneID,
start_dist: si::Meter<f64>,
end: LaneID,
end_dist: si::Meter<f64>,
is_bike: bool,
) -> Option<VecDeque<LaneID>> {
) -> Option<Path> {
// TODO using first_pt here and in heuristic_dist is particularly bad for walking
// directions
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>)> {
@ -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);
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.
@ -78,14 +116,14 @@ impl Pathfinder {
// Found it, now produce the path
if current == end {
let mut path: VecDeque<LaneID> = VecDeque::new();
let mut steps: VecDeque<PathStep> = VecDeque::new();
let mut lookup = current;
loop {
path.push_front(lookup);
steps.push_front(PathStep::Lane(lookup));
if lookup == start {
assert_eq!(path[0], start);
assert_eq!(*path.back().unwrap(), end);
return Some(path);
assert_eq!(steps[0], PathStep::Lane(start));
assert_eq!(*steps.back().unwrap(), PathStep::Lane(end));
return Some(Path { steps });
}
lookup = backrefs[&lookup];
}