mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-24 01:15:12 +03:00
Try tracing paths more precisely along road edges, even with changing widths. Use in the experimental bus tool. It needs work, but solid start.
This commit is contained in:
parent
6aa71539a5
commit
1c05a99969
@ -2,12 +2,11 @@ use abstutil::prettyprint_usize;
|
||||
use geom::Duration;
|
||||
use map_gui::tools::{InputWaypoints, WaypointID};
|
||||
use map_model::connectivity::WalkingOptions;
|
||||
use map_model::NORMAL_LANE_THICKNESS;
|
||||
use synthpop::{TripEndpoint, TripMode};
|
||||
use widgetry::mapspace::{ObjectID, World, WorldOutcome};
|
||||
use widgetry::{
|
||||
Color, EventCtx, GfxCtx, HorizontalAlignment, Line, Panel, State, Text, Transition,
|
||||
VerticalAlignment, Widget,
|
||||
Color, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, Outcome, Panel, State, Text,
|
||||
Transition, VerticalAlignment, Widget,
|
||||
};
|
||||
|
||||
use crate::isochrone::{Isochrone, MovementOptions, Options};
|
||||
@ -50,10 +49,10 @@ impl BusExperiment {
|
||||
.and_then(|req| map.pathfind(req).ok())
|
||||
{
|
||||
let duration = path.estimate_duration(map, None);
|
||||
if let Some(pl) = path.trace(map) {
|
||||
if let Ok(hitbox) = path.trace_v2(map) {
|
||||
world
|
||||
.add(ID::BusRoute(idx))
|
||||
.hitbox(pl.make_polygons(5.0 * NORMAL_LANE_THICKNESS))
|
||||
.hitbox(hitbox)
|
||||
.zorder(0)
|
||||
.draw_color(self.waypoints.get_waypoint_color(idx))
|
||||
.hover_alpha(0.8)
|
||||
@ -78,12 +77,13 @@ impl BusExperiment {
|
||||
stops,
|
||||
Options {
|
||||
movement: MovementOptions::Walking(WalkingOptions::default()),
|
||||
thresholds: vec![(Duration::minutes(15), Color::grey(0.3).alpha(0.5))],
|
||||
// TODO The inner colors overlap the outer; this doesn't look right yet
|
||||
thresholds: vec![
|
||||
/*thresholds: vec![
|
||||
(Duration::minutes(5), Color::grey(0.3).alpha(0.5)),
|
||||
(Duration::minutes(10), Color::grey(0.3).alpha(0.3)),
|
||||
(Duration::minutes(15), Color::grey(0.3).alpha(0.2)),
|
||||
],
|
||||
],*/
|
||||
},
|
||||
);
|
||||
world.draw_master_batch_built(isochrone.draw);
|
||||
@ -94,6 +94,10 @@ impl BusExperiment {
|
||||
|
||||
self.panel = Panel::new_builder(Widget::col(vec![
|
||||
map_gui::tools::app_header(ctx, app, "Bus planner"),
|
||||
ctx.style()
|
||||
.btn_back("15-minute neighborhoods")
|
||||
.hotkey(Key::Escape)
|
||||
.build_def(ctx),
|
||||
Text::from_multiline(vec![
|
||||
Line("Within a 15 min walk of all stops:"),
|
||||
Line(format!(
|
||||
@ -124,6 +128,12 @@ impl BusExperiment {
|
||||
impl State<App> for BusExperiment {
|
||||
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition<App> {
|
||||
let panel_outcome = self.panel.event(ctx);
|
||||
if let Outcome::Clicked(ref x) = panel_outcome {
|
||||
if x == "15-minute neighborhoods" {
|
||||
return Transition::Pop;
|
||||
}
|
||||
}
|
||||
|
||||
let world_outcome = self.world.event(ctx);
|
||||
let world_outcome_for_waypoints = world_outcome
|
||||
.maybe_map_id(|id| match id {
|
||||
|
@ -126,8 +126,8 @@ impl State<App> for Viewer {
|
||||
|
||||
match self.panel.event(ctx) {
|
||||
Outcome::Clicked(x) => match x.as_ref() {
|
||||
"Bus sketch" => {
|
||||
return Transition::Replace(crate::bus::BusExperiment::new_state(ctx, app));
|
||||
"Sketch bus route (experimental)" => {
|
||||
return Transition::Push(crate::bus::BusExperiment::new_state(ctx, app));
|
||||
}
|
||||
"Home" => {
|
||||
return Transition::Pop;
|
||||
@ -291,7 +291,7 @@ fn build_panel(ctx: &mut EventCtx, app: &App, start: &Building, isochrone: &Isoc
|
||||
map_gui::tools::app_header(ctx, app, "15-minute neighborhood explorer"),
|
||||
ctx.style()
|
||||
.btn_outline
|
||||
.text("Bus sketch")
|
||||
.text("Sketch bus route (experimental)")
|
||||
.hotkey(Key::B)
|
||||
.build_def(ctx),
|
||||
Text::from_all(vec![
|
||||
|
@ -39,10 +39,17 @@ impl Ring {
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn must_new(pts: Vec<Pt2D>) -> Ring {
|
||||
Ring::new(pts).unwrap()
|
||||
}
|
||||
|
||||
/// First dedupes adjacent points
|
||||
pub fn deduping_new(mut pts: Vec<Pt2D>) -> Result<Self> {
|
||||
pts.dedup();
|
||||
Self::new(pts)
|
||||
}
|
||||
|
||||
/// Draws the ring with some thickness, with half of it straddling the interor of the ring, and
|
||||
/// half on the outside.
|
||||
pub fn to_outline(&self, thickness: Distance) -> Polygon {
|
||||
|
@ -5,7 +5,7 @@ use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use abstutil::prettyprint_usize;
|
||||
use geom::{Distance, Duration, PolyLine, Speed, EPSILON_DIST};
|
||||
use geom::{Distance, Duration, PolyLine, Polygon, Ring, Speed, EPSILON_DIST};
|
||||
|
||||
use crate::{
|
||||
BuildingID, DirectedRoadID, LaneID, Map, PathConstraints, Position, Traversable, TurnID,
|
||||
@ -468,6 +468,38 @@ impl Path {
|
||||
Some(pts_so_far.unwrap())
|
||||
}
|
||||
|
||||
/// Draws the thickened path, matching entire roads. Ignores the path's exact starting and
|
||||
/// ending distance.
|
||||
pub fn trace_v2(&self, map: &Map) -> Result<Polygon> {
|
||||
let mut left_pts = Vec::new();
|
||||
let mut right_pts = Vec::new();
|
||||
for step in &self.steps {
|
||||
match step {
|
||||
PathStep::Lane(l) => {
|
||||
let road = map.get_parent(*l);
|
||||
let width = road.get_half_width();
|
||||
if map.get_l(*l).dst_i == road.dst_i {
|
||||
left_pts.extend(road.center_pts.shift_left(width)?.into_points());
|
||||
right_pts.extend(road.center_pts.shift_right(width)?.into_points());
|
||||
} else {
|
||||
left_pts
|
||||
.extend(road.center_pts.shift_right(width)?.reversed().into_points());
|
||||
right_pts
|
||||
.extend(road.center_pts.shift_left(width)?.reversed().into_points());
|
||||
}
|
||||
}
|
||||
PathStep::ContraflowLane(_) => todo!(),
|
||||
// Just make a straight line across the intersection. It'd be fancier to try and
|
||||
// trace along.
|
||||
PathStep::Turn(_) | PathStep::ContraflowTurn(_) => {}
|
||||
}
|
||||
}
|
||||
right_pts.reverse();
|
||||
left_pts.extend(right_pts);
|
||||
left_pts.push(left_pts[0]);
|
||||
Ok(Ring::deduping_new(left_pts)?.into_polygon())
|
||||
}
|
||||
|
||||
pub fn get_steps(&self) -> &VecDeque<PathStep> {
|
||||
&self.steps
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user