Draw partly overlapping paths in the LTN route tool using a new idea. #884 (#939)

Just divide each road segment by the number of colors needed.
Intersections aren't handled yet.
This commit is contained in:
Dustin Carlino 2022-06-10 15:42:33 +01:00 committed by GitHub
parent 54e240f2c0
commit 5bf9790dbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 68 additions and 48 deletions

View File

@ -0,0 +1,48 @@
use std::collections::BTreeMap;
use map_model::{PathStepV2, PathV2, RoadID};
use widgetry::mapspace::ToggleZoomed;
use widgetry::{Color, EventCtx};
use crate::App;
// TODO Move to map_gui
pub fn draw_overlapping_paths(
ctx: &mut EventCtx,
app: &App,
paths: Vec<(PathV2, Color)>,
) -> ToggleZoomed {
// Per road, just figure out what colors we need
let mut colors_per_road: BTreeMap<RoadID, Vec<Color>> = BTreeMap::new();
for (path, color) in paths {
for step in path.get_steps() {
match step {
PathStepV2::Along(dr) | PathStepV2::Contraflow(dr) => {
colors_per_road
.entry(dr.road)
.or_insert_with(Vec::new)
.push(color);
}
PathStepV2::Movement(_) | PathStepV2::ContraflowMovement(_) => {
// TODO Intersections?
}
}
}
}
// Per road, divide the needed colors proportionally
let mut draw = ToggleZoomed::builder();
for (road, colors) in colors_per_road {
let road = app.map.get_r(road);
let width_per_piece = road.get_width() / (colors.len() as f64);
for (idx, color) in colors.into_iter().enumerate() {
if let Ok(pl) = road.shift_from_left_side((0.5 + (idx as f64)) * width_per_piece) {
let polygon = pl.make_polygons(width_per_piece);
draw.unzoomed.push(color.alpha(0.8), polygon.clone());
draw.unzoomed.push(color.alpha(0.5), polygon);
}
}
}
draw.build(ctx)
}

View File

@ -23,6 +23,7 @@ mod components;
mod connectivity;
mod customize_boundary;
mod draw_cells;
mod draw_overlapping_paths;
mod edit;
mod export;
mod filters;

View File

