diff --git a/osm2streets/src/operations/mod.rs b/osm2streets/src/operations/mod.rs index c7b5bc35..8c174c75 100644 --- a/osm2streets/src/operations/mod.rs +++ b/osm2streets/src/operations/mod.rs @@ -2,3 +2,4 @@ mod collapse_intersection; mod collapse_short_road; +mod update_geometry; diff --git a/osm2streets/src/operations/update_geometry.rs b/osm2streets/src/operations/update_geometry.rs new file mode 100644 index 00000000..42d425be --- /dev/null +++ b/osm2streets/src/operations/update_geometry.rs @@ -0,0 +1,66 @@ +use geom::{Circle, Distance}; + +use crate::{IntersectionID, Road, StreetNetwork}; + +impl StreetNetwork { + /// Recalculates trim distances and intersection geometry. This is idempotent; it doesn't use + /// any results from the previous call. + pub fn update_geometry(&mut self, id: IntersectionID) { + let i = &self.intersections[&id]; + + // Update the polygon and Set trim distances for roads + let input_roads = i + .roads + .iter() + .map(|r| self.roads[r].to_input_road(self.config.driving_side)) + .collect::>(); + match crate::intersection_polygon(i.id, input_roads, &i.trim_roads_for_merging) { + Ok(results) => { + self.intersections.get_mut(&id).unwrap().polygon = results.intersection_polygon; + + for (r, dist) in results.trim_starts { + self.roads.get_mut(&r).unwrap().trim_start = dist; + } + for (r, dist) in results.trim_ends { + self.roads.get_mut(&r).unwrap().trim_end = dist; + } + for (pt, label) in results.debug { + self.debug_point(pt, label); + } + } + Err(err) => { + error!("Can't make intersection geometry for {}: {}", i.id, err); + + let r = i.roads[0]; + // Don't trim lines back at all + let road = &self.roads[&r]; + let pt = if road.src_i == i.id { + road.center_line.first_pt() + } else { + road.center_line.last_pt() + }; + self.intersections.get_mut(&id).unwrap().polygon = + Circle::new(pt, Distance::meters(3.0)).to_polygon(); + } + } + + // Update road center lines based on the trim. Note update_geometry works on one + // intersection at a time, so it's possible some roads haven't been trimmed yet on the + // other side. + for r in &self.intersections[&id].roads { + let road = self.roads.get_mut(r).unwrap(); + + let untrimmed = road.get_untrimmed_center_line(self.config.driving_side); + if let Some(pl) = + Road::trim_polyline_both_ends(untrimmed.clone(), road.trim_start, road.trim_end) + { + road.center_line = pl; + } else { + error!("{} got trimmed into oblivion, collapse it later", road.id); + road.center_line = untrimmed; + // Collapse it later + road.internal_junction_road = true; + } + } + } +} diff --git a/osm2streets/src/transform/intersection_geometry.rs b/osm2streets/src/transform/intersection_geometry.rs index 70e70b75..b66a9d69 100644 --- a/osm2streets/src/transform/intersection_geometry.rs +++ b/osm2streets/src/transform/intersection_geometry.rs @@ -1,68 +1,16 @@ use abstutil::Timer; -use geom::{Circle, Distance}; -use crate::{Road, StreetNetwork}; +use crate::StreetNetwork; pub fn generate(streets: &mut StreetNetwork, timer: &mut Timer) { timer.start_iter( "find each intersection polygon", streets.intersections.len(), ); - // It'd be nice to mutate in the loop, but the borrow checker won't let us - let mut set_polygons = Vec::new(); - // Set trim distances for all roads - for i in streets.intersections.values() { + let ids = streets.intersections.keys().cloned().collect::>(); + for i in ids { timer.next(); - let input_roads = i - .roads - .iter() - .map(|r| streets.roads[r].to_input_road(streets.config.driving_side)) - .collect::>(); - match crate::intersection_polygon(i.id, input_roads, &i.trim_roads_for_merging) { - Ok(results) => { - set_polygons.push((i.id, results.intersection_polygon)); - for (r, dist) in results.trim_starts { - streets.roads.get_mut(&r).unwrap().trim_start = dist; - } - for (r, dist) in results.trim_ends { - streets.roads.get_mut(&r).unwrap().trim_end = dist; - } - for (pt, label) in results.debug { - streets.debug_point(pt, label); - } - } - Err(err) => { - error!("Can't make intersection geometry for {}: {}", i.id, err); - - let r = i.roads[0]; - // Don't trim lines back at all - let road = &streets.roads[&r]; - let pt = if road.src_i == i.id { - road.center_line.first_pt() - } else { - road.center_line.last_pt() - }; - set_polygons.push((i.id, Circle::new(pt, Distance::meters(3.0)).to_polygon())); - } - } - } - - for road in streets.roads.values_mut() { - let untrimmed = road.get_untrimmed_center_line(streets.config.driving_side); - if let Some(pl) = - Road::trim_polyline_both_ends(untrimmed.clone(), road.trim_start, road.trim_end) - { - road.center_line = pl; - } else { - error!("{} got trimmed into oblivion, collapse it later", road.id); - road.center_line = untrimmed; - // Collapse it later - road.internal_junction_road = true; - } - } - - for (i, polygon) in set_polygons { - streets.intersections.get_mut(&i).unwrap().polygon = polygon; + streets.update_geometry(i); } }