Draw arrows to show entrances/exits to a LTN.

(and rename Line::reverse for consistency with PolyLine)
This commit is contained in:
Dustin Carlino 2021-10-29 12:25:30 -07:00
parent e62a41d45b
commit 32fc46831b
6 changed files with 37 additions and 11 deletions

View File

@ -1,6 +1,6 @@
use std::collections::BTreeSet; use std::collections::BTreeSet;
use geom::{Distance, Line}; use geom::{Distance, Line, PolyLine, Polygon};
use map_gui::tools::{CityPicker, ColorDiscrete}; use map_gui::tools::{CityPicker, ColorDiscrete};
use map_gui::ID; use map_gui::ID;
use map_model::{IntersectionID, Map, Road, RoadID}; use map_model::{IntersectionID, Map, Road, RoadID};
@ -242,7 +242,6 @@ impl Neighborhood {
vec![ vec![
("interior", Color::BLUE.alpha(0.8)), ("interior", Color::BLUE.alpha(0.8)),
("perimeter", Color::hex("#40B5AD").alpha(0.8)), ("perimeter", Color::hex("#40B5AD").alpha(0.8)),
("border", Color::CYAN.alpha(0.8)),
("rat-run", Color::RED.alpha(0.8)), ("rat-run", Color::RED.alpha(0.8)),
("modal filter", Color::GREEN), ("modal filter", Color::GREEN),
], ],
@ -257,10 +256,37 @@ impl Neighborhood {
colorer.add_r(*r, "perimeter"); colorer.add_r(*r, "perimeter");
} }
for i in &self.borders { for i in &self.borders {
colorer.add_i(*i, "border"); // TODO These should have a higher z-order than rat runs
let arrow = self.border_arrow(&app.primary.map, *i);
colorer.unzoomed.push(Color::PURPLE, arrow.clone());
colorer.zoomed.push(Color::PURPLE, arrow.clone());
} }
colorer.build(ctx) colorer.build(ctx)
} }
fn border_arrow(&self, map: &Map, i: IntersectionID) -> Polygon {
assert!(self.borders.contains(&i));
// Multiple interior roads could connect to one border, but let's just use one (the common
// case anyway)
let road = map.get_r(
*map.get_i(i)
.roads
.iter()
.find(|r| self.interior.contains(r))
.unwrap(),
);
let line = if road.dst_i == i {
road.center_pts.last_line()
} else {
road.center_pts.first_line().reversed()
};
PolyLine::must_new(vec![
line.pt2(),
line.pt2()
.project_away(Distance::meters(30.0), line.angle()),
])
.make_double_arrow(Distance::meters(5.0), geom::ArrowCap::Triangle)
}
} }
impl RatRun { impl RatRun {

View File

@ -142,7 +142,7 @@ impl Line {
} }
/// Returns a reversed line segment /// Returns a reversed line segment
pub fn reverse(&self) -> Line { pub fn reversed(&self) -> Line {
Line::must_new(self.pt2(), self.pt1()) Line::must_new(self.pt2(), self.pt1())
} }

View File

@ -354,7 +354,7 @@ fn calculate_corner_curbs(i: &Intersection, map: &Map) -> Vec<Polygon> {
let first_line = l2.first_line().shift_either_direction(width); let first_line = l2.first_line().shift_either_direction(width);
pts.push(first_line.pt1()); pts.push(first_line.pt1());
pts.push(first_line.unbounded_dist_along(thickness)); pts.push(first_line.unbounded_dist_along(thickness));
let last_line = l1.last_line().shift_either_direction(width).reverse(); let last_line = l1.last_line().shift_either_direction(width).reversed();
pts.insert(0, last_line.pt1()); pts.insert(0, last_line.pt1());
pts.insert(0, last_line.unbounded_dist_along(thickness)); pts.insert(0, last_line.unbounded_dist_along(thickness));
PolyLine::deduping_new(pts).ok() PolyLine::deduping_new(pts).ok()
@ -375,7 +375,7 @@ fn calculate_corner_curbs(i: &Intersection, map: &Map) -> Vec<Polygon> {
.first_line() .first_line()
.shift_either_direction(direction * shift(l2.width)); .shift_either_direction(direction * shift(l2.width));
if let Ok(pl) = PolyLine::deduping_new(vec![ if let Ok(pl) = PolyLine::deduping_new(vec![
last_line.reverse().unbounded_dist_along(thickness), last_line.reversed().unbounded_dist_along(thickness),
last_line.pt2(), last_line.pt2(),
first_line.pt1(), first_line.pt1(),
first_line.unbounded_dist_along(thickness), first_line.unbounded_dist_along(thickness),
@ -409,7 +409,7 @@ fn calculate_border_arrows(i: &Intersection, r: &Road, map: &Map) -> Vec<Polygon
if !i.outgoing_lanes.is_empty() { if !i.outgoing_lanes.is_empty() {
let (line, width) = if r.dst_i == i.id { let (line, width) = if r.dst_i == i.id {
( (
center.last_line().shift_left(width_back / 2.0).reverse(), center.last_line().shift_left(width_back / 2.0).reversed(),
width_back, width_back,
) )
} else { } else {
@ -429,7 +429,7 @@ fn calculate_border_arrows(i: &Intersection, r: &Road, map: &Map) -> Vec<Polygon
if !i.incoming_lanes.is_empty() { if !i.incoming_lanes.is_empty() {
let (line, width) = if r.dst_i == i.id { let (line, width) = if r.dst_i == i.id {
( (
center.last_line().shift_right(width_fwd / 2.0).reverse(), center.last_line().shift_right(width_fwd / 2.0).reversed(),
width_fwd, width_fwd,
) )
} else { } else {

View File

@ -232,7 +232,7 @@ fn curvey_turn(src: &Lane, dst: &Lane) -> Result<PolyLine> {
// The control points are straight out/in from the source/destination lanes, so // The control points are straight out/in from the source/destination lanes, so
// that the car exits and enters at the same angle as the road. // that the car exits and enters at the same angle as the road.
let src_line = src.last_line(); let src_line = src.last_line();
let dst_line = dst.first_line().reverse(); let dst_line = dst.first_line().reversed();
// TODO Tune the 5.0 and pieces // TODO Tune the 5.0 and pieces
let pt1 = src.last_pt(); let pt1 = src.last_pt();

View File

@ -291,7 +291,7 @@ impl Lane {
/// pt2 will be endpoint /// pt2 will be endpoint
pub fn end_line(&self, i: IntersectionID) -> Line { pub fn end_line(&self, i: IntersectionID) -> Line {
if i == self.src_i { if i == self.src_i {
self.first_line().reverse() self.first_line().reversed()
} else if i == self.dst_i { } else if i == self.dst_i {
self.last_line() self.last_line()
} else { } else {

View File

@ -743,7 +743,7 @@ impl Pedestrian {
PedState::EnteringParkingLot(pl, ref time_int) => { PedState::EnteringParkingLot(pl, ref time_int) => {
let line = &map.get_pl(pl).sidewalk_line; let line = &map.get_pl(pl).sidewalk_line;
( (
line.reverse() line.reversed()
.percent_along(time_int.percent(now)) .percent_along(time_int.percent(now))
.unwrap_or_else(|| line.pt1()), .unwrap_or_else(|| line.pt1()),
line.angle().opposite(), line.angle().opposite(),