start representing access restrictions by mode

This commit is contained in:
Dustin Carlino 2020-06-30 13:15:57 -07:00
parent 2b4bf1172b
commit 2c7440b03f
15 changed files with 151 additions and 91 deletions

View File

@ -8,8 +8,8 @@ data/input/raw_maps/huge_austin.bin,5d0fdca0eb9bae5cd5e0955442972bd4,https://www
data/input/raw_maps/huge_seattle.bin,22f323f1ce1917df9e261f24f557780f,https://www.dropbox.com/s/r6cj78jq3z7s5bs/huge_seattle.bin.zip?dl=0
data/input/raw_maps/lakeslice.bin,c346ac30ad726456802937729af76af4,https://www.dropbox.com/s/uh4oacev5raty9z/lakeslice.bin.zip?dl=0
data/input/raw_maps/montlake.bin,b17d1f76d6c5dd4a3af07343ca52590d,https://www.dropbox.com/s/dfcoo90hpwa8osj/montlake.bin.zip?dl=0
data/input/raw_maps/south_seattle.bin,aae79f98db1f1db4877fa3ea36dd6799,https://www.dropbox.com/s/fut27hmbobf3fn7/south_seattle.bin.zip?dl=0
data/input/raw_maps/udistrict.bin,7a07a32527ebc4577cebdf79f410cfd2,https://www.dropbox.com/s/l6n8blpex76tl9q/udistrict.bin.zip?dl=0
data/input/raw_maps/south_seattle.bin,a8ded05512d20fac14cdb8e605c14995,https://www.dropbox.com/s/1m7fkvuyhyev3cw/south_seattle.bin.zip?dl=0
data/input/raw_maps/udistrict.bin,eba1715dd8a66ff3fb0a39aa92419d93,https://www.dropbox.com/s/wbudupyrqd1aqg6/udistrict.bin.zip?dl=0
data/input/raw_maps/west_seattle.bin,04c347cc62a3c2f078190b98af04c10f,https://www.dropbox.com/s/350gq0dtgvw2lrg/west_seattle.bin.zip?dl=0
data/input/screenshots/downtown/01x01.gif,873df007edd02e5967f3917cbe8f342f,https://www.dropbox.com/s/4209gvxkypinlqs/01x01.gif.zip?dl=0
data/input/screenshots/downtown/01x02.gif,ec8b579d6cb498a2a85bc2af8b51f390,https://www.dropbox.com/s/9x5qtp86h3uemzm/01x02.gif.zip?dl=0
@ -364,16 +364,16 @@ data/input/seattle/sidewalks.bin,034dd47ab77902dbc81c0107f13d8965,https://www.dr
data/input/seattle/sidewalks.kml,94d385ba03ef1b57a5ba10965913ec6c,https://www.dropbox.com/s/vn8amar9xi6vbvh/sidewalks.kml.zip?dl=0
data/input/seattle/trips_2014.csv,d4a8e733045b28c0385fb81359d6df03,https://www.dropbox.com/s/5ppravwmk6bf20d/trips_2014.csv.zip?dl=0
data/system/cities/seattle.bin,65ed19fe6b0a41d57ccb481a5c76652a,https://www.dropbox.com/s/kwei76ih7g12n1r/seattle.bin.zip?dl=0
data/system/maps/ballard.bin,995adf8b00f7ae1bcf5b3bcb4287df16,https://www.dropbox.com/s/iottgk3e3wwn1sb/ballard.bin.zip?dl=0
data/system/maps/downtown.bin,f02f91f4e7a3ff910ebe803e8401afcf,https://www.dropbox.com/s/0pu30om3lsh014w/downtown.bin.zip?dl=0
data/system/maps/downtown_atx.bin,58749e8cc6c520ffbc6028f2be04656d,https://www.dropbox.com/s/p4d4jlrttmflbf7/downtown_atx.bin.zip?dl=0
data/system/maps/huge_austin.bin,1074a390013957bbd8a3d359638aadc5,https://www.dropbox.com/s/pa20via4ifb61r6/huge_austin.bin.zip?dl=0
data/system/maps/huge_seattle.bin,0858a4e1914aa72ce04abd8b61e4ed28,https://www.dropbox.com/s/f5lhssdvzwugey1/huge_seattle.bin.zip?dl=0
data/system/maps/lakeslice.bin,690a17e8f0fae370fb6764c9f7836a12,https://www.dropbox.com/s/d9tpix5a12316i2/lakeslice.bin.zip?dl=0
data/system/maps/montlake.bin,e770cedad9dbbd4a7d7dd737b79d753c,https://www.dropbox.com/s/1muzjwmrhf99ppq/montlake.bin.zip?dl=0
data/system/maps/south_seattle.bin,00c2054bce2202b10c603b420a076f31,https://www.dropbox.com/s/4cz88pohpzp48eu/south_seattle.bin.zip?dl=0
data/system/maps/udistrict.bin,ce77eaa72521046a11bc841eeadc4cdf,https://www.dropbox.com/s/b7tvz3tfchfrmdh/udistrict.bin.zip?dl=0
data/system/maps/west_seattle.bin,2887904a9b2a662a67678fa6a1bcfe7e,https://www.dropbox.com/s/6pu9dqsawpk7swo/west_seattle.bin.zip?dl=0
data/system/maps/ballard.bin,dcf893cd9a338f00cb88b5fe2048fe7a,https://www.dropbox.com/s/v4zdc1g5gjz5gyo/ballard.bin.zip?dl=0
data/system/maps/downtown.bin,5cfdff22ec0f8961d88054f613ee186a,https://www.dropbox.com/s/mw16rjqikr4u754/downtown.bin.zip?dl=0
data/system/maps/downtown_atx.bin,63cba91cbc3366eec68fba251d58a6da,https://www.dropbox.com/s/s2h3p2h5dv6snre/downtown_atx.bin.zip?dl=0
data/system/maps/huge_austin.bin,1141475a9b9e6d41b5d483403ce7ddf3,https://www.dropbox.com/s/9cra6p70e5vdc47/huge_austin.bin.zip?dl=0
data/system/maps/huge_seattle.bin,2fcc78ca78c6870912a898cafc1120ae,https://www.dropbox.com/s/ks1sdcn3u8jbkri/huge_seattle.bin.zip?dl=0
data/system/maps/lakeslice.bin,8a33d642b6af5875e2d48ceb685b84b0,https://www.dropbox.com/s/883ptuk0yga16qh/lakeslice.bin.zip?dl=0
data/system/maps/montlake.bin,338597accb3c94c2cd0fd0156b1bbd07,https://www.dropbox.com/s/cxyk0q7e4t048u0/montlake.bin.zip?dl=0
data/system/maps/south_seattle.bin,689aa5e980e08a58e86665a7a090ba46,https://www.dropbox.com/s/1prnq73si0xwwdt/south_seattle.bin.zip?dl=0
data/system/maps/udistrict.bin,6e1cecb203a4453a2aa85d79b02f9844,https://www.dropbox.com/s/wo49zxaw6z680xp/udistrict.bin.zip?dl=0
data/system/maps/west_seattle.bin,04123324605285542d5c6ed668d7c389,https://www.dropbox.com/s/71cexi6kijdxaz2/west_seattle.bin.zip?dl=0
data/system/prebaked_results/lakeslice/weekday.bin,05e4bf98e698919bbde9d62fa48a8599,https://www.dropbox.com/s/i1qun9jbo7xpy1k/weekday.bin.zip?dl=0
data/system/prebaked_results/montlake/car vs bike contention.bin,50b15194b8f91500ee6c17a5b0d498af,https://www.dropbox.com/s/jefg0ikjy9dsrdd/car%20vs%20bike%20contention.bin.zip?dl=0
data/system/prebaked_results/montlake/weekday.bin,fa12670c06a816719fa7331eabe8bc48,https://www.dropbox.com/s/jt6x1ej48n7cp3g/weekday.bin.zip?dl=0

