Skip to content

Commit

Permalink
WIP improvements for placement of turn restriction icons
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewphilipsmith committed Nov 14, 2023
1 parent 8dafe10 commit 5e50d88
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 17 deletions.
35 changes: 22 additions & 13 deletions apps/ltn/src/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ mod cells;
pub mod colors;
mod filters;

use std::collections::HashMap;

use geom::{Angle, Distance, Pt2D};
use map_model::{AmenityType, ExtraPOIType, FilterType, Map, RestrictionType, Road, TurnType};
use map_model::{AmenityType, ExtraPOIType, FilterType, Map, RestrictionType, Road, TurnType, RoadID};
use widgetry::mapspace::DrawCustomUnzoomedShapes;
use widgetry::{Color, Drawable, EventCtx, GeomBatch, GfxCtx, Line, RewriteColor, Text};

Expand Down Expand Up @@ -77,35 +79,42 @@ pub fn render_bus_routes(ctx: &EventCtx, map: &Map) -> Drawable {
ctx.upload(batch)
}


pub fn render_turn_restrictions(ctx: &EventCtx, map: &Map) -> Drawable {
let mut batch = GeomBatch::new();
for r1 in map.all_roads() {
// TODO Also interpret lane-level? Maybe just check all the generated turns and see what's
// allowed / banned in practice?

// Count the number of turn restrictions at each end of the road
let mut icon_counter = HashMap::from([
(r1.dst_i, 1),
(r1.src_i, 1),
]);

for (restriction, r2) in &r1.turn_restrictions {
// TODO "Invert" OnlyAllowTurns so we can just draw banned things
if *restriction == RestrictionType::BanTurns {
batch.append(draw_restriction(ctx, map, r1, map.get_r(*r2)));
let (t_type, sign_pt, r1_angle, i) = map.get_ban_turn_info(r1, map.get_r(*r2), &icon_counter);
// add to the counter
icon_counter.entry(i).and_modify(|n| *n+=1);
batch.append(draw_turn_restriction_icon(
ctx, t_type, sign_pt, r1, r1_angle,
));
}
}
for (_via, r2) in &r1.complicated_turn_restrictions {
// TODO Show the 'via'? Or just draw the entire shape?
batch.append(draw_restriction(ctx, map, r1, map.get_r(*r2)));
let (t_type, sign_pt, r1_angle, i) = map.get_ban_turn_info(r1, map.get_r(*r2), &icon_counter);
icon_counter.entry(i).and_modify(|n| *n+=1);
batch.append(draw_turn_restriction_icon(
ctx, t_type, sign_pt, r1, r1_angle,
));
}
}
ctx.upload(batch)
}

fn draw_restriction(ctx: &EventCtx, map: &Map, r1: &Road, r2: &Road) -> GeomBatch {
let mut batch = GeomBatch::new();
// TODO: remove/name this wrapper, which is just for debugging svg icon placement/rotation
let (t_type, sign_pt, r1_angle, _) = map.get_ban_turn_info(r1, r2);
batch.append(draw_turn_restriction_icon(
ctx, t_type, sign_pt, r1, r1_angle,
));
batch
}

fn draw_turn_restriction_icon(
ctx: &EventCtx,
t_type: TurnType,
Expand Down
20 changes: 18 additions & 2 deletions map_model/src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,7 @@ impl Map {
&self,
r1: &Road,
r2: &Road,
icon_counter: &HashMap<IntersectionID, i32>,
) -> (TurnType, Pt2D, Angle, IntersectionID) {
// Determine where to place the symbol
let i = match r1.common_endpoint(r2) {
Expand All @@ -1126,10 +1127,25 @@ impl Map {
}
};

// Determine what type of turn is it?
// Determine where to place and orientate the icon
let sign_count = *icon_counter.get(&i).unwrap_or(&1);
let mut ideal_dist_from_intersection = sign_count as f64 * 1.1 * r1.get_width();
if 2.0 * ideal_dist_from_intersection > r1.center_pts.length() {
// We've run out of space on the road to fit all of the icons on. We will just pile them up where we can
// Next try near the end of the stack, but just still in the appropriate half of the road
ideal_dist_from_intersection = 0.5 * (r1.center_pts.length() - r1.get_width());
if ideal_dist_from_intersection < Distance::ZERO {
// The road is wider than it is long, so just squeeze them in:
ideal_dist_from_intersection = 0.3 * r1.center_pts.length();
}
}

// Adjust according to which end of the road we've measuring from
let dist_from_intersection = if r1.src_i == i { ideal_dist_from_intersection } else { r1.center_pts.length() - ideal_dist_from_intersection };

let (sign_pt, mut r1_angle) = r1
.center_pts
.must_dist_along((if r1.src_i == i { 0.2 } else { 0.8 }) * r1.center_pts.length());
.must_dist_along(dist_from_intersection);

// Correct the angle, based on whether the vector direction is towards or away from the intersection
// TODO what is the standard way of describing the vector direction (rather than the traffic direction) for roads?
Expand Down
10 changes: 8 additions & 2 deletions tests/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Integration tests
use std::io::Write;
use std::{io::Write, collections::HashMap};

use anyhow::{bail, Result};
use fs_err::File;
Expand Down Expand Up @@ -113,8 +113,14 @@ fn all_turn_info_as_string(map: &Map) -> String {

s.push_str("\n------------\nRestrictions:\n------------\n");
for r1 in map.all_roads() {

let icon_counter = HashMap::from([
(r1.dst_i, 1),
(r1.src_i, 1),
]);

for (restriction, r2) in &r1.turn_restrictions {
let (t_type, sign_pt, _, i_id) = map.get_ban_turn_info(r1, map.get_r(*r2));
let (t_type, sign_pt, _, i_id) = map.get_ban_turn_info(r1, map.get_r(*r2), &icon_counter);
let i = map.get_i(i_id);
s.push_str(&format!(
"Turn from {} into {}, at intersection {:?} is a {:?}, type {:?}, location {}\n",
Expand Down

0 comments on commit 5e50d88

Please sign in to comment.