diff --git a/data/MANIFEST.txt b/data/MANIFEST.txt index 9cf0e1498a..06d9daa969 100644 --- a/data/MANIFEST.txt +++ b/data/MANIFEST.txt @@ -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 diff --git a/game/src/edit/zones.rs b/game/src/edit/zones.rs index cec50c5778..e88358df78 100644 --- a/game/src/edit/zones.rs +++ b/game/src/edit/zones.rs @@ -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, + _members: BTreeSet, unzoomed: Drawable, zoomed: Drawable, } impl ZoneEditor { pub fn new(ctx: &mut EventCtx, app: &App, start: RoadID) -> Box { - 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), ], ); diff --git a/game/src/info/lane.rs b/game/src/info/lane.rs index 879749522d..02bfa48ad3 100644 --- a/game/src/info/lane.rs +++ b/game/src/info/lane.rs @@ -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())); } diff --git a/game/src/render/lane.rs b/game/src/render/lane.rs index d1a895fb4a..2bcc3878db 100644 --- a/game/src/render/lane.rs +++ b/game/src/render/lane.rs @@ -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()); } diff --git a/game/src/render/map.rs b/game/src/render/map.rs index f42159e17a..27d4912efc 100644 --- a/game/src/render/map.rs +++ b/game/src/render/map.rs @@ -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()) diff --git a/game/src/render/road.rs b/game/src/render/road.rs index ddabca57c7..4e23f7b08b 100644 --- a/game/src/render/road.rs +++ b/game/src/render/road.rs @@ -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 diff --git a/map_model/src/intersection.rs b/map_model/src/intersection.rs index 93bffb5900..75bedd435b 100644 --- a/map_model/src/intersection.rs +++ b/map_model/src/intersection.rs @@ -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>( diff --git a/map_model/src/make/zones.rs b/map_model/src/make/zones.rs index 85493c9ce6..5f5a34cbd1 100644 --- a/map_model/src/make/zones.rs +++ b/map_model/src/make/zones.rs @@ -4,7 +4,7 @@ use std::collections::BTreeSet; pub fn make_all_zones(map: &Map) -> Vec { 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(), } } diff --git a/map_model/src/map.rs b/map_model/src/map.rs index 4df6afe14a..0928e2fad7 100644 --- a/map_model/src/map.rs +++ b/map_model/src/map.rs @@ -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 { 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 { diff --git a/map_model/src/pathfind/driving.rs b/map_model/src/pathfind/driving.rs index 0e5c670a82..7ad3994694 100644 --- a/map_model/src/pathfind/driving.rs +++ b/map_model/src/pathfind/driving.rs @@ -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) { diff --git a/map_model/src/pathfind/mod.rs b/map_model/src/pathfind/mod.rs index 5bfba425e5..afdc2b0e95 100644 --- a/map_model/src/pathfind/mod.rs +++ b/map_model/src/pathfind/mod.rs @@ -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,58 +558,63 @@ 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 - } - } else if start_r.is_private() { - 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? - let pt = req.end.pt(map); - borders.sort_by_key(|i| pt.dist_to(i.polygon.center())); - - for i in borders { - if let Some(result) = self.pathfind_from_zone(i, req.clone(), zone, map) { - validate_continuity(map, &result.steps.iter().cloned().collect()); - return Some(result); + } 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 mut borders: Vec<&Intersection> = + zone.borders.iter().map(|i| map.get_i(*i)).collect(); + // TODO Use the CH to pick the lowest overall cost? + let pt = req.end.pt(map); + borders.sort_by_key(|i| pt.dist_to(i.polygon.center())); + + for i in borders { + if let Some(result) = self.pathfind_from_zone(i, req.clone(), zone, map) { + validate_continuity(map, &result.steps.iter().cloned().collect()); + return Some(result); + } } - } - None - } else if end_r.is_private() { - 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? - let pt = req.start.pt(map); - borders.sort_by_key(|i| pt.dist_to(i.polygon.center())); - - for i in borders { - if let Some(result) = self.pathfind_to_zone(i, req.clone(), zone, map) { - validate_continuity(map, &result.steps.iter().cloned().collect()); - return Some(result); + } 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 mut borders: Vec<&Intersection> = + zone.borders.iter().map(|i| map.get_i(*i)).collect(); + // TODO Use the CH to pick the lowest overall cost? + let pt = req.start.pt(map); + borders.sort_by_key(|i| pt.dist_to(i.polygon.center())); + + for i in borders { + if let Some(result) = self.pathfind_to_zone(i, req.clone(), zone, map) { + validate_continuity(map, &result.steps.iter().cloned().collect()); + return Some(result); + } + } + return None; } - None - } else { - match req.constraints { - PathConstraints::Pedestrian => self.walking_graph.pathfind(&req, map), - PathConstraints::Car => self.car_graph.pathfind(&req, map).map(|(p, _)| p), - PathConstraints::Bike => self.bike_graph.pathfind(&req, map).map(|(p, _)| p), - PathConstraints::Bus => self.bus_graph.pathfind(&req, map).map(|(p, _)| p), - } + } + + match req.constraints { + PathConstraints::Pedestrian => self.walking_graph.pathfind(&req, map), + PathConstraints::Car => self.car_graph.pathfind(&req, map).map(|(p, _)| p), + PathConstraints::Bike => self.bike_graph.pathfind(&req, map).map(|(p, _)| p), + PathConstraints::Bus => self.bus_graph.pathfind(&req, map).map(|(p, _)| p), } } diff --git a/map_model/src/pathfind/walking.rs b/map_model/src/pathfind/walking.rs index cf9e6d6c5d..5cb4101a37 100644 --- a/map_model/src/pathfind/walking.rs +++ b/map_model/src/pathfind/walking.rs @@ -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)); diff --git a/map_model/src/road.rs b/map_model/src/road.rs index 98e0b1f9ce..77e6d3076a 100644 --- a/map_model/src/road.rs +++ b/map_model/src/road.rs @@ -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, 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 + } + } } diff --git a/map_model/src/zone.rs b/map_model/src/zone.rs index a45b594466..4940b7acfb 100644 --- a/map_model/src/zone.rs +++ b/map_model/src/zone.rs @@ -24,6 +24,7 @@ pub struct Zone { pub id: ZoneID, pub members: BTreeSet, pub borders: BTreeSet, + pub allow_through_traffic: BTreeSet, } impl Zone { diff --git a/sim/src/trips.rs b/sim/src/trips.rs index cb95a93101..449cb9f316 100644 --- a/sim/src/trips.rs +++ b/sim/src/trips.rs @@ -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)]