1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use std::cell::RefCell;
use geom::{Distance, PolyLine, Polygon, Pt2D};
use map_model::{
osm, LaneType, Map, ParkingLot, ParkingLotID, NORMAL_LANE_THICKNESS, PARKING_LOT_SPOT_LENGTH,
};
use widgetry::{Drawable, EventCtx, GeomBatch, GfxCtx};
use crate::colors::ColorScheme;
use crate::render::{DrawOptions, Renderable, OUTLINE_THICKNESS};
use crate::{AppLike, ID};
pub struct DrawParkingLot {
pub id: ParkingLotID,
draw: RefCell<Option<Drawable>>,
}
impl DrawParkingLot {
pub fn new(
ctx: &EventCtx,
lot: &ParkingLot,
cs: &ColorScheme,
unzoomed_batch: &mut GeomBatch,
) -> DrawParkingLot {
unzoomed_batch.push(cs.parking_lot, lot.polygon.clone());
for aisle in &lot.aisles {
let aisle_thickness = NORMAL_LANE_THICKNESS / 2.0;
unzoomed_batch.push(
cs.unzoomed_road_surface(osm::RoadRank::Local),
PolyLine::unchecked_new(aisle.clone()).make_polygons(aisle_thickness),
);
}
unzoomed_batch.append(
GeomBatch::load_svg(ctx, "system/assets/map/parking.svg")
.scale(0.05)
.centered_on(lot.polygon.polylabel()),
);
DrawParkingLot {
id: lot.id,
draw: RefCell::new(None),
}
}
pub fn render(&self, app: &dyn AppLike) -> GeomBatch {
let lot = app.map().get_pl(self.id);
let orig_line = &lot.sidewalk_line;
let front_path_line = orig_line
.slice(
Distance::ZERO,
orig_line.length() - app.map().get_l(lot.sidewalk_pos.lane()).width / 2.0,
)
.unwrap_or_else(|| orig_line.clone());
let mut batch = GeomBatch::new();
let rank = app.map().get_parent(lot.sidewalk_pos.lane()).get_rank();
batch.push(
app.cs().zoomed_road_surface(LaneType::Sidewalk, rank),
front_path_line.make_polygons(NORMAL_LANE_THICKNESS),
);
batch.push(app.cs().parking_lot, lot.polygon.clone());
for aisle in &lot.aisles {
let aisle_thickness = NORMAL_LANE_THICKNESS / 2.0;
batch.push(
app.cs()
.zoomed_road_surface(LaneType::Driving, osm::RoadRank::Local),
PolyLine::unchecked_new(aisle.clone()).make_polygons(aisle_thickness),
);
}
let width = NORMAL_LANE_THICKNESS;
let height = PARKING_LOT_SPOT_LENGTH;
for (pt, angle) in &lot.spots {
let left = pt.project_away(width / 2.0, angle.rotate_degs(90.0));
let right = pt.project_away(width / 2.0, angle.rotate_degs(-90.0));
batch.push(
app.cs().general_road_marking(rank),
PolyLine::must_new(vec![
left.project_away(height, *angle),
left,
right,
right.project_away(height, *angle),
])
.make_polygons(Distance::meters(0.25)),
);
}
batch
}
}
impl Renderable for DrawParkingLot {
fn get_id(&self) -> ID {
ID::ParkingLot(self.id)
}
fn draw(&self, g: &mut GfxCtx, app: &dyn AppLike, _: &DrawOptions) {
let mut draw = self.draw.borrow_mut();
if draw.is_none() {
*draw = Some(g.upload(self.render(app)));
}
g.redraw(draw.as_ref().unwrap());
}
fn get_zorder(&self) -> isize {
0
}
fn get_outline(&self, map: &Map) -> Polygon {
let pl = map.get_pl(self.id);
if let Ok(p) = pl.polygon.to_outline(OUTLINE_THICKNESS) {
p
} else {
pl.polygon.clone()
}
}
fn contains_pt(&self, pt: Pt2D, map: &Map) -> bool {
map.get_pl(self.id).polygon.contains_pt(pt)
}
}