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
127
128
129
130
131
132
133
134
135
136
137
use std::cell::RefCell;
use geom::{Circle, Distance, PolyLine, Pt2D};
use crate::{Color, Drawable, GeomBatch, GfxCtx};
pub struct DrawUnzoomedShapes {
shapes: Vec<Shape>,
per_zoom: RefCell<[Option<Drawable>; 11]>,
}
enum Shape {
Line {
polyline: PolyLine,
width: Distance,
color: Color,
},
Circle {
center: Pt2D,
radius: Distance,
color: Color,
},
Custom(Box<dyn Fn(&mut GeomBatch, f64)>),
}
impl Shape {
fn render(&self, batch: &mut GeomBatch, thickness: f64) {
match self {
Shape::Line {
polyline,
width,
color,
} => {
batch.push(*color, polyline.make_polygons(thickness * *width));
}
Shape::Circle {
center,
radius,
color,
} => {
batch.push(
*color,
Circle::new(*center, thickness * *radius).to_polygon(),
);
}
Shape::Custom(f) => f(batch, thickness),
}
}
}
pub struct DrawUnzoomedShapesBuilder {
shapes: Vec<Shape>,
}
impl DrawUnzoomedShapes {
pub fn empty() -> Self {
Self {
shapes: Vec::new(),
per_zoom: Default::default(),
}
}
pub fn builder() -> DrawUnzoomedShapesBuilder {
DrawUnzoomedShapesBuilder { shapes: Vec::new() }
}
pub fn draw(&self, g: &mut GfxCtx) {
let (zoom, idx) = discretize_zoom(g.canvas.cam_zoom);
let value = &mut self.per_zoom.borrow_mut()[idx];
if value.is_none() {
let max = 5.0;
let thickness = 1.0 + (max - 1.0) * (1.0 - zoom);
let mut batch = GeomBatch::new();
for shape in &self.shapes {
shape.render(&mut batch, thickness);
}
*value = Some(g.upload(batch));
}
g.redraw(value.as_ref().unwrap());
}
}
impl DrawUnzoomedShapesBuilder {
pub fn add_line(&mut self, polyline: PolyLine, width: Distance, color: Color) {
self.shapes.push(Shape::Line {
polyline,
width,
color,
});
}
pub fn add_circle(&mut self, center: Pt2D, radius: Distance, color: Color) {
self.shapes.push(Shape::Circle {
center,
radius,
color,
});
}
pub fn add_custom(&mut self, f: Box<dyn Fn(&mut GeomBatch, f64)>) {
self.shapes.push(Shape::Custom(f));
}
pub fn build(self) -> DrawUnzoomedShapes {
DrawUnzoomedShapes {
shapes: self.shapes,
per_zoom: Default::default(),
}
}
}
fn discretize_zoom(zoom: f64) -> (f64, usize) {
if zoom >= 1.0 {
return (1.0, 10);
}
let rounded = (zoom * 10.0).round();
let idx = rounded as usize;
(rounded / 10.0, idx)
}