From b9ac8021d0729145143e54caa7ab044467660b54 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Fri, 20 Sep 2019 13:06:29 -0700 Subject: [PATCH] making first-class mutations on raw map, so synthetic model does less work. not porting over the mutations not preserved by fixes yet, and also not actually recording fixes for the moment... --- docs/project/references.md | 1 + map_model/src/raw_data.rs | 203 ++++++++++++++++++++++++++----------- synthetic/src/model.rs | 148 ++++++--------------------- 3 files changed, 178 insertions(+), 174 deletions(-) diff --git a/docs/project/references.md b/docs/project/references.md index f02614bd4b..c370f591eb 100644 --- a/docs/project/references.md +++ b/docs/project/references.md @@ -6,6 +6,7 @@ - https://www.reddit.com/r/SeattleWA/comments/9oqkz9/how_traffic_patterns_will_change_after_seattles/ - https://www.reddit.com/r/Seattle/comments/9orqne/4_fresh_ideas_to_ease_seattles_coming_traffic/ - https://www.reddit.com/r/SeattleWA/comments/cr1r1l/why_the_fuck_does_the_right_lane_convert_to/ +- https://twitter.com/transitrunner/status/1175068582142599168 ## Groups that may be eventually interested diff --git a/map_model/src/raw_data.rs b/map_model/src/raw_data.rs index b349671fb8..6ef74b7c39 100644 --- a/map_model/src/raw_data.rs +++ b/map_model/src/raw_data.rs @@ -1,6 +1,6 @@ use crate::make::get_lane_types; pub use crate::make::{remove_disconnected_roads, Hint, Hints, InitialMap}; -use crate::{AreaType, IntersectionType, OffstreetParking, RoadSpec}; +use crate::{osm, AreaType, IntersectionType, OffstreetParking, RoadSpec}; use abstutil::Timer; use geom::{Distance, GPSBounds, LonLat, Polygon, Pt2D}; use gtfs::Route; @@ -94,8 +94,7 @@ impl Map { let mut skipped = 0; for orig in &fixes.delete_roads { - if let Some(r) = self.find_r(*orig) { - self.roads.remove(&r).unwrap(); + if self.delete_road(*orig, None).is_some() { applied += 1; } else { skipped += 1; @@ -103,8 +102,7 @@ impl Map { } for orig in &fixes.delete_intersections { - if let Some(i) = self.find_i(*orig) { - self.intersections.remove(&i).unwrap(); + if self.delete_intersection(*orig, None).is_some() { applied += 1; } else { skipped += 1; @@ -112,9 +110,7 @@ impl Map { } for i in &fixes.add_intersections { - if self.gps_bounds.contains(i.orig_id.point) { - let id = StableIntersectionID(self.intersections.keys().max().unwrap().0 + 1); - self.intersections.insert(id, i.clone()); + if self.create_intersection(i.clone()).is_some() { applied += 1; } else { skipped += 1; @@ -122,59 +118,15 @@ impl Map { } for r in &fixes.add_roads { - match ( - self.find_i(OriginalIntersection { - point: r.orig_id.pt1, - }), - self.find_i(OriginalIntersection { - point: r.orig_id.pt2, - }), - ) { - (Some(i1), Some(i2)) => { - let mut road = r.clone(); - road.i1 = i1; - road.i2 = i2; - let id = StableRoadID(self.roads.keys().max().unwrap().0 + 1); - self.roads.insert(id, road); - applied += 1; - } - _ => { - skipped += 1; - } + if self.create_road(r.clone()).is_some() { + applied += 1; + } else { + skipped += 1; } } for orig in &fixes.merge_short_roads { - if let Some(id) = self.find_r(*orig) { - // TODO Whoa, this one is complicated! - - let (i1, i2) = { - let r = self.roads.remove(&id).unwrap(); - (r.i1, r.i2) - }; - let (i1_pt, i1_orig_id_pt) = { - let i = &self.intersections[&i1]; - (i.point, i.orig_id.point) - }; - - // Arbitrarily keep i1 and destroy i2. - // TODO Make sure intersection types are the same. Make sure i2 isn't synthetic. - self.intersections.remove(&i2).unwrap(); - - // Fix up all roads connected to i2. - // TODO Maintain roads_per_intersection in raw_data? This will get slow. - for r in self.roads.values_mut() { - if r.i1 == i2 { - r.i1 = i1; - r.center_points[0] = i1_pt; - r.orig_id.pt1 = i1_orig_id_pt; - } else if r.i2 == i2 { - r.i2 = i1; - *r.center_points.last_mut().unwrap() = i1_pt; - r.orig_id.pt2 = i1_orig_id_pt; - } - } - + if self.merge_short_road(*orig, None).is_some() { applied += 1; } else { skipped += 1; @@ -182,8 +134,7 @@ impl Map { } for (orig, osm_tags) in &fixes.override_tags { - if let Some(r) = self.find_r(*orig) { - self.roads.get_mut(&r).unwrap().osm_tags = osm_tags.clone(); + if self.override_tags(*orig, osm_tags.clone()).is_some() { applied += 1; } else { skipped += 1; @@ -198,8 +149,142 @@ impl Map { )); } } + + // TODO Might be better to maintain this instead of doing a search everytime. + // TODO make private + pub fn roads_per_intersection(&self, i: StableIntersectionID) -> Vec { + let mut results = Vec::new(); + for (id, r) in &self.roads { + if r.i1 == i || r.i2 == i { + results.push(*id); + } + } + results + } } +// Mutations +impl Map { + pub fn delete_road( + &mut self, + orig: OriginalRoad, + fixes: Option<&mut MapFixes>, + ) -> Option { + let r = self.find_r(orig)?; + let road = self.roads.remove(&r).unwrap(); + if road.osm_tags.get(osm::SYNTHETIC) != Some(&"true".to_string()) { + fixes.map(|f| f.delete_roads.push(orig)); + } + Some(r) + } + + pub fn can_delete_intersection(&self, i: StableIntersectionID) -> bool { + self.roads_per_intersection(i).is_empty() + } + + pub fn delete_intersection( + &mut self, + orig: OriginalIntersection, + fixes: Option<&mut MapFixes>, + ) -> Option { + let id = self.find_i(orig)?; + assert!(self.can_delete_intersection(id)); + let i = self.intersections.remove(&id).unwrap(); + if i.synthetic { + fixes.map(|f| f.delete_intersections.push(orig)); + } + Some(id) + } + + pub fn create_intersection(&mut self, i: Intersection) -> Option { + if self.gps_bounds.contains(i.orig_id.point) { + let id = StableIntersectionID(self.intersections.keys().max().unwrap().0 + 1); + self.intersections.insert(id, i.clone()); + Some(id) + } else { + None + } + } + + pub fn create_road(&mut self, mut r: Road) -> Option { + match ( + self.find_i(OriginalIntersection { + point: r.orig_id.pt1, + }), + self.find_i(OriginalIntersection { + point: r.orig_id.pt2, + }), + ) { + (Some(i1), Some(i2)) => { + r.i1 = i1; + r.i2 = i2; + let id = StableRoadID(self.roads.keys().max().unwrap().0 + 1); + self.roads.insert(id, r); + Some(id) + } + _ => None, + } + } + + // (the merged road, the deleted intersection, list of modified roads connected to deleted + // intersection) + pub fn merge_short_road( + &mut self, + orig: OriginalRoad, + fixes: Option<&mut MapFixes>, + ) -> Option<(StableRoadID, StableIntersectionID, Vec)> { + let id = self.find_r(orig)?; + + let (i1, i2) = { + let r = self.roads.remove(&id).unwrap(); + (r.i1, r.i2) + }; + let (i1_pt, i1_orig_id_pt) = { + let i = &self.intersections[&i1]; + (i.point, i.orig_id.point) + }; + + // Arbitrarily keep i1 and destroy i2. + // TODO Make sure intersection types are the same. Make sure i2 isn't synthetic. + self.intersections.remove(&i2).unwrap(); + + // Fix up all roads connected to i2. + let mut fixed = Vec::new(); + for r in self.roads_per_intersection(i2) { + fixed.push(r); + let road = self.roads.get_mut(&r).unwrap(); + if road.i1 == i2 { + road.i1 = i1; + road.center_points[0] = i1_pt; + road.orig_id.pt1 = i1_orig_id_pt; + } else { + assert_eq!(road.i2, i2); + road.i2 = i1; + *road.center_points.last_mut().unwrap() = i1_pt; + road.orig_id.pt2 = i1_orig_id_pt; + } + } + + fixes.map(|f| f.merge_short_roads.push(orig)); + + Some((id, i2, fixed)) + } + + pub fn override_tags( + &mut self, + orig: OriginalRoad, + osm_tags: BTreeMap, + ) -> Option { + let r = self.find_r(orig)?; + self.roads.get_mut(&r).unwrap().osm_tags = osm_tags; + Some(r) + } +} + +// Mutations not recorded in MapFixes yet +// TODO Fix that! +impl Map {} + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Road { // The first and last point may not match up with i1 and i2. diff --git a/synthetic/src/model.rs b/synthetic/src/model.rs index 2bb5b4cf8b..eb0d7a2200 100644 --- a/synthetic/src/model.rs +++ b/synthetic/src/model.rs @@ -1,4 +1,4 @@ -use abstutil::{read_binary, MultiMap, Timer}; +use abstutil::{read_binary, Timer}; use ezgui::world::{Object, ObjectID, World}; use ezgui::{Color, EventCtx, GfxCtx, Line, Prerender, Text}; use geom::{Bounds, Circle, Distance, PolyLine, Polygon, Pt2D}; @@ -22,9 +22,6 @@ const BACKWARDS: Direction = false; pub struct Model { pub map: raw_data::Map, - roads_per_intersection: MultiMap, - // Never reuse IDs, and don't worry about being sequential - id_counter: usize, all_fixes: BTreeMap, // TODO Not sure this should be pub... pub showing_pts: Option, @@ -39,8 +36,6 @@ impl Model { pub fn blank() -> Model { Model { map: raw_data::Map::blank(String::new()), - roads_per_intersection: MultiMap::new(), - id_counter: 0, all_fixes: BTreeMap::new(), showing_pts: None, @@ -80,21 +75,6 @@ impl Model { } } - for id in model.map.buildings.keys() { - model.id_counter = model.id_counter.max(id.0 + 1); - } - - for id in model.map.intersections.keys() { - model.id_counter = model.id_counter.max(id.0 + 1); - } - - for (id, r) in &model.map.roads { - model.id_counter = model.id_counter.max(id.0 + 1); - - model.roads_per_intersection.insert(r.i1, *id); - model.roads_per_intersection.insert(r.i2, *id); - } - model.world = World::new(&model.compute_bounds()); if !model.exclude_bldgs { for id in model.map.buildings.keys().cloned().collect::>() { @@ -249,11 +229,9 @@ impl Model { } pub fn create_i(&mut self, point: Pt2D, prerender: &Prerender) { - let id = StableIntersectionID(self.id_counter); - self.id_counter += 1; - self.map.intersections.insert( - id, - raw_data::Intersection { + let id = self + .map + .create_intersection(raw_data::Intersection { point, intersection_type: IntersectionType::StopSign, label: None, @@ -261,8 +239,8 @@ impl Model { point: point.forcibly_to_gps(&self.map.gps_bounds), }, synthetic: true, - }, - ); + }) + .unwrap(); self.intersection_added(id, prerender); } @@ -280,7 +258,7 @@ impl Model { self.intersection_added(id, prerender); // Now update all the roads. - for r in self.roads_per_intersection.get(id).clone() { + for r in self.map.roads_per_intersection(id) { self.road_deleted(r); let road = self.map.roads.get_mut(&r).unwrap(); @@ -313,11 +291,12 @@ impl Model { pub fn toggle_i_type(&mut self, id: StableIntersectionID, prerender: &Prerender) { self.world.delete(ID::Intersection(id)); + let num_roads = self.map.roads_per_intersection(id).len(); let i = self.map.intersections.get_mut(&id).unwrap(); i.intersection_type = match i.intersection_type { IntersectionType::StopSign => IntersectionType::TrafficSignal, IntersectionType::TrafficSignal => { - if self.roads_per_intersection.get(id).len() == 1 { + if num_roads == 1 { IntersectionType::Border } else { IntersectionType::StopSign @@ -330,25 +309,14 @@ impl Model { } pub fn delete_i(&mut self, id: StableIntersectionID) { - if !self.roads_per_intersection.get(id).is_empty() { + let orig = self.map.intersections[&id].orig_id; + if !self.map.can_delete_intersection(id) { println!("Can't delete intersection used by roads"); return; } - let i = self.map.intersections.remove(&id).unwrap(); - + // TODO pass in fixes + let id = self.map.delete_intersection(orig, None).unwrap(); self.world.delete(ID::Intersection(id)); - - if let Some(ref name) = self.edit_fixes { - if !i.synthetic { - self.all_fixes - .get_mut(name) - .unwrap() - .delete_intersections - .push(i.orig_id); - } - } else { - println!("This won't be saved in any MapFixes!"); - } } pub fn get_i_center(&self, id: StableIntersectionID) -> Pt2D { @@ -426,11 +394,10 @@ impl Model { self.map.intersections[&i1].point, self.map.intersections[&i2].point, ]; - let id = StableRoadID(self.id_counter); - self.id_counter += 1; - self.map.roads.insert( - id, - raw_data::Road { + + let id = self + .map + .create_road(raw_data::Road { i1, i2, orig_id: raw_data::OriginalRoad { @@ -441,11 +408,8 @@ impl Model { center_points, osm_tags, osm_way_id: SYNTHETIC_OSM_WAY_ID, - }, - ); - self.roads_per_intersection.insert(i1, id); - self.roads_per_intersection.insert(i2, id); - + }) + .unwrap(); self.road_added(id, prerender); } @@ -554,21 +518,9 @@ impl Model { assert!(self.showing_pts != Some(id)); self.road_deleted(id); - let r = self.map.roads.remove(&id).unwrap(); - self.roads_per_intersection.remove(r.i1, id); - self.roads_per_intersection.remove(r.i2, id); - - if let Some(ref name) = self.edit_fixes { - if r.osm_tags.get(osm::SYNTHETIC) != Some(&"true".to_string()) { - self.all_fixes - .get_mut(name) - .unwrap() - .delete_roads - .push(r.orig_id); - } - } else { - println!("This won't be saved in any MapFixes!"); - } + let orig = self.map.roads[&id].orig_id; + // TODO pass in fixes + self.map.delete_road(orig, None).unwrap(); } pub fn get_road_spec(&self, id: StableRoadID) -> String { @@ -709,53 +661,20 @@ impl Model { } pub fn merge_r(&mut self, id: StableRoadID, prerender: &Prerender) { - // TODO Make sure nothing involved is synthetic. assert!(self.showing_pts != Some(id)); + + // TODO Bit hacky, but we have to do this before doing the mutation, so we know the number + // of lanes and can generate all the IDs. self.road_deleted(id); - let (i1, i2, merged_orig_id) = { - let r = self.map.roads.remove(&id).unwrap(); - self.roads_per_intersection.remove(r.i1, id); - self.roads_per_intersection.remove(r.i2, id); - (r.i1, r.i2, r.orig_id) - }; - let (i1_pt, i1_orig_id_pt) = { - let i = &self.map.intersections[&i1]; - (i.point, i.orig_id.point) - }; + let orig = self.map.roads[&id].orig_id; + // TODO pass fixes + let (_, deleted_i, changed_roads) = self.map.merge_short_road(orig, None).unwrap(); - // Arbitrarily keep i1 and destroy i2. - // TODO Make sure intersection types are the same. Make sure i2 isn't synthetic. - self.map.intersections.remove(&i2).unwrap(); - self.world.delete(ID::Intersection(i2)); - - // Fix up all roads connected to i2. - for fix_id in self.roads_per_intersection.get(i2).clone() { - self.road_deleted(fix_id); - - let mut fix = self.map.roads.get_mut(&fix_id).unwrap(); - if fix.i1 == i2 { - fix.i1 = i1; - fix.center_points[0] = i1_pt; - fix.orig_id.pt1 = i1_orig_id_pt; - } else { - assert_eq!(fix.i2, i2); - fix.i2 = i1; - *fix.center_points.last_mut().unwrap() = i1_pt; - fix.orig_id.pt2 = i1_orig_id_pt; - } - - self.road_added(fix_id, prerender); - } - - if let Some(ref name) = self.edit_fixes { - self.all_fixes - .get_mut(name) - .unwrap() - .merge_short_roads - .push(merged_orig_id); - } else { - println!("This won't be saved in any MapFixes!"); + self.world.delete(ID::Intersection(deleted_i)); + for r in changed_roads { + self.road_deleted(r); + self.road_added(r, prerender); } } } @@ -772,8 +691,7 @@ impl Model { } pub fn create_b(&mut self, center: Pt2D, prerender: &Prerender) { - let id = StableBuildingID(self.id_counter); - self.id_counter += 1; + let id = StableBuildingID(self.map.buildings.keys().max().unwrap().0 + 1); self.map.buildings.insert( id, raw_data::Building {