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