From 01a4abb64ab5cfde50f878b7ab875f9e77dac0c4 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Fri, 24 May 2019 16:01:00 -0700 Subject: [PATCH] work around path traces that're breaking PolyLine --- editor/src/debug/mod.rs | 2 +- editor/src/mission/all_trips.rs | 2 +- editor/src/mission/individ_trips.rs | 2 +- editor/src/mission/mod.rs | 11 ++++++++++- geom/src/polyline.rs | 24 ++++++++++++++++-------- map_model/src/make/initial/merge.rs | 4 ++-- map_model/src/pathfind/mod.rs | 12 ++++++++++-- popdat/src/main.rs | 2 ++ 8 files changed, 43 insertions(+), 16 deletions(-) diff --git a/editor/src/debug/mod.rs b/editor/src/debug/mod.rs index a4b00a3a19..cb2437cd7f 100644 --- a/editor/src/debug/mod.rs +++ b/editor/src/debug/mod.rs @@ -467,7 +467,7 @@ fn recalc_intersection_geom(id: IntersectionID, map: &Map, g: &mut GfxCtx) { let (pl1, width1) = wraparound_get(&road_centers, idx); let (pl2, width2) = wraparound_get(&road_centers, idx + 1); - let glued = pl1.clone().extend(&pl2.reversed()); + let glued = pl1.clone().extend(&pl2.reversed()).unwrap(); let max_width = (*width1).max(*width2); let poly = Polygon::new(&glued.to_thick_boundary_pts(max_width)); g.draw_polygon(Color::RED.alpha(0.4), &poly); diff --git a/editor/src/mission/all_trips.rs b/editor/src/mission/all_trips.rs index eff7b9959f..887ff45f37 100644 --- a/editor/src/mission/all_trips.rs +++ b/editor/src/mission/all_trips.rs @@ -21,7 +21,7 @@ impl TripsVisualizer { let trips = ctx.loading_screen("load trip data", |_, mut timer| { let popdat: PopDat = abstutil::read_binary("../data/shapes/popdat", &mut timer) .expect("Couldn't load popdat"); - let mut all_trips = clip_trips(&popdat, ui, &mut timer); + let mut all_trips = clip_trips(&popdat, ui, 1_000, &mut timer); let requests = all_trips .iter() .map(|trip| trip.path_req(&ui.primary.map)) diff --git a/editor/src/mission/individ_trips.rs b/editor/src/mission/individ_trips.rs index a6ec7157f8..82e6c87fca 100644 --- a/editor/src/mission/individ_trips.rs +++ b/editor/src/mission/individ_trips.rs @@ -30,7 +30,7 @@ impl TripsVisualizer { ], ctx, ), - trips: clip_trips(&popdat, ui, &mut timer), + trips: clip_trips(&popdat, ui, 10_000, &mut timer), // TODO We'll break if there are no matching trips current: 0, } diff --git a/editor/src/mission/mod.rs b/editor/src/mission/mod.rs index 51d71be2a5..11c2a7966f 100644 --- a/editor/src/mission/mod.rs +++ b/editor/src/mission/mod.rs @@ -190,12 +190,21 @@ impl Trip { } } -pub fn clip_trips(popdat: &popdat::PopDat, ui: &UI, timer: &mut Timer) -> Vec { +// TODO max_results just temporary for development. +pub fn clip_trips( + popdat: &popdat::PopDat, + ui: &UI, + max_results: usize, + timer: &mut Timer, +) -> Vec { let mut results = Vec::new(); let bounds = ui.primary.map.get_gps_bounds(); timer.start_iter("clip trips", popdat.trips.len()); for trip in &popdat.trips { timer.next(); + if results.len() == max_results { + continue; + } if !bounds.contains(trip.from) || !bounds.contains(trip.to) { continue; } diff --git a/geom/src/polyline.rs b/geom/src/polyline.rs index 7c5d6803ff..32687b90df 100644 --- a/geom/src/polyline.rs +++ b/geom/src/polyline.rs @@ -38,11 +38,7 @@ impl PolyLine { // Can't have duplicates! If the polyline ever crosses back on itself, all sorts of things // are broken. - let seen_pts: HashSet = result - .points() - .iter() - .map(|pt| HashablePt2D::from(*pt)) - .collect(); + let seen_pts = to_set(result.points()); if seen_pts.len() != result.points().len() { panic!("PolyLine has repeat points: {}", result); } @@ -95,10 +91,17 @@ impl PolyLine { PolyLine::new(pts) } - // TODO Rename append, make a prepend that just flips the arguments - pub fn extend(self, other: &PolyLine) -> PolyLine { + // Returns None if the two have any duplicate points (besides the last->first). + pub fn extend(self, other: &PolyLine) -> Option { assert_eq!(*self.pts.last().unwrap(), other.pts[0]); + let pl1 = to_set(self.points()); + let pl2 = to_set(&other.points()[1..]); + if pl1.intersection(&pl2).next().is_some() { + println!("Can't append, duplicate points... {} and {}", self, other); + return None; + } + // There's an exciting edge case: the next point to add is on self's last line. let same_line = self .last_line() @@ -109,7 +112,7 @@ impl PolyLine { pts.pop(); } pts.extend(other.pts.iter().skip(1)); - PolyLine::new(pts) + Some(PolyLine::new(pts)) } // One or both args might be empty. @@ -123,6 +126,7 @@ impl PolyLine { PolyLine::new(first) .extend(&PolyLine::new(second)) + .unwrap() .points() .clone() } @@ -653,3 +657,7 @@ fn check_angles(orig: &PolyLine, fixed: PolyLine) -> Warn { } Warn::warnings(fixed, warnings) } + +fn to_set(pts: &[Pt2D]) -> HashSet { + pts.iter().map(|pt| HashablePt2D::from(*pt)).collect() +} diff --git a/map_model/src/make/initial/merge.rs b/map_model/src/make/initial/merge.rs index 312a68c5a2..7b5eb022f3 100644 --- a/map_model/src/make/initial/merge.rs +++ b/map_model/src/make/initial/merge.rs @@ -128,14 +128,14 @@ fn merge( .original_center_pts .get_slice_starting_at(r.trimmed_center_pts.last_pt()) { - r.trimmed_center_pts = r.trimmed_center_pts.clone().extend(&append); + r.trimmed_center_pts = r.trimmed_center_pts.clone().extend(&append).unwrap(); } } else { if let Some(prepend) = r .original_center_pts .get_slice_ending_at(r.trimmed_center_pts.first_pt()) { - r.trimmed_center_pts = prepend.extend(&r.trimmed_center_pts); + r.trimmed_center_pts = prepend.extend(&r.trimmed_center_pts).unwrap(); } } } diff --git a/map_model/src/pathfind/mod.rs b/map_model/src/pathfind/mod.rs index 2dfc4d7346..36aae1f807 100644 --- a/map_model/src/pathfind/mod.rs +++ b/map_model/src/pathfind/mod.rs @@ -215,8 +215,16 @@ impl Path { self.steps[i].slice(map, start_dist_this_step, dist_remaining) { if pts_so_far.is_some() { - let pts = pts_so_far.unwrap().extend(&new_pts); - pts_so_far = Some(pts); + if let Some(pts) = pts_so_far.unwrap().extend(&new_pts) { + pts_so_far = Some(pts); + } else { + println!( + "Adding {:?} to {:?} causes duplicate points!", + self.steps[i], + self.steps.iter().take(i).collect::>() + ); + return None; + } } else { pts_so_far = Some(new_pts); } diff --git a/popdat/src/main.rs b/popdat/src/main.rs index b0725e126a..710e7a81ef 100644 --- a/popdat/src/main.rs +++ b/popdat/src/main.rs @@ -3,6 +3,8 @@ fn main() { let mut popdat = popdat::PopDat::import_all(&mut timer); // TODO Productionize this. + // https://file.ac/cLdO7Hp_OB0/ has trips_2014.csv. https://file.ac/Xdjmi8lb2dA/ has the 2014 + // inputs. let parcels = popdat::psrc::import_parcels( "/home/dabreegster/Downloads/psrc/2014/landuse/parcels_urbansim.txt", &mut timer,