1 use geom::{Angle, ArrowCap, Distance, PolyLine, Polygon};
2 use map_model::{IntersectionCluster, IntersectionID, LaneID, Map, MovementID, UberTurnGroup};
3 use std::collections::{HashMap, HashSet};
4
5 const TURN_ICON_ARROW_LENGTH: Distance = Distance::const_meters(1.5);
6
7 pub struct DrawMovement {
8 pub id: MovementID,
9 pub block: Polygon,
10 pub arrow: Polygon,
11 }
12
13 impl DrawMovement {
for_i(i: IntersectionID, map: &Map) -> Vec<DrawMovement>14 pub fn for_i(i: IntersectionID, map: &Map) -> Vec<DrawMovement> {
15 // TODO Sort by angle here if we want some consistency
16 let mut offset_per_lane: HashMap<LaneID, usize> = HashMap::new();
17 let mut draw = Vec::new();
18 for movement in map.get_traffic_signal(i).movements.values() {
19 let offset = movement
20 .members
21 .iter()
22 .map(|t| *offset_per_lane.entry(t.src).or_insert(0))
23 .max()
24 .unwrap();
25 let (pl, width) = movement.src_center_and_width(map);
26 let (block, arrow) = make_geom(offset as f64, pl, width, movement.angle);
27 let mut seen_lanes = HashSet::new();
28 for t in &movement.members {
29 if !seen_lanes.contains(&t.src) {
30 *offset_per_lane.get_mut(&t.src).unwrap() = offset + 1;
31 seen_lanes.insert(t.src);
32 }
33 }
34
35 draw.push(DrawMovement {
36 id: movement.id,
37 block,
38 arrow,
39 });
40 }
41 draw
42 }
43 }
44
45 pub struct DrawUberTurnGroup {
46 pub group: UberTurnGroup,
47 pub block: Polygon,
48 pub arrow: Polygon,
49 }
50
51 impl DrawUberTurnGroup {
new(ic: &IntersectionCluster, map: &Map) -> Vec<DrawUberTurnGroup>52 pub fn new(ic: &IntersectionCluster, map: &Map) -> Vec<DrawUberTurnGroup> {
53 let mut offset_per_lane: HashMap<LaneID, usize> = HashMap::new();
54 let mut draw = Vec::new();
55 for group in ic.uber_turn_groups(map) {
56 let offset = group
57 .members
58 .iter()
59 .map(|ut| *offset_per_lane.entry(ut.entry()).or_insert(0))
60 .max()
61 .unwrap();
62 let (pl, width) = group.src_center_and_width(map);
63 let (block, arrow) = make_geom(offset as f64, pl, width, group.angle());
64 let mut seen_lanes = HashSet::new();
65 for ut in &group.members {
66 if !seen_lanes.contains(&ut.entry()) {
67 *offset_per_lane.get_mut(&ut.entry()).unwrap() = offset + 1;
68 seen_lanes.insert(ut.entry());
69 }
70 }
71
72 draw.push(DrawUberTurnGroup {
73 group,
74 block,
75 arrow,
76 });
77 }
78 draw
79 }
80 }
81
82 // Produces (block, arrow)
make_geom(offset: f64, pl: PolyLine, width: Distance, angle: Angle) -> (Polygon, Polygon)83 fn make_geom(offset: f64, pl: PolyLine, width: Distance, angle: Angle) -> (Polygon, Polygon) {
84 let height = TURN_ICON_ARROW_LENGTH;
85 // Always extend the pl first to handle short entry lanes
86 let extension = PolyLine::must_new(vec![
87 pl.last_pt(),
88 pl.last_pt()
89 .project_away(Distance::meters(500.0), pl.last_line().angle()),
90 ]);
91 let pl = pl.must_extend(extension);
92 let slice = pl.exact_slice(offset * height, (offset + 1.0) * height);
93 let block = slice.make_polygons(width);
94
95 let arrow = {
96 let center = slice.middle();
97 PolyLine::must_new(vec![
98 center.project_away(TURN_ICON_ARROW_LENGTH / 2.0, angle.opposite()),
99 center.project_away(TURN_ICON_ARROW_LENGTH / 2.0, angle),
100 ])
101 .make_arrow(Distance::meters(0.5), ArrowCap::Triangle)
102 };
103
104 (block, arrow)
105 }
106