mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 00:12:55 +03:00
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...
This commit is contained in:
parent
0ae0a88abb
commit
b9ac8021d0
@ -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
|
||||
|
||||
|
@ -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<StableRoadID> {
|
||||
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<StableRoadID> {
|
||||
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<StableIntersectionID> {
|
||||
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<StableIntersectionID> {
|
||||
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<StableRoadID> {
|
||||
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<StableRoadID>)> {
|
||||
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<String, String>,
|
||||
) -> Option<StableRoadID> {
|
||||
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.
|
||||
|
@ -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<StableIntersectionID, StableRoadID>,
|
||||
// Never reuse IDs, and don't worry about being sequential
|
||||
id_counter: usize,
|
||||
all_fixes: BTreeMap<String, MapFixes>,
|
||||
// TODO Not sure this should be pub...
|
||||
pub showing_pts: Option<StableRoadID>,
|
||||
@ -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::<Vec<_>>() {
|
||||
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user