@ -1,8 +1,8 @@
use geom::{Distance, Duration};
use geom::Duration;
use map_gui::tools::{
DrawRoadLabels, InputWaypoints, TripManagement, TripManagementState, WaypointID,
};
use map_model::{PathfinderCache, NORMAL_LANE_THICKNESS};
use map_model::{PathV2, PathfinderCache};
use synthpop::{TripEndpoint, TripMode};
use widgetry::mapspace::{ToggleZoomed, World};
use widgetry::{
@ -136,12 +136,12 @@ impl RoutePlanner {
// Returns a widget to display
fn recalculate_paths(&mut self, ctx: &mut EventCtx, app: &App) -> Widget {
let map = &app.map;
let mut draw = ToggleZoomed::builder();
let mut paths: Vec<(PathV2, Color)> = Vec::new();
// The baseline is the one ignoring ALL filters (pre-existing and new)
let baseline_time = {
let mut total_time = Duration::ZERO;
let color = *colors::PLAN_ROUTE_BEFORE;
let mut params = map.routing_params().clone();
params.main_road_penalty = app.session.main_road_penalty;
@ -152,13 +152,8 @@ impl RoutePlanner {
.pathfind_with_params(map, req, params.clone())
})
{
let cost = path.get_cost();
if let Some(pl) = path.into_v1(map).ok().and_then(|path| path.trace(map)) {
let shape = pl.make_polygons(5.0 * NORMAL_LANE_THICKNESS);
draw.unzoomed.push(color.alpha(0.8), shape.clone());
draw.zoomed.push(color.alpha(0.5), shape);
total_time += cost;
}
total_time += path.get_cost();
paths.push((path, *colors::PLAN_ROUTE_BEFORE));
}
}
@ -172,8 +167,7 @@ impl RoutePlanner {
params.main_road_penalty = app.session.main_road_penalty;
let mut total_time = Duration::ZERO;
let mut draw_after = ToggleZoomed::builder();
let color = *colors::PLAN_ROUTE_AFTER;
let mut paths_after = Vec::new();
for pair in self.waypoints.get_waypoints().windows(2) {
if let Some(path) = TripEndpoint::path_req(pair[0], pair[1], TripMode::Drive, map)
.and_then(|req| {
@ -181,18 +175,13 @@ impl RoutePlanner {
.pathfind_with_params(map, req, params.clone())
})
{
let cost = path.get_cost();
if let Some(pl) = path.into_v1(map).ok().and_then(|path| path.trace(map)) {
let shape = pl.make_polygons(5.0 * NORMAL_LANE_THICKNESS);
draw_after.unzoomed.push(color.alpha(0.8), shape.clone());
draw_after.zoomed.push(color.alpha(0.5), shape);
total_time += cost;
}
total_time += path.get_cost();
paths_after.push((path, *colors::PLAN_ROUTE_AFTER));
}
}
// To simplify colors, don't draw this path when it's the same as the baseline
if total_time != baseline_time {
draw.append(draw_after);
paths.append(&mut paths_after);
}
total_time
@ -201,21 +190,12 @@ impl RoutePlanner {
let biking_time = {
// No custom params -- use the map's built-in bike CH
let mut total_time = Duration::ZERO;
let color = *colors::PLAN_ROUTE_BIKE;
for pair in self.waypoints.get_waypoints().windows(2) {
if let Some((path, pl)) =
TripEndpoint::path_req(pair[0], pair[1], TripMode::Bike, map)
.and_then(|req| map.pathfind(req).ok())
.and_then(|path| path.trace(map).map(|pl| (path, pl)))
if let Some(path) = TripEndpoint::path_req(pair[0], pair[1], TripMode::Bike, map)
.and_then(|req| map.pathfind_v2(req).ok())
{
let shape = pl.exact_dashed_polygons(
2.0 * NORMAL_LANE_THICKNESS,
Distance::meters(10.0),
Distance::meters(6.0),
);
draw.unzoomed.extend(color.alpha(0.8), shape.clone());
draw.zoomed.extend(color.alpha(0.5), shape);
total_time += path.estimate_duration(map, Some(map_model::MAX_BIKE_SPEED));
total_time += path.get_cost();
paths.push((path, *colors::PLAN_ROUTE_BIKE));
}
}
total_time
@ -224,27 +204,18 @@ impl RoutePlanner {
let walking_time = {
// No custom params -- use the map's built-in CH
let mut total_time = Duration::ZERO;
let color = *colors::PLAN_ROUTE_WALK;
for pair in self.waypoints.get_waypoints().windows(2) {
if let Some((path, pl)) =
TripEndpoint::path_req(pair[0], pair[1], TripMode::Walk, map)
.and_then(|req| map.pathfind(req).ok())
.and_then(|path| path.trace(map).map(|pl| (path, pl)))
if let Some(path) = TripEndpoint::path_req(pair[0], pair[1], TripMode::Walk, map)
.and_then(|req| map.pathfind_v2(req).ok())
{
let shape = pl.exact_dashed_polygons(
1.5 * NORMAL_LANE_THICKNESS,
Distance::meters(8.0),
Distance::meters(6.0),
);
draw.unzoomed.extend(color.alpha(0.8), shape.clone());
draw.zoomed.extend(color.alpha(0.5), shape);
total_time += path.estimate_duration(map, Some(map_model::MAX_WALKING_SPEED));
total_time += path.get_cost();
paths.push((path, *colors::PLAN_ROUTE_WALK));
}
}
total_time
};
self.draw_routes = draw.build(ctx);
self.draw_routes = crate::draw_overlapping_paths::draw_overlapping_paths(ctx, app, paths);
Widget::col(vec![
Widget::row(vec![