map_gui/render/
transit_stop.rs
1use geom::{Angle, Bounds, Circle, Distance, Line, Pt2D, Tessellation};
2use map_model::{Map, TransitStop, TransitStopID};
3use widgetry::{Drawable, EventCtx, GeomBatch, GfxCtx};
4
5use crate::colors::ColorScheme;
6use crate::render::{DrawOptions, Renderable, OUTLINE_THICKNESS};
7use crate::{AppLike, ID};
8
9const RADIUS: Distance = Distance::const_meters(1.0);
10
11pub struct DrawTransitStop {
12 pub id: TransitStopID,
13 center: Pt2D,
14 zorder: isize,
15
16 draw_default: Drawable,
17}
18
19impl DrawTransitStop {
20 pub fn new(ctx: &EventCtx, stop: &TransitStop, map: &Map, cs: &ColorScheme) -> DrawTransitStop {
21 let (pt, angle) = stop.sidewalk_pos.pt_and_angle(map);
22 let center = pt.project_away(
23 map.get_l(stop.sidewalk_pos.lane()).width / 2.0,
24 angle.rotate_degs(90.0),
25 );
26
27 let mut icon = GeomBatch::new();
28 icon.append(
29 GeomBatch::load_svg(
30 ctx.prerender,
31 if stop.is_train_stop {
32 "system/assets/map/light_rail.svg"
33 } else {
34 "system/assets/meters/bus.svg"
35 },
36 )
37 .scale(0.05)
38 .centered_on(center),
39 );
40 let mut batch = GeomBatch::new();
41 batch.push(
42 cs.bus_layer.alpha(0.8),
43 Circle::new(center, RADIUS).to_polygon(),
44 );
45 batch.append(icon.autocrop().centered_on(center));
46 batch.push(
47 cs.stop_sign_pole,
48 Line::must_new(
49 center.project_away(RADIUS, Angle::degrees(90.0)),
50 center.project_away(1.5 * RADIUS, Angle::degrees(90.0)),
51 )
52 .make_polygons(Distance::meters(0.3)),
53 );
54
55 DrawTransitStop {
56 id: stop.id,
57 center,
58 zorder: map.get_parent(stop.sidewalk_pos.lane()).zorder,
59 draw_default: ctx.upload(batch),
60 }
61 }
62}
63
64impl Renderable for DrawTransitStop {
65 fn get_id(&self) -> ID {
66 ID::TransitStop(self.id)
67 }
68
69 fn draw(&self, g: &mut GfxCtx, _: &dyn AppLike, _: &DrawOptions) {
70 g.redraw(&self.draw_default);
71 }
72
73 fn get_outline(&self, _: &Map) -> Tessellation {
74 Tessellation::from(
75 Circle::new(self.center, RADIUS)
76 .to_outline(OUTLINE_THICKNESS)
77 .expect("constants defined wrong"),
78 )
79 }
80
81 fn get_bounds(&self, _: &Map) -> Bounds {
82 Circle::new(self.center, RADIUS).get_bounds()
83 }
84
85 fn contains_pt(&self, pt: Pt2D, _: &Map) -> bool {
86 Circle::new(self.center, RADIUS).contains_pt(pt)
87 }
88
89 fn get_zorder(&self) -> isize {
90 self.zorder
91 }
92}