mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 08:24:15 +03:00
make peds use front paths for parking lots too
This commit is contained in:
parent
a643f039ad
commit
65b500509e
@ -374,9 +374,9 @@ data/system/maps/montlake.bin,d58d14b9fbae8cfdf6c547fe140ff3fe,https://www.dropb
|
|||||||
data/system/maps/mt_baker.bin,09dd0d4220e1ebbed4fc730ed2081933,https://www.dropbox.com/s/cetje663p04cbgp/mt_baker.bin.zip?dl=0
|
data/system/maps/mt_baker.bin,09dd0d4220e1ebbed4fc730ed2081933,https://www.dropbox.com/s/cetje663p04cbgp/mt_baker.bin.zip?dl=0
|
||||||
data/system/maps/udistrict.bin,4de690facca9297f148396f3f09c3a6a,https://www.dropbox.com/s/zqt2je8fadssz5j/udistrict.bin.zip?dl=0
|
data/system/maps/udistrict.bin,4de690facca9297f148396f3f09c3a6a,https://www.dropbox.com/s/zqt2je8fadssz5j/udistrict.bin.zip?dl=0
|
||||||
data/system/maps/west_seattle.bin,867b16afdf12c484d680bfbc73cbd919,https://www.dropbox.com/s/5pp1ik9l40yj3wh/west_seattle.bin.zip?dl=0
|
data/system/maps/west_seattle.bin,867b16afdf12c484d680bfbc73cbd919,https://www.dropbox.com/s/5pp1ik9l40yj3wh/west_seattle.bin.zip?dl=0
|
||||||
data/system/prebaked_results/lakeslice/weekday.bin,cbd73a7a14a8406a99cafac4e2eedf5b,https://www.dropbox.com/s/1c1sohvy50263wg/weekday.bin.zip?dl=0
|
data/system/prebaked_results/lakeslice/weekday.bin,5402db739bd44a5f763f64fa14887733,https://www.dropbox.com/s/1c1sohvy50263wg/weekday.bin.zip?dl=0
|
||||||
data/system/prebaked_results/montlake/car vs bike contention.bin,ac46a6b81a65431209075a7de5ed9227,https://www.dropbox.com/s/jefg0ikjy9dsrdd/car%20vs%20bike%20contention.bin.zip?dl=0
|
data/system/prebaked_results/montlake/car vs bike contention.bin,ac46a6b81a65431209075a7de5ed9227,https://www.dropbox.com/s/jefg0ikjy9dsrdd/car%20vs%20bike%20contention.bin.zip?dl=0
|
||||||
data/system/prebaked_results/montlake/weekday.bin,cd953900d32389809fb2dda206789528,https://www.dropbox.com/s/1aq7n9ow8tfqb5d/weekday.bin.zip?dl=0
|
data/system/prebaked_results/montlake/weekday.bin,0a06da39f1f76199744d27b137bc1bc0,https://www.dropbox.com/s/1aq7n9ow8tfqb5d/weekday.bin.zip?dl=0
|
||||||
data/system/scenarios/ballard/weekday.bin,60d3eb1cdb8672e2d29cf3acf23ccabe,https://www.dropbox.com/s/67hys1v7m7oe979/weekday.bin.zip?dl=0
|
data/system/scenarios/ballard/weekday.bin,60d3eb1cdb8672e2d29cf3acf23ccabe,https://www.dropbox.com/s/67hys1v7m7oe979/weekday.bin.zip?dl=0
|
||||||
data/system/scenarios/downtown/weekday.bin,8821147124da650f975483ed1e5bbb69,https://www.dropbox.com/s/pstvu4p7xj3gaoi/weekday.bin.zip?dl=0
|
data/system/scenarios/downtown/weekday.bin,8821147124da650f975483ed1e5bbb69,https://www.dropbox.com/s/pstvu4p7xj3gaoi/weekday.bin.zip?dl=0
|
||||||
data/system/scenarios/huge_seattle/weekday.bin,31bfc23f39bb54bef939119f6cfbd2e2,https://www.dropbox.com/s/u3pmsshwnf13g83/weekday.bin.zip?dl=0
|
data/system/scenarios/huge_seattle/weekday.bin,31bfc23f39bb54bef939119f6cfbd2e2,https://www.dropbox.com/s/u3pmsshwnf13g83/weekday.bin.zip?dl=0
|
||||||
|
@ -212,12 +212,17 @@ impl DrawPedCrowd {
|
|||||||
map.right_shift(pl_slice, SIDEWALK_THICKNESS / 4.0).unwrap()
|
map.right_shift(pl_slice, SIDEWALK_THICKNESS / 4.0).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PedCrowdLocation::FrontPath(b) => map
|
PedCrowdLocation::BldgFrontPath(b) => map
|
||||||
.get_b(b)
|
.get_b(b)
|
||||||
.front_path
|
.front_path
|
||||||
.line
|
.line
|
||||||
.to_polyline()
|
.to_polyline()
|
||||||
.exact_slice(input.low, input.high),
|
.exact_slice(input.low, input.high),
|
||||||
|
PedCrowdLocation::LotFrontPath(pl) => map
|
||||||
|
.get_pl(pl)
|
||||||
|
.sidewalk_line
|
||||||
|
.to_polyline()
|
||||||
|
.exact_slice(input.low, input.high),
|
||||||
};
|
};
|
||||||
let blob = pl_shifted.make_polygons(SIDEWALK_THICKNESS / 2.0);
|
let blob = pl_shifted.make_polygons(SIDEWALK_THICKNESS / 2.0);
|
||||||
let mut batch = GeomBatch::new();
|
let mut batch = GeomBatch::new();
|
||||||
@ -235,7 +240,8 @@ impl DrawPedCrowd {
|
|||||||
blob,
|
blob,
|
||||||
zorder: match input.location {
|
zorder: match input.location {
|
||||||
PedCrowdLocation::Sidewalk(on, _) => on.get_zorder(map),
|
PedCrowdLocation::Sidewalk(on, _) => on.get_zorder(map),
|
||||||
PedCrowdLocation::FrontPath(_) => 0,
|
PedCrowdLocation::BldgFrontPath(_) => 0,
|
||||||
|
PedCrowdLocation::LotFrontPath(_) => 0,
|
||||||
},
|
},
|
||||||
draw_default: prerender.upload(batch),
|
draw_default: prerender.upload(batch),
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,12 @@ use std::fmt;
|
|||||||
// TODO For now, ignore the mapped roads linking things and just use the same driveway approach
|
// TODO For now, ignore the mapped roads linking things and just use the same driveway approach
|
||||||
// that buildings use.
|
// that buildings use.
|
||||||
|
|
||||||
|
// TODO Nits:
|
||||||
|
// - handle relations with individual slots, like https://www.openstreetmap.org/relation/2580595?
|
||||||
|
// - Northlake: onstreet or a lot?
|
||||||
|
// - E1 at UW filtered out
|
||||||
|
// - aisle clipping isnt perfect (23rd and rainier, pepsi)
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct ParkingLotID(pub usize);
|
pub struct ParkingLotID(pub usize);
|
||||||
|
|
||||||
|
@ -6,7 +6,9 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use abstutil::{deserialize_multimap, serialize_multimap, MultiMap};
|
use abstutil::{deserialize_multimap, serialize_multimap, MultiMap};
|
||||||
use geom::{Distance, Duration, Line, PolyLine, Speed, Time};
|
use geom::{Distance, Duration, Line, PolyLine, Speed, Time};
|
||||||
use map_model::{BuildingID, BusRouteID, Map, Path, PathStep, Traversable, SIDEWALK_THICKNESS};
|
use map_model::{
|
||||||
|
BuildingID, BusRouteID, Map, ParkingLotID, Path, PathStep, Traversable, SIDEWALK_THICKNESS,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
@ -73,6 +75,10 @@ impl WalkingSimState {
|
|||||||
TimeInterval::new(now, now + map.get_b(b).front_path.line.length() / ped.speed),
|
TimeInterval::new(now, now + map.get_b(b).front_path.line.length() / ped.speed),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
SidewalkPOI::ParkingSpot(ParkingSpot::Lot(pl, _)) => PedState::LeavingParkingLot(
|
||||||
|
pl,
|
||||||
|
TimeInterval::new(now, now + map.get_pl(pl).sidewalk_line.length() / ped.speed),
|
||||||
|
),
|
||||||
SidewalkPOI::BikeRack(driving_pos) => PedState::FinishingBiking(
|
SidewalkPOI::BikeRack(driving_pos) => PedState::FinishingBiking(
|
||||||
params.start.clone(),
|
params.start.clone(),
|
||||||
Line::new(driving_pos.pt(map), params.start.sidewalk_pos.pt(map)),
|
Line::new(driving_pos.pt(map), params.start.sidewalk_pos.pt(map)),
|
||||||
@ -122,18 +128,30 @@ impl WalkingSimState {
|
|||||||
if ped.path.is_last_step() {
|
if ped.path.is_last_step() {
|
||||||
match ped.goal.connection {
|
match ped.goal.connection {
|
||||||
SidewalkPOI::ParkingSpot(spot) => {
|
SidewalkPOI::ParkingSpot(spot) => {
|
||||||
self.peds_per_traversable
|
if let ParkingSpot::Lot(pl, _) = spot {
|
||||||
.remove(ped.path.current_step().as_traversable(), ped.id);
|
ped.state = PedState::EnteringParkingLot(
|
||||||
trips.ped_reached_parking_spot(
|
pl,
|
||||||
now,
|
TimeInterval::new(
|
||||||
ped.id,
|
now,
|
||||||
spot,
|
now + map.get_pl(pl).sidewalk_line.length() / ped.speed,
|
||||||
ped.total_blocked_time,
|
),
|
||||||
map,
|
);
|
||||||
parking,
|
scheduler
|
||||||
scheduler,
|
.push(ped.state.get_end_time(), Command::UpdatePed(ped.id));
|
||||||
);
|
} else {
|
||||||
self.peds.remove(&id);
|
self.peds_per_traversable
|
||||||
|
.remove(ped.path.current_step().as_traversable(), ped.id);
|
||||||
|
trips.ped_reached_parking_spot(
|
||||||
|
now,
|
||||||
|
ped.id,
|
||||||
|
spot,
|
||||||
|
ped.total_blocked_time,
|
||||||
|
map,
|
||||||
|
parking,
|
||||||
|
scheduler,
|
||||||
|
);
|
||||||
|
self.peds.remove(&id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SidewalkPOI::Building(b) => {
|
SidewalkPOI::Building(b) => {
|
||||||
ped.state = PedState::EnteringBuilding(
|
ped.state = PedState::EnteringBuilding(
|
||||||
@ -247,6 +265,27 @@ impl WalkingSimState {
|
|||||||
);
|
);
|
||||||
self.peds.remove(&id);
|
self.peds.remove(&id);
|
||||||
}
|
}
|
||||||
|
PedState::LeavingParkingLot(pl, _) => {
|
||||||
|
ped.state = ped.crossing_state(map.get_pl(pl).sidewalk_pos.dist_along(), now, map);
|
||||||
|
scheduler.push(ped.state.get_end_time(), Command::UpdatePed(ped.id));
|
||||||
|
}
|
||||||
|
PedState::EnteringParkingLot(_, _) => {
|
||||||
|
self.peds_per_traversable
|
||||||
|
.remove(ped.path.current_step().as_traversable(), ped.id);
|
||||||
|
trips.ped_reached_parking_spot(
|
||||||
|
now,
|
||||||
|
ped.id,
|
||||||
|
match ped.goal.connection {
|
||||||
|
SidewalkPOI::ParkingSpot(spot) => spot,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
ped.total_blocked_time,
|
||||||
|
map,
|
||||||
|
parking,
|
||||||
|
scheduler,
|
||||||
|
);
|
||||||
|
self.peds.remove(&id);
|
||||||
|
}
|
||||||
PedState::StartingToBike(ref spot, _, _) => {
|
PedState::StartingToBike(ref spot, _, _) => {
|
||||||
self.peds_per_traversable
|
self.peds_per_traversable
|
||||||
.remove(ped.path.current_step().as_traversable(), ped.id);
|
.remove(ped.path.current_step().as_traversable(), ped.id);
|
||||||
@ -364,10 +403,11 @@ impl WalkingSimState {
|
|||||||
on: Traversable,
|
on: Traversable,
|
||||||
map: &Map,
|
map: &Map,
|
||||||
) -> (Vec<DrawPedestrianInput>, Vec<DrawPedCrowdInput>) {
|
) -> (Vec<DrawPedestrianInput>, Vec<DrawPedCrowdInput>) {
|
||||||
// Classify into direction-based groups or by building front path.
|
// Classify into direction-based groups or by building/parking lot front path.
|
||||||
let mut forwards: Vec<(PedestrianID, Distance)> = Vec::new();
|
let mut forwards: Vec<(PedestrianID, Distance)> = Vec::new();
|
||||||
let mut backwards: Vec<(PedestrianID, Distance)> = Vec::new();
|
let mut backwards: Vec<(PedestrianID, Distance)> = Vec::new();
|
||||||
let mut front_path: MultiMap<BuildingID, (PedestrianID, Distance)> = MultiMap::new();
|
let mut bldg_front_path: MultiMap<BuildingID, (PedestrianID, Distance)> = MultiMap::new();
|
||||||
|
let mut lot_front_path: MultiMap<ParkingLotID, (PedestrianID, Distance)> = MultiMap::new();
|
||||||
|
|
||||||
for id in self.peds_per_traversable.get(on) {
|
for id in self.peds_per_traversable.get(on) {
|
||||||
let ped = &self.peds[id];
|
let ped = &self.peds[id];
|
||||||
@ -390,11 +430,19 @@ impl WalkingSimState {
|
|||||||
}
|
}
|
||||||
PedState::LeavingBuilding(b, ref int) => {
|
PedState::LeavingBuilding(b, ref int) => {
|
||||||
let len = map.get_b(b).front_path.line.length();
|
let len = map.get_b(b).front_path.line.length();
|
||||||
front_path.insert(b, (*id, int.percent(now) * len));
|
bldg_front_path.insert(b, (*id, int.percent(now) * len));
|
||||||
}
|
}
|
||||||
PedState::EnteringBuilding(b, ref int) => {
|
PedState::EnteringBuilding(b, ref int) => {
|
||||||
let len = map.get_b(b).front_path.line.length();
|
let len = map.get_b(b).front_path.line.length();
|
||||||
front_path.insert(b, (*id, (1.0 - int.percent(now)) * len));
|
bldg_front_path.insert(b, (*id, (1.0 - int.percent(now)) * len));
|
||||||
|
}
|
||||||
|
PedState::LeavingParkingLot(pl, ref int) => {
|
||||||
|
let len = map.get_pl(pl).sidewalk_line.length();
|
||||||
|
lot_front_path.insert(pl, (*id, int.percent(now) * len));
|
||||||
|
}
|
||||||
|
PedState::EnteringParkingLot(pl, ref int) => {
|
||||||
|
let len = map.get_pl(pl).sidewalk_line.length();
|
||||||
|
lot_front_path.insert(pl, (*id, (1.0 - int.percent(now)) * len));
|
||||||
}
|
}
|
||||||
PedState::StartingToBike(_, _, _)
|
PedState::StartingToBike(_, _, _)
|
||||||
| PedState::FinishingBiking(_, _, _)
|
| PedState::FinishingBiking(_, _, _)
|
||||||
@ -422,12 +470,19 @@ impl WalkingSimState {
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(front_path.consume().into_iter().map(|(b, set)| {
|
.chain(bldg_front_path.consume().into_iter().map(|(b, set)| {
|
||||||
(
|
(
|
||||||
set.into_iter().collect::<Vec<_>>(),
|
set.into_iter().collect::<Vec<_>>(),
|
||||||
PedCrowdLocation::FrontPath(b),
|
PedCrowdLocation::BldgFrontPath(b),
|
||||||
map.get_b(b).front_path.line.length(),
|
map.get_b(b).front_path.line.length(),
|
||||||
)
|
)
|
||||||
|
}))
|
||||||
|
.chain(lot_front_path.consume().into_iter().map(|(pl, set)| {
|
||||||
|
(
|
||||||
|
set.into_iter().collect::<Vec<_>>(),
|
||||||
|
PedCrowdLocation::LotFrontPath(pl),
|
||||||
|
map.get_pl(pl).sidewalk_line.length(),
|
||||||
|
)
|
||||||
})) {
|
})) {
|
||||||
if group.is_empty() {
|
if group.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
@ -493,8 +548,12 @@ impl Pedestrian {
|
|||||||
match self.state {
|
match self.state {
|
||||||
PedState::Crossing(ref dist_int, ref time_int) => dist_int.lerp(time_int.percent(now)),
|
PedState::Crossing(ref dist_int, ref time_int) => dist_int.lerp(time_int.percent(now)),
|
||||||
PedState::WaitingToTurn(dist, _) => dist,
|
PedState::WaitingToTurn(dist, _) => dist,
|
||||||
PedState::LeavingBuilding(b, _) => map.get_b(b).front_path.sidewalk.dist_along(),
|
PedState::LeavingBuilding(b, _) | PedState::EnteringBuilding(b, _) => {
|
||||||
PedState::EnteringBuilding(b, _) => map.get_b(b).front_path.sidewalk.dist_along(),
|
map.get_b(b).front_path.sidewalk.dist_along()
|
||||||
|
}
|
||||||
|
PedState::LeavingParkingLot(pl, _) | PedState::EnteringParkingLot(pl, _) => {
|
||||||
|
map.get_pl(pl).sidewalk_pos.dist_along()
|
||||||
|
}
|
||||||
PedState::StartingToBike(ref spot, _, _) => spot.sidewalk_pos.dist_along(),
|
PedState::StartingToBike(ref spot, _, _) => spot.sidewalk_pos.dist_along(),
|
||||||
PedState::FinishingBiking(ref spot, _, _) => spot.sidewalk_pos.dist_along(),
|
PedState::FinishingBiking(ref spot, _, _) => spot.sidewalk_pos.dist_along(),
|
||||||
PedState::WaitingForBus(_, _) => self.goal.sidewalk_pos.dist_along(),
|
PedState::WaitingForBus(_, _) => self.goal.sidewalk_pos.dist_along(),
|
||||||
@ -540,22 +599,33 @@ impl Pedestrian {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
PedState::LeavingBuilding(b, ref time_int) => {
|
PedState::LeavingBuilding(b, ref time_int) => {
|
||||||
let front_path = &map.get_b(b).front_path;
|
let line = &map.get_b(b).front_path.line;
|
||||||
(
|
(
|
||||||
front_path
|
line.dist_along(time_int.percent(now) * line.length()),
|
||||||
.line
|
line.angle(),
|
||||||
.dist_along(time_int.percent(now) * front_path.line.length()),
|
|
||||||
front_path.line.angle(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
PedState::EnteringBuilding(b, ref time_int) => {
|
PedState::EnteringBuilding(b, ref time_int) => {
|
||||||
let front_path = &map.get_b(b).front_path;
|
let line = &map.get_b(b).front_path.line;
|
||||||
(
|
(
|
||||||
front_path
|
line.reverse()
|
||||||
.line
|
.dist_along(time_int.percent(now) * line.length()),
|
||||||
.reverse()
|
line.angle().opposite(),
|
||||||
.dist_along(time_int.percent(now) * front_path.line.length()),
|
)
|
||||||
front_path.line.angle().opposite(),
|
}
|
||||||
|
PedState::LeavingParkingLot(pl, ref time_int) => {
|
||||||
|
let line = &map.get_pl(pl).sidewalk_line;
|
||||||
|
(
|
||||||
|
line.dist_along(time_int.percent(now) * line.length()),
|
||||||
|
line.angle(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PedState::EnteringParkingLot(pl, ref time_int) => {
|
||||||
|
let line = &map.get_pl(pl).sidewalk_line;
|
||||||
|
(
|
||||||
|
line.reverse()
|
||||||
|
.dist_along(time_int.percent(now) * line.length()),
|
||||||
|
line.angle().opposite(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
PedState::StartingToBike(_, ref line, ref time_int) => {
|
PedState::StartingToBike(_, ref line, ref time_int) => {
|
||||||
@ -639,6 +709,8 @@ enum PedState {
|
|||||||
WaitingToTurn(Distance, Time),
|
WaitingToTurn(Distance, Time),
|
||||||
LeavingBuilding(BuildingID, TimeInterval),
|
LeavingBuilding(BuildingID, TimeInterval),
|
||||||
EnteringBuilding(BuildingID, TimeInterval),
|
EnteringBuilding(BuildingID, TimeInterval),
|
||||||
|
LeavingParkingLot(ParkingLotID, TimeInterval),
|
||||||
|
EnteringParkingLot(ParkingLotID, TimeInterval),
|
||||||
StartingToBike(SidewalkSpot, Line, TimeInterval),
|
StartingToBike(SidewalkSpot, Line, TimeInterval),
|
||||||
FinishingBiking(SidewalkSpot, Line, TimeInterval),
|
FinishingBiking(SidewalkSpot, Line, TimeInterval),
|
||||||
WaitingForBus(BusRouteID, Time),
|
WaitingForBus(BusRouteID, Time),
|
||||||
@ -651,6 +723,8 @@ impl PedState {
|
|||||||
PedState::WaitingToTurn(_, _) => unreachable!(),
|
PedState::WaitingToTurn(_, _) => unreachable!(),
|
||||||
PedState::LeavingBuilding(_, ref time_int) => time_int.end,
|
PedState::LeavingBuilding(_, ref time_int) => time_int.end,
|
||||||
PedState::EnteringBuilding(_, ref time_int) => time_int.end,
|
PedState::EnteringBuilding(_, ref time_int) => time_int.end,
|
||||||
|
PedState::LeavingParkingLot(_, ref time_int) => time_int.end,
|
||||||
|
PedState::EnteringParkingLot(_, ref time_int) => time_int.end,
|
||||||
PedState::StartingToBike(_, _, ref time_int) => time_int.end,
|
PedState::StartingToBike(_, _, ref time_int) => time_int.end,
|
||||||
PedState::FinishingBiking(_, _, ref time_int) => time_int.end,
|
PedState::FinishingBiking(_, _, ref time_int) => time_int.end,
|
||||||
PedState::WaitingForBus(_, _) => unreachable!(),
|
PedState::WaitingForBus(_, _) => unreachable!(),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{CarID, PedestrianID, PersonID, VehicleType};
|
use crate::{CarID, PedestrianID, PersonID, VehicleType};
|
||||||
use geom::{Angle, Distance, PolyLine, Pt2D, Time};
|
use geom::{Angle, Distance, PolyLine, Pt2D, Time};
|
||||||
use map_model::{BuildingID, Map, Traversable, TurnID};
|
use map_model::{BuildingID, Map, ParkingLotID, Traversable, TurnID};
|
||||||
|
|
||||||
// Intermediate structures so that sim and game crates don't have a cyclic dependency.
|
// Intermediate structures so that sim and game crates don't have a cyclic dependency.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -25,7 +25,8 @@ pub struct DrawPedCrowdInput {
|
|||||||
pub enum PedCrowdLocation {
|
pub enum PedCrowdLocation {
|
||||||
// bool is contraflow
|
// bool is contraflow
|
||||||
Sidewalk(Traversable, bool),
|
Sidewalk(Traversable, bool),
|
||||||
FrontPath(BuildingID),
|
BldgFrontPath(BuildingID),
|
||||||
|
LotFrontPath(ParkingLotID),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
Loading…
Reference in New Issue
Block a user