mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 23:43:25 +03:00
WIP starting the great Path refactor... changing the API, but not impl,
of pathfind
This commit is contained in:
parent
58025c027d
commit
74c60709a3
@ -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?
|
||||||
|
@ -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",
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user