1use super::*;
2
3pub struct Tiled<'a, P: Processor> {
4 default: &'a mut P,
5 is_tiled: usize,
6 group_depth: usize,
7 tile_buf: Vec<Element>,
8 tile_x0: f32,
9 tile_y0: f32,
10 tile_x1: f32,
11 tile_y1: f32,
12 x0: f32,
13 x1: f32,
14 y0: f32,
15 y1: f32,
16 style: TiledStyle
17}
18
19#[derive(Clone, Copy, Debug)]
20pub struct TiledStyle {
21 pub h_grid_margin: f32,
22 pub v_grid_margin: f32,
23 pub tile_margin: f32,
24 pub grid_color: Option<[u8; 3]>,
25}
26
27impl Default for TiledStyle {
28 fn default() -> Self {
29 TiledStyle {
30 tile_margin: 0.1,
31 h_grid_margin: 10.,
32 v_grid_margin: 10.,
33 grid_color: Some([200; 3]),
34 }
35 }
36}
37
38impl<'a, P: Processor> Tiled<'a, P> {
39 pub fn new(p: &'a mut P, style: TiledStyle) -> Self {
40 Tiled {
41 default: p,
42 is_tiled: std::usize::MAX,
43 group_depth: 0,
44 tile_buf: Vec::new(),
45 tile_x0: std::f32::INFINITY,
46 tile_y0: std::f32::INFINITY,
47 tile_x1: -std::f32::INFINITY,
48 tile_y1: -std::f32::INFINITY,
49 x0: std::f32::INFINITY,
50 y0: std::f32::INFINITY,
51 x1: -std::f32::INFINITY,
52 y1: -std::f32::INFINITY,
53 style
54 }
55 }
56
57 fn draw_tile(&mut self, x: f32, y: f32, style: &Style) {
58 self.tile_buf.push(Element::Rectangle {
59 style: Style {
60 fill_color: style.stroke_color.clone(),
61 stroke_color: Some([0, 0, 0]),
62 fill_opacity: style.opacity.clone(),
63 .. Style::default()
64 },
65 x0: x - 5. + self.style.tile_margin,
66 y0: y - 5. + self.style.tile_margin,
67 x1: x + 5. - self.style.tile_margin,
68 y1: y + 5. - self.style.tile_margin,
69 });
70 self.x1 = self.x1.max(x);
71 self.y1 = self.y1.max(y);
72 self.x0 = self.x0.min(x);
73 self.y0 = self.y0.min(y);
74 self.tile_x0 = self.tile_x0.min(x - self.style.h_grid_margin);
75 self.tile_y0 = self.tile_y0.min(y - self.style.v_grid_margin);
76 self.tile_x1 = self.tile_x1.max(x + self.style.h_grid_margin);
77 self.tile_y1 = self.tile_y1.max(y + self.style.v_grid_margin);
78 }
79
80 fn line(&mut self, current_is_drawn: &mut bool, mut x0: f32, mut y0: f32, x: f32, y: f32, style: &Style) {
81 debug!("=> {:?} {:?}", x, y);
82 if x.round() > x0.round() {
84 if *current_is_drawn {
85 x0 += 10.
86 }
87 while x0.round() <= x.round() {
88 self.draw_tile(x0, y0, &style);
89 x0 += 10.
90 }
91 *current_is_drawn = true;
92 } else if x.round() < x0.round() {
93 if *current_is_drawn {
94 x0 -= 10.
95 }
96 while x0.round() >= x.round() {
97 self.draw_tile(x0, y0, &style);
98 x0 -= 10.
99 }
100 *current_is_drawn = true;
101 }
102
103 if y.round() > y0.round() {
105 if *current_is_drawn {
106 y0 += 10.
107 }
108 while y0.round() <= y.round() {
109 self.draw_tile(x, y0, &style);
110 y0 += 10.
111 }
112 *current_is_drawn = true;
113 } else if y.round() < y0.round() {
114 if *current_is_drawn {
115 y0 -= 10.
116 }
117 while y0.round() >= y.round() {
118 self.draw_tile(x, y0, &style);
119 y0 -= 10.
120 }
121 *current_is_drawn = true;
122 }
123 }
124
125 fn path(
126 &mut self,
127 close: bool,
128 path: &[PathElement],
129 style: &Style,
130 ) -> Result<(), failure::Error> {
131 let (mut x0, mut y0) = (0., 0.);
132 let mut initial = None;
133 let mut current_is_drawn = true;
134 for elt in path.iter() {
135 match *elt {
136 PathElement::Move { x, y } => {
137 debug!("MV {:?} {:?}", x, y);
138 if !current_is_drawn {
139 self.draw_tile(x0, y0, &style);
140 }
141 current_is_drawn = false;
142 if close {
143 if let Some((mut x, mut y)) = initial.take() {
144 if x0 > x {
146 x += 1.
147 } else if x0 < x {
148 x -= 1.
149 }
150 if y0 > x {
151 y += 1.
152 } else if y0 < x {
153 y -= 1.
154 }
155 self.line(&mut current_is_drawn, x0, y0, x, y, style)
156 }
157 }
158 initial = Some((x, y));
159 x0 = x;
160 y0 = y;
161 }
162 PathElement::Bezier3 { .. } => {}
163 PathElement::Line { x, y } => {
164 self.line(&mut current_is_drawn, x0, y0, x, y, style);
165 x0 = x;
166 y0 = y;
167 }
168 }
169 }
170 if close {
171 if let Some((mut x, mut y)) = initial.take() {
172 if x0 > x {
173 x += 1.
174 } else if x0 < x {
175 x -= 1.
176 }
177 if y0 > x {
178 y += 1.
179 } else if y0 < x {
180 y -= 1.
181 }
182 self.line(&mut current_is_drawn, x0, y0, x, y, style)
183 }
184 }
185 Ok(())
186 }
187
188 fn tiled_element(&mut self, element: Element) -> Result<(), failure::Error> {
189 debug!("tiled_element: {:?}", element);
190 match element {
191 Element::Path {
192 close,
193 ref style,
194 ref path,
195 } => {
196 if style.stroke_color.is_some() {
197 self.path(close, path, style)?;
198 self.tile_buf.push(element);
199 } else {
200 for elt in path.iter() {
202 match *elt {
203 PathElement::Move { x, y } => {
204 self.x1 = self.x1.max(x);
205 self.y1 = self.y1.max(y);
206 self.x0 = self.x0.min(x);
207 self.y0 = self.y0.min(y);
208 }
209 PathElement::Bezier3 {
210 x,
211 y,
212 x1,
213 y1,
214 x2,
215 y2,
216 } => {
217 self.x1 = self.x1.max(x).max(x1).max(x2);
218 self.y1 = self.y1.max(y).max(y1).max(y2);
219 self.x0 = self.x0.min(x).min(x1).min(x2);
220 self.y0 = self.y0.min(y).min(y1).min(y2);
221 }
222 PathElement::Line { x, y } => {
223 self.x1 = self.x1.max(x);
224 self.y1 = self.y1.max(y);
225 self.x0 = self.x0.min(x);
226 self.y0 = self.y0.min(y);
227 }
228 }
229 }
230 self.tile_buf.push(element)
231 }
232 }
233 e => self.tile_buf.push(e),
234 }
235 Ok(())
236 }
237}
238
239impl<'a, P: Processor> Processor for Tiled<'a, P> {
240 fn process(&mut self, element: Element) -> Result<(), failure::Error> {
241 debug!("element {:?}", element);
242 match element {
243 Element::BeginGroup { id } => {
244 self.group_depth += 1;
245 if id.contains("tiled") {
246 self.is_tiled = self.group_depth;
247 }
248 self.tile_buf.push(Element::BeginGroup { id })
249 }
250 Element::EndGroup => {
251 self.group_depth -= 1;
252 if self.group_depth < self.is_tiled {
253 self.is_tiled = std::usize::MAX
254 }
255 self.tile_buf.push(Element::EndGroup)
256 }
257 e => {
258 if self.group_depth >= self.is_tiled {
259 self.tiled_element(e)?
260 } else {
261 self.tile_buf.push(e)
262 }
263 }
264 }
265 Ok(())
266 }
267
268 fn finish(&mut self) -> Result<(), failure::Error> {
269 debug!("finish, outputting grid");
270 let mut x0 = self.tile_x0 - 5.;
271 let mut y0 = self.tile_y0 - 5.;
272 self.x0 = self.x0.min(x0);
273 self.y0 = self.y0.min(y0);
274 let xoff = ((x0 - self.x0) / 10.).round() * 10.;
275 let yoff = ((y0 - self.y0) / 10.).round() * 10.;
276 x0 -= xoff;
277 y0 -= yoff;
278 let x1 = self.x1.max(self.tile_x1);
279 let y1 = self.y1.max(self.tile_y1);
280 let w = ((x1 - x0) / 10.).round() * 10.;
281 let h = ((y1 - y0) / 10.).round() * 10.;
282
283 let style = Style {
284 stroke_color: self.style.grid_color.clone(),
285 .. Style::default()
286 };
287
288 self.default.process(Element::Rectangle {
289 style: style.clone(),
290 x0: self.tile_x0 - 5. - xoff,
291 y0: self.tile_y0 - 5. - yoff,
292 x1: self.tile_x0 - 5. - xoff + w,
293 y1: self.tile_y0 - 5. - yoff + h,
294 })?;
295
296
297 x0 += 10.;
298 while x0.round() < x1.round() {
299 self.default.process(Element::Path {
300 close: false,
301 style: style.clone(),
302 path: vec![
303 PathElement::Move { x: x0, y: y0 + h },
304 PathElement::Line { x: x0, y: y0 },
305 ],
306 })?;
307 x0 += 10.;
308 }
309
310 y0 += 10.;
311 while y0.round() < y1.round() {
312 self.default.process(Element::Path {
313 close: false,
314 style: style.clone(),
315 path: vec![
316 PathElement::Move {
317 x: self.tile_x0 - 5. - xoff,
318 y: y0,
319 },
320 PathElement::Line {
321 x: self.tile_x0 - 5. - xoff + w,
322 y: y0,
323 },
324 ],
325 })?;
326 y0 += 10.;
327 }
328
329 for elt in self.tile_buf.drain(..) {
330 self.default.process(elt)?
331 }
332 self.default.finish()
333 }
334}