mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 09:24:26 +03:00
Rip out all of the special code for pathfinding into/out of access-restricted zones.
There's a much simpler implementation, it transpires. #555, #574
This commit is contained in:
parent
b6c5ee38c2
commit
e6cf2d54bc
@ -8,13 +8,9 @@
|
|||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use enumset::EnumSet;
|
use enumset::EnumSet;
|
||||||
use petgraph::graphmap::DiGraphMap;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::pathfind::{driving_cost, walking_cost, WalkingNode};
|
use crate::{IntersectionID, Map, PathConstraints, RoadID};
|
||||||
use crate::{
|
|
||||||
IntersectionID, LaneID, Map, Path, PathConstraints, PathRequest, PathStep, RoadID, TurnID,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||||
pub struct AccessRestrictions {
|
pub struct AccessRestrictions {
|
||||||
@ -63,94 +59,6 @@ impl Zone {
|
|||||||
|
|
||||||
zones
|
zones
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run slower Dijkstra's within the interior of a private zone. Don't go outside the borders.
|
|
||||||
pub fn pathfind(&self, req: PathRequest, map: &Map) -> Option<Path> {
|
|
||||||
assert_ne!(req.constraints, PathConstraints::Pedestrian);
|
|
||||||
|
|
||||||
let mut graph: DiGraphMap<LaneID, TurnID> = DiGraphMap::new();
|
|
||||||
for r in &self.members {
|
|
||||||
for l in map.get_r(*r).all_lanes() {
|
|
||||||
if req.constraints.can_use(map.get_l(l), map) {
|
|
||||||
for turn in map.get_turns_for(l, req.constraints) {
|
|
||||||
if !self.borders.contains(&turn.id.parent) {
|
|
||||||
graph.add_edge(turn.id.src, turn.id.dst, turn.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (_, path) = petgraph::algo::astar(
|
|
||||||
&graph,
|
|
||||||
req.start.lane(),
|
|
||||||
|l| l == req.end.lane(),
|
|
||||||
|(_, _, turn)| {
|
|
||||||
driving_cost(
|
|
||||||
map.get_l(turn.src),
|
|
||||||
map.get_t(*turn),
|
|
||||||
req.constraints,
|
|
||||||
map.routing_params(),
|
|
||||||
map,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|_| 0.0,
|
|
||||||
)?;
|
|
||||||
let mut steps = Vec::new();
|
|
||||||
for pair in path.windows(2) {
|
|
||||||
steps.push(PathStep::Lane(pair[0]));
|
|
||||||
// We don't need to look for this turn in the map; we know it exists.
|
|
||||||
steps.push(PathStep::Turn(TurnID {
|
|
||||||
parent: map.get_l(pair[0]).dst_i,
|
|
||||||
src: pair[0],
|
|
||||||
dst: pair[1],
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
steps.push(PathStep::Lane(req.end.lane()));
|
|
||||||
assert_eq!(steps[0], PathStep::Lane(req.start.lane()));
|
|
||||||
Some(Path::new(map, steps, req, Vec::new()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO Not happy this works so differently
|
|
||||||
pub fn pathfind_walking(&self, req: PathRequest, map: &Map) -> Option<Vec<WalkingNode>> {
|
|
||||||
let mut graph: DiGraphMap<WalkingNode, usize> = DiGraphMap::new();
|
|
||||||
for r in &self.members {
|
|
||||||
for l in map.get_r(*r).all_lanes() {
|
|
||||||
let l = map.get_l(l);
|
|
||||||
if l.is_walkable() {
|
|
||||||
let cost = walking_cost(l.length());
|
|
||||||
let n1 = WalkingNode::SidewalkEndpoint(l.id, true);
|
|
||||||
let n2 = WalkingNode::SidewalkEndpoint(l.id, false);
|
|
||||||
graph.add_edge(n1, n2, cost);
|
|
||||||
graph.add_edge(n2, n1, cost);
|
|
||||||
|
|
||||||
for turn in map.get_turns_for(l.id, PathConstraints::Pedestrian) {
|
|
||||||
if self.members.contains(&map.get_l(turn.id.dst).parent) {
|
|
||||||
graph.add_edge(
|
|
||||||
WalkingNode::SidewalkEndpoint(l.id, l.dst_i == turn.id.parent),
|
|
||||||
WalkingNode::SidewalkEndpoint(
|
|
||||||
turn.id.dst,
|
|
||||||
map.get_l(turn.id.dst).dst_i == turn.id.parent,
|
|
||||||
),
|
|
||||||
walking_cost(turn.geom.length()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let closest_start = WalkingNode::closest(req.start, map);
|
|
||||||
let closest_end = WalkingNode::closest(req.end, map);
|
|
||||||
let (_, path) = petgraph::algo::astar(
|
|
||||||
&graph,
|
|
||||||
closest_start,
|
|
||||||
|end| end == closest_end,
|
|
||||||
|(_, _, cost)| *cost,
|
|
||||||
|_| 0,
|
|
||||||
)?;
|
|
||||||
Some(path)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn floodfill(map: &Map, start: RoadID) -> Zone {
|
fn floodfill(map: &Map, start: RoadID) -> Zone {
|
||||||
|
@ -167,13 +167,7 @@ fn make_input_graph(
|
|||||||
for l in map.all_lanes() {
|
for l in map.all_lanes() {
|
||||||
let from = nodes.get(Node::Lane(l.id));
|
let from = nodes.get(Node::Lane(l.id));
|
||||||
let mut any = false;
|
let mut any = false;
|
||||||
if constraints.can_use(l, map)
|
if constraints.can_use(l, map) {
|
||||||
&& map
|
|
||||||
.get_r(l.parent)
|
|
||||||
.access_restrictions
|
|
||||||
.allow_through_traffic
|
|
||||||
.contains(constraints)
|
|
||||||
{
|
|
||||||
let indices = uber_turn_entrances.get(l.id);
|
let indices = uber_turn_entrances.get(l.id);
|
||||||
if indices.is_empty() {
|
if indices.is_empty() {
|
||||||
for turn in map.get_turns_for(l.id, constraints) {
|
for turn in map.get_turns_for(l.id, constraints) {
|
||||||
|
@ -410,26 +410,6 @@ impl Path {
|
|||||||
&self.steps
|
&self.steps
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not for walking paths
|
|
||||||
fn append(&mut self, other: Path, map: &Map) {
|
|
||||||
assert!(self.currently_inside_ut.is_none());
|
|
||||||
assert!(other.currently_inside_ut.is_none());
|
|
||||||
let turn = match (*self.steps.back().unwrap(), other.steps[0]) {
|
|
||||||
(PathStep::Lane(src), PathStep::Lane(dst)) => TurnID {
|
|
||||||
parent: map.get_l(src).dst_i,
|
|
||||||
src,
|
|
||||||
dst,
|
|
||||||
},
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
self.steps.push_back(PathStep::Turn(turn));
|
|
||||||
// TODO Need to correct for the uncrossed start/end distance where we're gluing together
|
|
||||||
self.total_length += map.get_t(turn).geom.length();
|
|
||||||
self.steps.extend(other.steps);
|
|
||||||
self.total_length += other.total_length;
|
|
||||||
self.uber_turns.extend(other.uber_turns);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Estimate how long following the path will take in the best case, assuming no traffic or
|
/// Estimate how long following the path will take in the best case, assuming no traffic or
|
||||||
/// delay at intersections. To determine the speed along each step, the agent following their
|
/// delay at intersections. To determine the speed along each step, the agent following their
|
||||||
/// path and their optional max_speed must be specified.
|
/// path and their optional max_speed must be specified.
|
||||||
@ -491,7 +471,6 @@ impl PathConstraints {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Handle private zones here?
|
|
||||||
pub fn can_use(self, l: &Lane, map: &Map) -> bool {
|
pub fn can_use(self, l: &Lane, map: &Map) -> bool {
|
||||||
match self {
|
match self {
|
||||||
PathConstraints::Pedestrian => l.is_walkable(),
|
PathConstraints::Pedestrian => l.is_walkable(),
|
||||||
|
@ -5,11 +5,10 @@ use serde::{Deserialize, Serialize};
|
|||||||
use abstutil::Timer;
|
use abstutil::Timer;
|
||||||
|
|
||||||
use crate::pathfind::ch::ContractionHierarchyPathfinder;
|
use crate::pathfind::ch::ContractionHierarchyPathfinder;
|
||||||
|
use crate::pathfind::dijkstra;
|
||||||
use crate::pathfind::walking::{one_step_walking_path, walking_path_to_steps};
|
use crate::pathfind::walking::{one_step_walking_path, walking_path_to_steps};
|
||||||
use crate::pathfind::{dijkstra, WalkingNode};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BusRouteID, BusStopID, Intersection, LaneID, Map, Path, PathConstraints, PathRequest, Position,
|
BusRouteID, BusStopID, LaneID, Map, Path, PathConstraints, PathRequest, Position, RoutingParams,
|
||||||
RoutingParams, TurnID, Zone,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Most of the time, prefer using the faster contraction hierarchies. But sometimes, callers can
|
/// Most of the time, prefer using the faster contraction hierarchies. But sometimes, callers can
|
||||||
@ -22,14 +21,13 @@ pub enum Pathfinder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Pathfinder {
|
impl Pathfinder {
|
||||||
/// Finds a path from a start to an end for a certain type of agent. Handles requests that
|
/// Finds a path from a start to an end for a certain type of agent.
|
||||||
/// start or end inside access-restricted zones.
|
|
||||||
pub fn pathfind(&self, req: PathRequest, map: &Map) -> Option<Path> {
|
pub fn pathfind(&self, req: PathRequest, map: &Map) -> Option<Path> {
|
||||||
self.pathfind_with_params(req, map.routing_params(), map)
|
self.pathfind_with_params(req, map.routing_params(), map)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds a path from a start to an end for a certain type of agent. Handles requests that
|
/// Finds a path from a start to an end for a certain type of agent. May use custom routing
|
||||||
/// start or end inside access-restricted zones. May use custom routing parameters.
|
/// parameters.
|
||||||
pub fn pathfind_with_params(
|
pub fn pathfind_with_params(
|
||||||
&self,
|
&self,
|
||||||
req: PathRequest,
|
req: PathRequest,
|
||||||
@ -40,82 +38,30 @@ impl Pathfinder {
|
|||||||
return Some(one_step_walking_path(&req, map));
|
return Some(one_step_walking_path(&req, map));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we start or end in a private zone, have to stitch together a smaller path with a path
|
|
||||||
// through the main map.
|
|
||||||
let start_r = map.get_parent(req.start.lane());
|
|
||||||
let end_r = map.get_parent(req.end.lane());
|
|
||||||
|
|
||||||
match (start_r.get_zone(map), end_r.get_zone(map)) {
|
|
||||||
(Some(z1), Some(z2)) => {
|
|
||||||
if z1 == z2 {
|
|
||||||
if !z1
|
|
||||||
.restrictions
|
|
||||||
.allow_through_traffic
|
|
||||||
.contains(req.constraints)
|
|
||||||
{
|
|
||||||
if req.constraints == PathConstraints::Pedestrian {
|
|
||||||
let steps =
|
|
||||||
walking_path_to_steps(z1.pathfind_walking(req.clone(), map)?, map);
|
|
||||||
return Some(Path::new(map, steps, req, Vec::new()));
|
|
||||||
}
|
|
||||||
return z1.pathfind(req, map);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO Handle paths going between two different zones
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(Some(zone), None) => {
|
|
||||||
if !zone
|
|
||||||
.restrictions
|
|
||||||
.allow_through_traffic
|
|
||||||
.contains(req.constraints)
|
|
||||||
{
|
|
||||||
// Calculate the entire path using every possible border, then take the one
|
|
||||||
// with the least total distance.
|
|
||||||
// TODO This is slow and doesn't account for the mode-specific cost.
|
|
||||||
let mut paths = Vec::new();
|
|
||||||
for i in &zone.borders {
|
|
||||||
if let Some(result) =
|
|
||||||
self.pathfind_from_zone(map.get_i(*i), req.clone(), zone, map)
|
|
||||||
{
|
|
||||||
paths.push(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return paths.into_iter().min_by_key(|p| p.total_length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(None, Some(zone)) => {
|
|
||||||
if !zone
|
|
||||||
.restrictions
|
|
||||||
.allow_through_traffic
|
|
||||||
.contains(req.constraints)
|
|
||||||
{
|
|
||||||
// Calculate the entire path using every possible border, then take the one
|
|
||||||
// with the least total distance.
|
|
||||||
// TODO This is slow and doesn't account for the mode-specific cost.
|
|
||||||
let mut paths = Vec::new();
|
|
||||||
for i in &zone.borders {
|
|
||||||
if let Some(result) =
|
|
||||||
self.pathfind_to_zone(map.get_i(*i), req.clone(), zone, map)
|
|
||||||
{
|
|
||||||
paths.push(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return paths.into_iter().min_by_key(|p| p.total_length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(None, None) => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.constraints == PathConstraints::Pedestrian {
|
if req.constraints == PathConstraints::Pedestrian {
|
||||||
if req.start.lane() == req.end.lane() {
|
if req.start.lane() == req.end.lane() {
|
||||||
return Some(one_step_walking_path(&req, map));
|
return Some(one_step_walking_path(&req, map));
|
||||||
}
|
}
|
||||||
let steps = walking_path_to_steps(self.simple_walking_path(&req, map)?, map);
|
let nodes = match self {
|
||||||
|
Pathfinder::Dijkstra => dijkstra::simple_walking_path(&req, map)?,
|
||||||
|
Pathfinder::CH(ref p) => p.simple_walking_path(&req, map)?,
|
||||||
|
};
|
||||||
|
let steps = walking_path_to_steps(nodes, map);
|
||||||
return Some(Path::new(map, steps, req, Vec::new()));
|
return Some(Path::new(map, steps, req, Vec::new()));
|
||||||
}
|
}
|
||||||
self.simple_pathfind(&req, params, map)
|
|
||||||
|
if params != map.routing_params() {
|
||||||
|
// If the params differ from the ones baked into the map, the CHs won't match. This
|
||||||
|
// should only be happening from the debug UI; be very obnoxious if we start calling it
|
||||||
|
// from the simulation or something else.
|
||||||
|
warn!("Pathfinding slowly for {} with custom params", req);
|
||||||
|
return dijkstra::simple_pathfind(&req, params, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Pathfinder::Dijkstra => dijkstra::simple_pathfind(&req, params, map),
|
||||||
|
Pathfinder::CH(ref p) => p.simple_pathfind(&req, map),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pathfind_avoiding_lanes(
|
pub fn pathfind_avoiding_lanes(
|
||||||
@ -147,193 +93,4 @@ impl Pathfinder {
|
|||||||
Pathfinder::CH(ref mut p) => p.apply_edits(map, timer),
|
Pathfinder::CH(ref mut p) => p.apply_edits(map, timer),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doesn't handle zones or pedestrians
|
|
||||||
fn simple_pathfind(
|
|
||||||
&self,
|
|
||||||
req: &PathRequest,
|
|
||||||
params: &RoutingParams,
|
|
||||||
map: &Map,
|
|
||||||
) -> Option<Path> {
|
|
||||||
if params != map.routing_params() {
|
|
||||||
// If the params differ from the ones baked into the map, the CHs won't match. This
|
|
||||||
// should only be happening from the debug UI; be very obnoxious if we start calling it
|
|
||||||
// from the simulation or something else.
|
|
||||||
warn!("Pathfinding slowly for {} with custom params", req);
|
|
||||||
return dijkstra::simple_pathfind(req, params, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
match self {
|
|
||||||
Pathfinder::Dijkstra => dijkstra::simple_pathfind(req, params, map),
|
|
||||||
Pathfinder::CH(ref p) => p.simple_pathfind(req, map),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn simple_walking_path(&self, req: &PathRequest, map: &Map) -> Option<Vec<WalkingNode>> {
|
|
||||||
match self {
|
|
||||||
Pathfinder::Dijkstra => dijkstra::simple_walking_path(req, map),
|
|
||||||
Pathfinder::CH(ref p) => p.simple_walking_path(req, map),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pathfind_from_zone(
|
|
||||||
&self,
|
|
||||||
i: &Intersection,
|
|
||||||
mut req: PathRequest,
|
|
||||||
zone: &Zone,
|
|
||||||
map: &Map,
|
|
||||||
) -> Option<Path> {
|
|
||||||
// Because sidewalks aren't all immediately linked, insist on a (src, dst) combo that
|
|
||||||
// are actually connected by a turn.
|
|
||||||
let src_choices = i
|
|
||||||
.get_incoming_lanes(map, req.constraints)
|
|
||||||
.into_iter()
|
|
||||||
.filter(|l| zone.members.contains(&map.get_l(*l).parent))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let dst_choices = i
|
|
||||||
.get_outgoing_lanes(map, req.constraints)
|
|
||||||
.into_iter()
|
|
||||||
.filter(|l| !zone.members.contains(&map.get_l(*l).parent))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let (src, dst) = {
|
|
||||||
let mut result = None;
|
|
||||||
'OUTER: for l1 in src_choices {
|
|
||||||
for l2 in &dst_choices {
|
|
||||||
if l1 != *l2
|
|
||||||
&& map
|
|
||||||
.maybe_get_t(TurnID {
|
|
||||||
parent: i.id,
|
|
||||||
src: l1,
|
|
||||||
dst: *l2,
|
|
||||||
})
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
result = Some((l1, *l2));
|
|
||||||
break 'OUTER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result?
|
|
||||||
};
|
|
||||||
|
|
||||||
let interior_req = PathRequest {
|
|
||||||
start: req.start,
|
|
||||||
end: if map.get_l(src).dst_i == i.id {
|
|
||||||
Position::end(src, map)
|
|
||||||
} else {
|
|
||||||
Position::start(src)
|
|
||||||
},
|
|
||||||
constraints: req.constraints,
|
|
||||||
};
|
|
||||||
let orig_req = req.clone();
|
|
||||||
req.start = if map.get_l(dst).src_i == i.id {
|
|
||||||
Position::start(dst)
|
|
||||||
} else {
|
|
||||||
Position::end(dst, map)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let PathConstraints::Pedestrian = req.constraints {
|
|
||||||
let mut interior_path = zone.pathfind_walking(interior_req, map)?;
|
|
||||||
let main_path = if req.start.lane() == req.end.lane() {
|
|
||||||
let mut one_step = vec![
|
|
||||||
WalkingNode::closest(req.start, map),
|
|
||||||
WalkingNode::closest(req.end, map),
|
|
||||||
];
|
|
||||||
one_step.dedup();
|
|
||||||
one_step
|
|
||||||
} else {
|
|
||||||
self.simple_walking_path(&req, map)?
|
|
||||||
};
|
|
||||||
interior_path.extend(main_path);
|
|
||||||
let steps = walking_path_to_steps(interior_path, map);
|
|
||||||
return Some(Path::new(map, steps, orig_req, Vec::new()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut interior_path = zone.pathfind(interior_req, map)?;
|
|
||||||
let main_path = self.simple_pathfind(&req, map.routing_params(), map)?;
|
|
||||||
interior_path.append(main_path, map);
|
|
||||||
interior_path.orig_req = orig_req;
|
|
||||||
Some(interior_path)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pathfind_to_zone(
|
|
||||||
&self,
|
|
||||||
i: &Intersection,
|
|
||||||
mut req: PathRequest,
|
|
||||||
zone: &Zone,
|
|
||||||
map: &Map,
|
|
||||||
) -> Option<Path> {
|
|
||||||
// Because sidewalks aren't all immediately linked, insist on a (src, dst) combo that
|
|
||||||
// are actually connected by a turn.
|
|
||||||
let src_choices = i
|
|
||||||
.get_incoming_lanes(map, req.constraints)
|
|
||||||
.into_iter()
|
|
||||||
.filter(|l| !zone.members.contains(&map.get_l(*l).parent))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let dst_choices = i
|
|
||||||
.get_outgoing_lanes(map, req.constraints)
|
|
||||||
.into_iter()
|
|
||||||
.filter(|l| zone.members.contains(&map.get_l(*l).parent))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let (src, dst) = {
|
|
||||||
let mut result = None;
|
|
||||||
'OUTER: for l1 in src_choices {
|
|
||||||
for l2 in &dst_choices {
|
|
||||||
if l1 != *l2
|
|
||||||
&& map
|
|
||||||
.maybe_get_t(TurnID {
|
|
||||||
parent: i.id,
|
|
||||||
src: l1,
|
|
||||||
dst: *l2,
|
|
||||||
})
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
result = Some((l1, *l2));
|
|
||||||
break 'OUTER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result?
|
|
||||||
};
|
|
||||||
|
|
||||||
let interior_req = PathRequest {
|
|
||||||
start: if map.get_l(dst).src_i == i.id {
|
|
||||||
Position::start(dst)
|
|
||||||
} else {
|
|
||||||
Position::end(dst, map)
|
|
||||||
},
|
|
||||||
end: req.end,
|
|
||||||
constraints: req.constraints,
|
|
||||||
};
|
|
||||||
let orig_req = req.clone();
|
|
||||||
req.end = if map.get_l(src).dst_i == i.id {
|
|
||||||
Position::end(src, map)
|
|
||||||
} else {
|
|
||||||
Position::start(src)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let PathConstraints::Pedestrian = req.constraints {
|
|
||||||
let interior_path = zone.pathfind_walking(interior_req, map)?;
|
|
||||||
let mut main_path = if req.start.lane() == req.end.lane() {
|
|
||||||
let mut one_step = vec![
|
|
||||||
WalkingNode::closest(req.start, map),
|
|
||||||
WalkingNode::closest(req.end, map),
|
|
||||||
];
|
|
||||||
one_step.dedup();
|
|
||||||
one_step
|
|
||||||
} else {
|
|
||||||
self.simple_walking_path(&req, map)?
|
|
||||||
};
|
|
||||||
|
|
||||||
main_path.extend(interior_path);
|
|
||||||
let steps = walking_path_to_steps(main_path, map);
|
|
||||||
return Some(Path::new(map, steps, orig_req, Vec::new()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let interior_path = zone.pathfind(interior_req, map)?;
|
|
||||||
let mut main_path = self.simple_pathfind(&req, map.routing_params(), map)?;
|
|
||||||
main_path.append(interior_path, map);
|
|
||||||
main_path.orig_req = orig_req;
|
|
||||||
Some(main_path)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -232,13 +232,7 @@ fn make_input_graph(
|
|||||||
let mut input_graph = InputGraph::new();
|
let mut input_graph = InputGraph::new();
|
||||||
|
|
||||||
for l in map.all_lanes() {
|
for l in map.all_lanes() {
|
||||||
if l.is_walkable()
|
if l.is_walkable() {
|
||||||
&& map
|
|
||||||
.get_r(l.parent)
|
|
||||||
.access_restrictions
|
|
||||||
.allow_through_traffic
|
|
||||||
.contains(PathConstraints::Pedestrian)
|
|
||||||
{
|
|
||||||
let mut cost = walking_cost(l.length());
|
let mut cost = walking_cost(l.length());
|
||||||
// TODO Tune this penalty, along with many others.
|
// TODO Tune this penalty, along with many others.
|
||||||
if l.is_shoulder() {
|
if l.is_shoulder() {
|
||||||
|
Loading…
Reference in New Issue
Block a user