1use crate::error::{Error, Result};
8use pointy::{BBox, Float, Pt, Seg, Transform};
9
10#[derive(Copy, Clone, Debug, Eq, PartialEq)]
12enum Command {
13 MoveTo = 1,
15
16 LineTo = 2,
18
19 ClosePath = 7,
21}
22
23#[derive(Copy, Clone, Debug, Eq, PartialEq)]
25struct CommandInt {
26 id: Command,
28
29 count: u32,
31}
32
33#[derive(Copy, Clone, Debug, Eq, PartialEq)]
35struct ParamInt {
36 value: i32,
38}
39
40#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
42pub enum GeomType {
43 #[default]
45 Point,
46
47 Linestring,
49
50 Polygon,
52}
53
54#[derive(Default)]
70pub struct GeomEncoder<F>
71where
72 F: Float,
73{
74 geom_tp: GeomType,
76
77 xy_end: Option<Pt<F>>,
79
80 transform: Transform<F>,
82
83 bbox: BBox<F>,
85
86 x_min: i32,
88
89 x_max: i32,
91
92 y_min: i32,
94
95 y_max: i32,
97
98 pt0: Option<(i32, i32)>,
100
101 pt1: Option<(i32, i32)>,
103
104 cmd_offset: usize,
106
107 count: u32,
109
110 data: Vec<u32>,
112}
113
114pub struct GeomData {
130 geom_tp: GeomType,
132
133 data: Vec<u32>,
135}
136
137impl CommandInt {
138 fn new(id: Command, count: u32) -> Self {
140 debug_assert!(count <= 0x1FFF_FFFF);
141 CommandInt { id, count }
142 }
143
144 fn encode(&self) -> u32 {
146 ((self.id as u32) & 0x7) | (self.count << 3)
147 }
148
149 fn decode(code: u32) -> Self {
151 let id = match code & 0x7 {
152 1 => Command::MoveTo,
153 2 => Command::LineTo,
154 7 => Command::ClosePath,
155 _ => panic!("Invalid code: {code}"),
156 };
157 let count = code >> 3;
158 CommandInt { id, count }
159 }
160}
161
162impl ParamInt {
163 fn new(value: i32) -> Self {
165 ParamInt { value }
166 }
167
168 fn encode(&self) -> u32 {
170 ((self.value << 1) ^ (self.value >> 31)) as u32
171 }
172}
173
174impl<F> GeomEncoder<F>
175where
176 F: Float,
177{
178 pub fn new(geom_tp: GeomType) -> Self {
182 GeomEncoder {
183 geom_tp,
184 x_min: i32::MIN,
185 x_max: i32::MAX,
186 y_min: i32::MIN,
187 y_max: i32::MAX,
188 ..Default::default()
189 }
190 }
191
192 fn adjust_minmax(mut self) -> Self {
194 if self.bbox != BBox::default() {
195 let p = self.transform * (self.bbox.x_min(), self.bbox.y_min());
196 let x0 = p.x.round().to_i32().unwrap_or(i32::MIN);
197 let y0 = p.y.round().to_i32().unwrap_or(i32::MIN);
198 let p = self.transform * (self.bbox.x_max(), self.bbox.y_max());
199 let x1 = p.x.round().to_i32().unwrap_or(i32::MAX);
200 let y1 = p.y.round().to_i32().unwrap_or(i32::MAX);
201 self.x_min = x0.min(x1);
202 self.y_min = y0.min(y1);
203 self.x_max = x0.max(x1);
204 self.y_max = y0.max(y1);
205 }
206 self
207 }
208
209 pub fn bbox(mut self, bbox: BBox<F>) -> Self {
211 self.bbox = bbox;
212 self.adjust_minmax()
213 }
214
215 pub fn transform(mut self, transform: Transform<F>) -> Self {
217 self.transform = transform;
218 self.adjust_minmax()
219 }
220
221 fn push_command(&mut self, cmd: Command) {
223 log::trace!("push_command: {cmd:?}");
224 self.cmd_offset = self.data.len();
225 self.data.push(CommandInt::new(cmd, 1).encode());
226 }
227
228 fn set_command_count(&mut self, count: u32) {
230 let off = self.cmd_offset;
231 let mut cmd = CommandInt::decode(self.data[off]);
232 cmd.count = count;
233 self.data[off] = cmd.encode();
234 }
235
236 fn push_point(&mut self, x: i32, y: i32) {
238 log::trace!("push_point: {x},{y}");
239 self.pt0 = self.pt1;
240 let (px, py) = self.pt0.unwrap_or((0, 0));
241 self.data.push(ParamInt::new(x.saturating_sub(px)).encode());
242 self.data.push(ParamInt::new(y.saturating_sub(py)).encode());
243 self.pt1 = Some((x, y));
244 self.count += 1;
245 }
246
247 fn pop_point(&mut self) {
249 log::trace!("pop_point");
250 self.data.pop();
251 self.data.pop();
252 self.pt1 = self.pt0;
253 self.count -= 1;
254 }
255
256 pub fn point(mut self, x: F, y: F) -> Result<Self> {
258 self.add_point(x, y)?;
259 Ok(self)
260 }
261
262 pub fn add_point(&mut self, x: F, y: F) -> Result<()> {
264 self.add_boundary_points(x, y)?;
265 self.add_tile_point(x, y)
266 }
267
268 fn add_boundary_points(&mut self, x: F, y: F) -> Result<()> {
270 if let Some(pxy) = self.xy_end {
271 let xy = Pt::from((x, y));
272 let seg = Seg::new(pxy, xy);
273 if let Some(seg) = seg.clip(self.bbox) {
274 if seg.p0 != pxy {
275 self.add_tile_point(seg.p0.x, seg.p0.y)?;
276 }
277 if seg.p1 != xy {
278 self.add_tile_point(seg.p1.x, seg.p1.y)?;
279 }
280 }
281 }
282 match self.geom_tp {
283 GeomType::Linestring | GeomType::Polygon => {
284 self.xy_end = Some(Pt::from((x, y)));
285 }
286 _ => (),
287 }
288 Ok(())
289 }
290
291 fn add_tile_point(&mut self, x: F, y: F) -> Result<()> {
293 let pt = self.make_point(x, y)?;
294 if let Some((px, py)) = self.pt1
295 && pt.0 == px
296 && pt.1 == py
297 {
298 if self.count == 0 {
299 self.count += 1;
304 } else {
305 log::trace!("redundant point: {px},{py}");
308 }
309 return Ok(());
310 }
311 match self.geom_tp {
312 GeomType::Point => {
313 if self.count == 0 {
314 self.push_command(Command::MoveTo);
315 }
316 }
317 GeomType::Linestring => match self.count {
318 0 => self.push_command(Command::MoveTo),
319 1 => self.push_command(Command::LineTo),
320 _ => (),
321 },
322 GeomType::Polygon => {
323 match self.count {
324 0 => self.push_command(Command::MoveTo),
325 1 => self.push_command(Command::LineTo),
326 _ => (),
327 }
328 if self.count >= 2 && self.should_simplify_point(pt.0, pt.1) {
329 self.pop_point();
330 }
331 }
332 }
333 self.push_point(pt.0, pt.1);
334 Ok(())
335 }
336
337 fn make_point(&self, x: F, y: F) -> Result<(i32, i32)> {
339 let p = self.transform * (x, y);
340 let mut x = p.x.round().to_i32().ok_or(Error::InvalidValue())?;
341 let mut y = p.y.round().to_i32().ok_or(Error::InvalidValue())?;
342 x = x.clamp(self.x_min, self.x_max);
343 y = y.clamp(self.y_min, self.y_max);
344 Ok((x, y))
345 }
346
347 fn should_simplify_point(&self, x: i32, y: i32) -> bool {
349 if let (Some((p0x, p0y)), Some((p1x, p1y))) = (self.pt0, self.pt1) {
350 if p0x == p1x && p1x == x {
351 return (p0y < p1y && p1y < y) || (p0y > p1y && p1y > y);
352 }
353 if p0y == p1y && p1y == y {
354 return (p0x < p1x && p1x < x) || (p0x > p1x && p1x > x);
355 }
356 }
357 false
358 }
359
360 pub fn complete_geom(&mut self) -> Result<()> {
362 match self.geom_tp {
365 GeomType::Point => {
366 self.set_command_count(self.count);
367 return Ok(());
369 }
370 GeomType::Linestring => {
371 if self.count > 1 {
372 self.set_command_count(self.count - 1);
373 }
374 }
375 GeomType::Polygon => {
376 if self.count > 1 {
377 self.set_command_count(self.count - 1);
378 self.push_command(Command::ClosePath);
379 }
380 }
381 }
382 self.count = 0;
384 self.xy_end = None;
385 self.pt0 = None;
386 Ok(())
387 }
388
389 pub fn complete(mut self) -> Result<Self> {
391 self.complete_geom()?;
392 Ok(self)
393 }
394
395 pub fn encode(mut self) -> Result<GeomData> {
397 self = self.complete()?;
400 Ok(GeomData::new(self.geom_tp, self.data))
401 }
402}
403
404impl GeomData {
405 fn new(geom_tp: GeomType, data: Vec<u32>) -> Self {
410 GeomData { geom_tp, data }
411 }
412
413 pub(crate) fn geom_type(&self) -> GeomType {
415 self.geom_tp
416 }
417
418 pub fn is_empty(&self) -> bool {
420 self.data.is_empty()
421 }
422
423 pub fn len(&self) -> usize {
425 self.data.len()
426 }
427
428 pub(crate) fn into_vec(self) -> Vec<u32> {
430 self.data
431 }
432}
433
434#[cfg(test)]
435mod test {
436 use super::*;
437
438 #[test]
440 fn test_point() {
441 let v = GeomEncoder::new(GeomType::Point)
442 .point(25.0, 17.0)
443 .unwrap()
444 .encode()
445 .unwrap()
446 .into_vec();
447 assert_eq!(v, vec!(9, 50, 34));
448 }
449
450 #[test]
451 fn test_multipoint() {
452 let v = GeomEncoder::new(GeomType::Point)
453 .point(5.0, 7.0)
454 .unwrap()
455 .point(3.0, 2.0)
456 .unwrap()
457 .encode()
458 .unwrap()
459 .into_vec();
460 assert_eq!(v, vec!(17, 10, 14, 3, 9));
461 }
462
463 #[test]
464 fn test_linestring() {
465 let v = GeomEncoder::new(GeomType::Linestring)
466 .point(2.0, 2.0)
467 .unwrap()
468 .point(2.0, 10.0)
469 .unwrap()
470 .point(10.0, 10.0)
471 .unwrap()
472 .encode()
473 .unwrap()
474 .into_vec();
475 assert_eq!(v, vec!(9, 4, 4, 18, 0, 16, 16, 0));
476 }
477
478 #[test]
479 fn test_multilinestring() {
480 let v = GeomEncoder::new(GeomType::Linestring)
481 .point(2.0, 2.0)
482 .unwrap()
483 .point(2.0, 10.0)
484 .unwrap()
485 .point(10.0, 10.0)
486 .unwrap()
487 .complete()
488 .unwrap()
489 .point(1.0, 1.0)
490 .unwrap()
491 .point(3.0, 5.0)
492 .unwrap()
493 .encode()
494 .unwrap()
495 .into_vec();
496 assert_eq!(v, vec!(9, 4, 4, 18, 0, 16, 16, 0, 9, 17, 17, 10, 4, 8));
497 }
498
499 #[test]
500 fn test_multilinestring_with_redundant_points() {
501 let v = GeomEncoder::new(GeomType::Linestring)
502 .point(2.0, 2.0)
503 .unwrap()
504 .point(2.0, 2.0)
505 .unwrap()
506 .point(10.0, 10.0)
507 .unwrap()
508 .complete()
509 .unwrap()
510 .point(10.0, 10.0)
511 .unwrap()
512 .point(13.0, 15.0)
513 .unwrap()
514 .point(10.0, 10.0)
515 .unwrap()
516 .complete()
517 .unwrap()
518 .point(2.0, 2.0)
519 .unwrap()
520 .point(10.0, 10.0)
521 .unwrap()
522 .encode()
523 .unwrap()
524 .into_vec();
525 assert_eq!(
526 v,
527 vec!(9, 4, 4, 10, 16, 16, 18, 6, 10, 5, 9, 9, 15, 15, 10, 16, 16)
528 );
529 }
530
531 #[test]
532 fn test_polygon() {
533 let v = GeomEncoder::new(GeomType::Polygon)
534 .point(3.0, 6.0)
535 .unwrap()
536 .point(8.0, 12.0)
537 .unwrap()
538 .point(20.0, 34.0)
539 .unwrap()
540 .encode()
541 .unwrap()
542 .into_vec();
543 assert_eq!(v, vec!(9, 6, 12, 18, 10, 12, 24, 44, 15));
544 }
545
546 #[test]
547 fn test_multipolygon() {
548 let v = GeomEncoder::new(GeomType::Polygon)
549 .point(0.0, 0.0)
551 .unwrap()
552 .point(10.0, 0.0)
553 .unwrap()
554 .point(10.0, 10.0)
555 .unwrap()
556 .point(0.0, 10.0)
557 .unwrap()
558 .complete()
559 .unwrap()
560 .point(11.0, 11.0)
562 .unwrap()
563 .point(20.0, 11.0)
564 .unwrap()
565 .point(20.0, 20.0)
566 .unwrap()
567 .point(11.0, 20.0)
568 .unwrap()
569 .complete()
570 .unwrap()
571 .point(13.0, 13.0)
573 .unwrap()
574 .point(13.0, 17.0)
575 .unwrap()
576 .point(17.0, 17.0)
577 .unwrap()
578 .point(17.0, 13.0)
579 .unwrap()
580 .encode()
581 .unwrap()
582 .into_vec();
583 assert_eq!(
584 v,
585 vec!(
586 9, 0, 0, 26, 20, 0, 0, 20, 19, 0, 15, 9, 22, 2, 26, 18, 0, 0,
587 18, 17, 0, 15, 9, 4, 13, 26, 0, 8, 8, 0, 0, 7, 15
588 )
589 );
590 }
591}