View File

@ -1,4 +1,4 @@
use crate::app::App;
use crate::app::{App, ShowEverything};
use crate::common::ColorDiscrete;
use crate::common::CommonState;
use crate::game::{State, Transition};
@ -9,25 +9,31 @@ use ezgui::{
};
use map_model::RoadID;
use maplit::btreeset;
use sim::{DontDrawAgents, TripMode};
use std::collections::BTreeSet;
pub struct ZoneEditor {
composite: Composite,
members: BTreeSet<RoadID>,
_members: BTreeSet<RoadID>,
unzoomed: Drawable,
zoomed: Drawable,
}
impl ZoneEditor {
pub fn new(ctx: &mut EventCtx, app: &App, start: RoadID) -> Box<dyn State> {
let members = if app.primary.map.get_r(start).is_private() {
app.primary.map.road_to_zone(start).members.clone()
let (members, allow_through_traffic) = if let Some(z) = app.primary.map.get_r(start).zone {
let zone = app.primary.map.get_z(z);
(
zone.members.clone(),
zone.allow_through_traffic
.iter()
.map(|c| TripMode::from_constraints(*c))
.collect(),
)
} else {
// Starting a new zone
btreeset! { start }
(btreeset! { start }, BTreeSet::new())
};
// TODO Pull this from the existing zone
let allow_thru_trips = BTreeSet::new();
let (unzoomed, zoomed, legend) = draw_zone(ctx, app, &members);
@ -45,7 +51,7 @@ impl ZoneEditor {
)
.draw(ctx)
.margin_below(10),
checkbox_per_mode(ctx, app, &allow_thru_trips).margin_below(10),
checkbox_per_mode(ctx, app, &allow_through_traffic).margin_below(10),
Widget::row(vec![
Btn::text_fg("Apply").build_def(ctx, hotkey(Key::Enter)),
Btn::text_fg("Cancel").build_def(ctx, hotkey(Key::Escape)),
@ -57,7 +63,7 @@ impl ZoneEditor {
)
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
.build(ctx),
members,
_members: members,
unzoomed,
zoomed,
})
@ -67,14 +73,28 @@ impl ZoneEditor {
impl State for ZoneEditor {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
ctx.canvas_movement();
// Restrict what can be selected.
// TODO Share with PaintSelect.
if ctx.redo_mouseover() {
app.recalculate_current_selection(ctx);
if let Some(ID::Lane(_)) = app.primary.current_selection {
} else if let Some(ID::Road(_)) = app.primary.current_selection {
app.primary.current_selection = app.calculate_current_selection(
ctx,
&DontDrawAgents {},
&ShowEverything::new(),
false,
true,
false,
);
if let Some(ID::Road(_)) = app.primary.current_selection {
} else if let Some(ID::Lane(l)) = app.primary.current_selection {
app.primary.current_selection = Some(ID::Road(app.primary.map.get_l(l).parent));
} else {
app.primary.current_selection = None;
}
if let Some(ID::Road(r)) = app.primary.current_selection {
if app.primary.map.get_r(r).is_light_rail() {
app.primary.current_selection = None;
}
}
}
match self.composite.event(ctx) {
@ -94,6 +114,7 @@ impl State for ZoneEditor {
}
fn draw(&self, g: &mut GfxCtx, app: &App) {
// TODO The currently selected road is covered up pretty badly
if g.canvas.cam_zoom < app.opts.min_zoom_for_detail {
g.redraw(&self.unzoomed);
} else {
@ -112,7 +133,7 @@ fn draw_zone(
let mut colorer = ColorDiscrete::new(
app,
vec![
("restricted road", Color::RED),
("restricted road", Color::CYAN),
("entrance/exit", Color::BLUE),
],
);

View File

@ -16,7 +16,7 @@ pub fn info(ctx: &EventCtx, app: &App, details: &mut Details, id: LaneID) -> Vec
if !l.is_sidewalk() {
kv.push(("Type", l.lane_type.describe().to_string()));
}
if r.is_private() {
if r.zone.is_some() {
// TODO Ideally the area name, and be more specific about access restrictions
kv.push(("Access", "Private".to_string()));
}

View File

@ -184,7 +184,7 @@ impl DrawLane {
}
};
}
if road.is_private() {
if road.zone.is_some() {
draw.push(cs.private_road.alpha(0.5), polygon.clone());
}

View File

@ -68,7 +68,7 @@ impl DrawMap {
all_roads.push(
if r.is_light_rail() {
cs.light_rail_track
} else if r.is_private() {
} else if r.zone.is_some() {
cs.private_road
} else {
osm_rank_to_color(cs, r.get_rank())

View File

@ -20,7 +20,7 @@ impl DrawRoad {
let mut draw = GeomBatch::new();
let center = r.get_current_center(map);
let width = Distance::meters(0.25);
let color = if r.is_private() {
let color = if r.zone.is_some() {
cs.road_center_line.lerp(cs.private_road, 0.5)
} else {
cs.road_center_line
@ -70,12 +70,12 @@ impl Renderable for DrawRoad {
if r.center_pts.length() >= Distance::meters(30.0) && name != "???" {
// TODO If it's definitely straddling bus/bike lanes, change the color? Or
// even easier, just skip the center lines?
let fg = if r.is_private() {
let fg = if r.zone.is_some() {
app.cs.road_center_line.lerp(app.cs.private_road, 0.5)
} else {
app.cs.road_center_line
};
let bg = if r.is_private() {
let bg = if r.zone.is_some() {
app.cs.driving_lane.lerp(app.cs.private_road, 0.5)
} else {
app.cs.driving_lane

View File

@ -65,7 +65,7 @@ impl Intersection {
}
pub fn is_private(&self, map: &Map) -> bool {
self.roads.iter().all(|r| map.get_r(*r).is_private())
self.roads.iter().all(|r| map.get_r(*r).zone.is_some())
}
pub fn get_incoming_lanes<'a>(

View File

@ -4,7 +4,7 @@ use std::collections::BTreeSet;
pub fn make_all_zones(map: &Map) -> Vec<Zone> {
let mut queue = Vec::new();
for r in map.all_roads() {
if r.is_private() {
if r.osm_tags.get("access") == Some(&"private".to_string()) {
queue.push(r.id);
}
}
@ -36,7 +36,7 @@ fn floodfill(map: &Map, start: RoadID, id: ZoneID) -> Zone {
members.insert(current);
for r in map.get_next_roads(current) {
let r = map.get_r(r);
if r.is_private() {
if r.osm_tags.get("access") == Some(&"private".to_string()) {
queue.push(r.id);
} else {
borders.insert(map.get_r(current).common_endpt(r));
@ -49,5 +49,6 @@ fn floodfill(map: &Map, start: RoadID, id: ZoneID) -> Zone {
id,
members,
borders,
allow_through_traffic: BTreeSet::new(),
}
}

View File

@ -745,11 +745,6 @@ impl Map {
None
}
pub fn road_to_zone(&self, r: RoadID) -> &Zone {
// TODO Consider indexing
self.zones.iter().find(|z| z.members.contains(&r)).unwrap()
}
pub fn right_shift(&self, pl: PolyLine, width: Distance) -> Warn<PolyLine> {
self.driving_side.right_shift(pl, width)
}
@ -1024,6 +1019,7 @@ fn make_half_map(
} else {
0
},
zone: None,
};
road.speed_limit = road.speed_limit_from_osm();
@ -1142,6 +1138,11 @@ fn make_half_map(
make::buildings::make_all_parking_lots(&raw.parking_lots, &raw.parking_aisles, &map, timer);
map.zones = make::zones::make_all_zones(&map);
for z in &map.zones {
for r in &z.members {
map.roads[r.0].zone = Some(z.id);
}
}
for (idx, a) in raw.areas.iter().enumerate() {
map.areas.push(Area {

View File

@ -161,7 +161,9 @@ fn make_input_graph(
for l in map.all_lanes() {
let from = nodes.get(Node::Lane(l.id));
let mut any = false;
if constraints.can_use(l, map) && !map.get_r(l.parent).is_private() {
if constraints.can_use(l, map)
&& map.get_r(l.parent).allow_through_traffic(constraints, map)
{
let indices = uber_turn_entrances.get(l.id);
if indices.is_empty() {
for turn in map.get_turns_for(l.id, constraints) {

View File

@ -365,7 +365,7 @@ fn glue(step1: PathStep, step2: PathStep, map: &Map) -> TurnID {
// Who's asking for a path?
// TODO This is an awful name.
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub enum PathConstraints {
Pedestrian,
Car,
@ -385,6 +385,7 @@ impl PathConstraints {
}
}
// TODO Handle private zones here?
pub fn can_use(self, l: &Lane, map: &Map) -> bool {
match self {
PathConstraints::Pedestrian => l.is_sidewalk(),
@ -557,20 +558,22 @@ impl Pathfinder {
let start_r = map.get_parent(req.start.lane());
let end_r = map.get_parent(req.end.lane());
if start_r.is_private() && end_r.is_private() {
let zone1 = map.road_to_zone(start_r.id);
let zone2 = map.road_to_zone(end_r.id);
if zone1.id == zone2.id {
zone1.pathfind(req, map)
if start_r.zone.is_some() && end_r.zone.is_some() {
if start_r.zone == end_r.zone {
let zone = map.get_z(start_r.zone.unwrap());
if !zone.allow_through_traffic.contains(&req.constraints) {
return zone.pathfind(req, map);
}
} else {
// TODO Handle paths going between two different zones
None
return None;
}
} else if start_r.is_private() {
} else if let Some(z) = start_r.zone {
let zone = map.get_z(z);
if !zone.allow_through_traffic.contains(&req.constraints) {
if req.constraints == PathConstraints::Pedestrian {
return None;
}
let zone = map.road_to_zone(start_r.id);
let mut borders: Vec<&Intersection> =
zone.borders.iter().map(|i| map.get_i(*i)).collect();
// TODO Use the CH to pick the lowest overall cost?
@ -583,12 +586,14 @@ impl Pathfinder {
return Some(result);
}
}
None
} else if end_r.is_private() {
return None;
}
} else if let Some(z) = end_r.zone {
let zone = map.get_z(z);
if !zone.allow_through_traffic.contains(&req.constraints) {
if req.constraints == PathConstraints::Pedestrian {
return None;
}
let zone = map.road_to_zone(end_r.id);
let mut borders: Vec<&Intersection> =
zone.borders.iter().map(|i| map.get_i(*i)).collect();
// TODO Use the CH to pick the lowest overall cost?
@ -601,8 +606,10 @@ impl Pathfinder {
return Some(result);
}
}
None
} else {
return None;
}
}
match req.constraints {
PathConstraints::Pedestrian => self.walking_graph.pathfind(&req, map),
PathConstraints::Car => self.car_graph.pathfind(&req, map).map(|(p, _)| p),
@ -610,7 +617,6 @@ impl Pathfinder {
PathConstraints::Bus => self.bus_graph.pathfind(&req, map).map(|(p, _)| p),
}
}
}
// TODO Alright, reconsider refactoring pieces of this again. :)
fn pathfind_from_zone(

View File

@ -134,7 +134,11 @@ fn make_input_graph(
let mut input_graph = InputGraph::new();
for l in map.all_lanes() {
if l.is_sidewalk() && !map.get_r(l.parent).is_private() {
if l.is_sidewalk()
&& map
.get_r(l.parent)
.allow_through_traffic(PathConstraints::Pedestrian, map)
{
let cost = walking_cost(l.length());
let n1 = nodes.get(WalkingNode::SidewalkEndpoint(l.id, true));
let n2 = nodes.get(WalkingNode::SidewalkEndpoint(l.id, false));

View File

@ -1,5 +1,5 @@
use crate::raw::{OriginalRoad, RestrictionType};
use crate::{osm, BusStopID, IntersectionID, LaneID, LaneType, Map, PathConstraints};
use crate::{osm, BusStopID, IntersectionID, LaneID, LaneType, Map, PathConstraints, ZoneID};
use abstutil::{Error, Warn};
use geom::{Distance, PolyLine, Polygon, Speed};
use serde::{Deserialize, Serialize};
@ -93,6 +93,7 @@ pub struct Road {
pub complicated_turn_restrictions: Vec<(RoadID, RoadID)>,
pub orig_id: OriginalRoad,
pub speed_limit: Speed,
pub zone: Option<ZoneID>,
pub zorder: isize,
// Invariant: A road must contain at least one child
@ -415,10 +416,6 @@ impl Road {
!self.children_forwards.is_empty() && self.children_forwards[0].1 == LaneType::LightRail
}
pub fn is_private(&self) -> bool {
self.osm_tags.get("access") == Some(&"private".to_string())
}
pub fn common_endpt(&self, other: &Road) -> IntersectionID {
if self.src_i == other.src_i || self.src_i == other.dst_i {
self.src_i
@ -428,4 +425,12 @@ impl Road {
panic!("{} and {} don't share an endpoint", self.id, other.id);
}
}
pub(crate) fn allow_through_traffic(&self, constraints: PathConstraints, map: &Map) -> bool {
if let Some(z) = self.zone {
map.get_z(z).allow_through_traffic.contains(&constraints)
} else {
true
}
}
}

View File

@ -24,6 +24,7 @@ pub struct Zone {
pub id: ZoneID,
pub members: BTreeSet<RoadID>,
pub borders: BTreeSet<IntersectionID>,
pub allow_through_traffic: BTreeSet<PathConstraints>,
}
impl Zone {

View File

@ -1391,6 +1391,25 @@ impl TripMode {
TripMode::Drive => "Car",
}
}
// TODO Collapse these two enums?
pub fn to_constraints(self) -> PathConstraints {
match self {
TripMode::Walk => PathConstraints::Pedestrian,
TripMode::Bike => PathConstraints::Bike,
TripMode::Transit => PathConstraints::Bus,
TripMode::Drive => PathConstraints::Car,
}
}
pub fn from_constraints(c: PathConstraints) -> TripMode {
match c {
PathConstraints::Pedestrian => TripMode::Walk,
PathConstraints::Bike => TripMode::Bike,
PathConstraints::Bus => TripMode::Transit,
PathConstraints::Car => TripMode::Drive,
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]