1use core::cmp::Ordering;
19use core::ops::Range;
20
21use geo_types::Coord;
22
23use crate::TileError;
24use crate::clip_polygon::{close_ring, fill_box, keep_edge, push_distinct, push_fill_box};
25use crate::clip_polyline::to_local;
26use crate::geom::{crossing_x_ceil, ring_orientation};
27use crate::grid::{Grid, MAX_TILE_VISITS, RouteSink};
28use crate::polygon_view::{PolygonView, copy_view, offset, span};
29use crate::tile::TileId;
30use crate::vertex::{PolyVertex, Vertex};
31
32const MAX_FEATURE_VERTICES: usize = 1 << 28;
37
38#[derive(Debug, Clone, Copy)]
41struct RingInfo {
42 start: u32,
43 len: u32,
44 poly: u32,
45 hole: bool,
46}
47
48#[derive(Debug, Clone, Copy)]
52struct PolyInfo {
53 first: u32,
54 orient: Ordering,
55 index: u32,
56}
57
58#[derive(Debug, Clone, Copy)]
61struct Hit {
62 ty: i32,
63 tx: i32,
64 edge: u32,
65 ring: u32,
66}
67
68#[derive(Debug, Clone, Copy)]
72struct Crossing {
73 ty: i32,
74 edge: u32,
75 ring: u32,
76 up: bool,
77 right_of: i64,
78}
79
80impl Crossing {
81 fn sign(self) -> i64 {
82 if self.up { 1 } else { -1 }
83 }
84}
85
86struct HitSink<'a> {
88 hits: &'a mut Vec<Hit>,
89 crossings: &'a mut Vec<Crossing>,
90 extent: i64,
91 buffer: i64,
92 ring: u32,
93 next: u32,
94 edge: u32,
95}
96
97impl HitSink<'_> {
98 fn push_crossing(
100 &mut self,
101 a: Coord<i32>,
102 b: Coord<i32>,
103 ty: i64,
104 cy: i64,
105 ) -> Result<(), TileError> {
106 let cy = i32::try_from(cy).map_err(|_| TileError::Overflow)?;
107 let x = crossing_x_ceil(a, b, cy);
109 self.crossings.push(Crossing {
110 ty: i32::try_from(ty).map_err(|_| TileError::Overflow)?,
111 edge: self.edge,
112 ring: self.ring,
113 up: b.y > a.y,
114 right_of: (x - self.extent - self.buffer).div_euclid(self.extent),
115 });
116 Ok(())
117 }
118}
119
120impl<V: PolyVertex> RouteSink<V> for HitSink<'_> {
121 fn begin_polyline(&mut self) {}
122
123 fn begin_segment(&mut self) {
124 self.edge = self.next;
126 self.next += 1;
127 }
128
129 fn emit(&mut self, tile: TileId, _: Coord<i32>, _: V, _: V) -> Result<(), TileError> {
130 self.hits.push(Hit {
131 ty: tile.y,
132 tx: tile.x,
133 edge: self.edge,
134 ring: self.ring,
135 });
136 Ok(())
137 }
138
139 fn end_segment(
143 &mut self,
144 a: Coord<i32>,
145 b: Coord<i32>,
146 row: Option<i32>,
147 ) -> Result<(), TileError> {
148 let (lo, hi) = (i64::from(a.y.min(b.y)), i64::from(a.y.max(b.y)));
150 if let Some(ty) = row {
151 let (ty, cy) = (i64::from(ty), row_center(i64::from(ty), self.extent));
153 return if lo <= cy && cy < hi {
154 self.push_crossing(a, b, ty, cy)
155 } else {
156 Ok(())
157 };
158 }
159 let mut ty = lo.div_euclid(self.extent) - 1;
160 let mut cy = row_center(ty, self.extent);
161 while cy < lo {
162 ty += 1;
163 cy = row_center(ty, self.extent);
164 }
165 while cy < hi {
166 self.push_crossing(a, b, ty, cy)?;
167 ty += 1;
168 cy = row_center(ty, self.extent);
169 }
170 Ok(())
171 }
172}
173
174fn row_center(ty: i64, extent: i64) -> i64 {
179 ty * extent + if ty < 0 { extent / 2 } else { (extent - 1) / 2 }
180}
181
182fn counting_sort<T: Copy>(
186 items: &mut [T],
187 tmp: &mut Vec<T>,
188 counts: &mut Vec<usize>,
189 buckets: usize,
190 bucket: impl Fn(&T) -> usize,
191) {
192 counts.clear();
193 counts.resize(buckets, 0);
194 for item in items.iter() {
195 counts[bucket(item)] += 1;
196 }
197 let mut start = 0;
199 for c in counts.iter_mut() {
200 (*c, start) = (start, start + *c);
201 }
202 tmp.clear();
203 tmp.extend_from_slice(items);
204 for item in tmp.iter() {
205 let at = &mut counts[bucket(item)];
206 items[*at] = *item;
207 *at += 1;
208 }
209}
210
211fn sort_hits(hits: &mut [Hit], tmp: &mut Vec<Hit>, counts: &mut Vec<usize>) {
218 let key = |h: &Hit| (h.ty, h.tx, h.edge);
219 let Some(&first) = hits.first() else {
220 return;
221 };
222 let (mut x, mut y) = ((first.tx, first.tx), (first.ty, first.ty));
223 for h in hits.iter() {
224 x = (x.0.min(h.tx), x.1.max(h.tx));
225 y = (y.0.min(h.ty), y.1.max(h.ty));
226 }
227 let (columns, rows) = (
228 x.1.abs_diff(x.0) as usize + 1,
229 y.1.abs_diff(y.0) as usize + 1,
230 );
231 let column = |h: &Hit| h.tx.abs_diff(x.0) as usize;
232 let row = |h: &Hit| h.ty.abs_diff(y.0) as usize;
233 let budget = hits.len().saturating_mul(4);
234 if columns == 1 && rows == 1 {
235 } else if hits.len() < 32 || columns + rows > budget {
237 hits.sort_unstable_by_key(key);
238 } else if let Some(tiles) = columns.checked_mul(rows)
239 && tiles <= budget
240 {
241 counting_sort(hits, tmp, counts, tiles, |h| row(h) * columns + column(h));
242 } else {
243 counting_sort(hits, tmp, counts, columns, column);
244 counting_sort(hits, tmp, counts, rows, row);
245 }
246 debug_assert!(hits.is_sorted_by_key(key));
247}
248
249fn sort_crossings(crossings: &mut [Crossing], tmp: &mut Vec<Crossing>, counts: &mut Vec<usize>) {
253 let key = |c: &Crossing| (c.ty, c.edge);
254 let Some(&first) = crossings.first() else {
255 return;
256 };
257 let y = crossings.iter().fold((first.ty, first.ty), |(lo, hi), c| {
258 (lo.min(c.ty), hi.max(c.ty))
259 });
260 let rows = y.1.abs_diff(y.0) as usize + 1;
261 if crossings.len() < 32 || rows > crossings.len().saturating_mul(4) {
262 crossings.sort_unstable_by_key(key);
263 } else if rows > 1 {
264 counting_sort(crossings, tmp, counts, rows, |c| {
265 c.ty.abs_diff(y.0) as usize
266 });
267 }
268 debug_assert!(crossings.is_sorted_by_key(key));
269}
270
271fn fenwick_build(tree: &mut Vec<i64>, values: impl Iterator<Item = i64>) {
273 tree.clear();
274 tree.extend(values);
275 for i in 0..tree.len() {
276 let parent = i | (i + 1);
277 if parent < tree.len() {
278 tree[parent] += tree[i];
279 }
280 }
281}
282
283fn fenwick_add(tree: &mut [i64], mut i: usize, delta: i64) {
285 while i < tree.len() {
286 tree[i] += delta;
287 i |= i + 1;
288 }
289}
290
291fn fenwick_prefix(tree: &[i64], mut end: usize) -> i64 {
293 let mut sum = 0;
294 while end > 0 {
295 sum += tree[end - 1];
296 end &= end - 1;
297 }
298 sum
299}
300
301fn localize<V: PolyVertex>(verts: &mut [V], origin: Coord<i32>) -> Result<(), TileError> {
303 for v in verts {
304 *v = to_local(*v, origin)?;
305 }
306 Ok(())
307}
308
309#[derive(Debug, Clone)]
311struct Input<V> {
312 pts: Vec<V>,
313 rings: Vec<RingInfo>,
314 polys: Vec<PolyInfo>,
315}
316
317impl<V: PolyVertex> Input<V> {
318 fn load<P>(&mut self, polygons: P) -> Result<(), TileError>
321 where
322 P: IntoIterator,
323 P::Item: IntoIterator,
324 <P::Item as IntoIterator>::Item: AsRef<[V]>,
325 {
326 self.pts.clear();
327 self.rings.clear();
328 self.polys.clear();
329 for (index, polygon) in polygons.into_iter().enumerate() {
330 let index = offset(index)?;
331 let mut rings = polygon.into_iter();
332 let Some(exterior) = rings.next() else {
333 continue;
334 };
335 let first = offset(self.rings.len())?;
336 let poly = offset(self.polys.len())?;
337 if !self.push_ring(exterior.as_ref(), poly, false)? {
338 continue;
339 }
340 for hole in rings {
341 self.push_ring(hole.as_ref(), poly, true)?;
342 }
343 self.polys.push(PolyInfo {
344 first,
345 orient: Ordering::Equal,
347 index,
348 });
349 }
350 Ok(())
351 }
352
353 fn orient_polygons(&mut self) {
355 for poly in &mut self.polys {
356 let ext = self.rings[poly.first as usize];
357 poly.orient =
358 ring_orientation(&self.pts[ext.start as usize..(ext.start + ext.len) as usize]);
359 }
360 }
361
362 #[inline]
364 fn push_ring(&mut self, ring: &[V], poly: u32, hole: bool) -> Result<bool, TileError> {
365 let start = self.pts.len();
366 let len = push_distinct(ring, &mut self.pts);
367 if len < 3 {
368 self.pts.truncate(start);
369 return Ok(false);
370 }
371 self.pts.push(self.pts[start]);
372 offset(self.pts.len())?;
374 self.rings.push(RingInfo {
375 start: offset(start)?,
376 len: offset(len)?,
377 poly,
378 hole,
379 });
380 Ok(true)
381 }
382
383 fn ring_pts(&self, ring: RingInfo) -> &[V] {
385 &self.pts[ring.start as usize..(ring.start + ring.len) as usize]
386 }
387}
388
389#[derive(Debug, Clone, PartialEq, Eq, Hash)]
401#[non_exhaustive]
402pub struct FillRun {
403 pub y: i32,
405 pub x: Range<i32>,
407 pub polygon: u32,
410 orient: Ordering,
412}
413
414#[derive(Debug, Clone)]
417struct Pieces<V> {
418 verts: Vec<V>,
419 ring_ends: Vec<u32>,
420 poly_ends: Vec<u32>,
421 tiles: Vec<TileEntry>,
422 runs: Vec<FillRun>,
423}
424
425#[derive(Debug, Clone, Copy)]
427struct TileEntry {
428 tile: TileId,
429 poly_end: u32,
430}
431
432#[derive(Clone, Copy, Default)]
434struct Savepoint {
435 verts: usize,
436 ring_ends: usize,
437 poly_ends: usize,
438 tiles: usize,
439 runs: usize,
440}
441
442impl<V> Pieces<V> {
443 fn savepoint(&self) -> Savepoint {
444 Savepoint {
445 verts: self.verts.len(),
446 ring_ends: self.ring_ends.len(),
447 poly_ends: self.poly_ends.len(),
448 tiles: self.tiles.len(),
449 runs: self.runs.len(),
450 }
451 }
452
453 fn rollback(&mut self, s: Savepoint) {
454 self.verts.truncate(s.verts);
455 self.ring_ends.truncate(s.ring_ends);
456 self.poly_ends.truncate(s.poly_ends);
457 self.tiles.truncate(s.tiles);
458 self.runs.truncate(s.runs);
459 }
460
461 fn clear(&mut self) {
462 self.rollback(Savepoint::default());
463 }
464
465 fn shrink_to_fit(&mut self) {
466 self.verts.shrink_to_fit();
467 self.ring_ends.shrink_to_fit();
468 self.poly_ends.shrink_to_fit();
469 self.tiles.shrink_to_fit();
470 self.runs.shrink_to_fit();
471 }
472}
473
474#[derive(Debug, Clone)]
476struct Scratch {
477 hits: Vec<Hit>,
478 hits_tmp: Vec<Hit>,
480 crossings_tmp: Vec<Crossing>,
481 counts: Vec<usize>,
482 crossings: Vec<Crossing>,
483 by_x: Vec<u32>,
485 fenwick: Vec<i64>,
487 inside: Vec<bool>,
490 holes_in: Vec<u32>,
492 covering: Vec<u32>,
494 cover_pos: Vec<usize>,
495 last_run: Vec<usize>,
497 fill_ok: bool,
499 vert_limit: usize,
504 arcs: Vec<(usize, usize)>,
506 touched: Vec<u32>,
507 extra: Vec<u32>,
508}
509
510impl Scratch {
511 const fn new() -> Self {
512 Self {
513 hits: Vec::new(),
514 hits_tmp: Vec::new(),
515 crossings_tmp: Vec::new(),
516 counts: Vec::new(),
517 crossings: Vec::new(),
518 by_x: Vec::new(),
519 fenwick: Vec::new(),
520 inside: Vec::new(),
521 holes_in: Vec::new(),
522 covering: Vec::new(),
523 cover_pos: Vec::new(),
524 last_run: Vec::new(),
525 fill_ok: false,
526 vert_limit: 0,
527 arcs: Vec::new(),
528 touched: Vec::new(),
529 extra: Vec::new(),
530 }
531 }
532
533 fn route<V: PolyVertex>(
536 &mut self,
537 grid: Grid,
538 input: &Input<V>,
539 mut budget: i64,
540 ) -> Result<(), TileError> {
541 self.hits.clear();
542 self.crossings.clear();
543 self.hits.reserve(input.pts.len());
546 for (ring, info) in (0..).zip(&input.rings) {
547 let start = info.start as usize;
548 let closed = &input.pts[start..=start + info.len as usize];
549 let mut sink = HitSink {
550 hits: &mut self.hits,
551 crossings: &mut self.crossings,
552 extent: i64::from(grid.extent()),
553 buffer: i64::from(grid.buffer()),
554 ring,
555 next: info.start,
556 edge: 0,
557 };
558 grid.route_within(closed, &mut sink, &mut budget)?;
559 }
560 sort_hits(&mut self.hits, &mut self.hits_tmp, &mut self.counts);
561 sort_crossings(
562 &mut self.crossings,
563 &mut self.crossings_tmp,
564 &mut self.counts,
565 );
566 Ok(())
567 }
568
569 fn sweep<V: PolyVertex>(
571 &mut self,
572 grid: Grid,
573 input: &Input<V>,
574 out: &mut Pieces<V>,
575 max_verts: usize,
576 fill_ok: bool,
577 ) -> Result<(), TileError> {
578 self.vert_limit = out.verts.len().saturating_add(max_verts);
579 self.fill_ok = fill_ok;
580 self.last_run.clear();
581 self.last_run.resize(input.polys.len(), usize::MAX);
582 self.inside.clear();
585 self.inside.resize(input.rings.len(), false);
586 self.holes_in.clear();
587 self.holes_in.resize(input.polys.len(), 0);
588 self.cover_pos.clear();
589 self.cover_pos.resize(input.polys.len(), 0);
590 self.covering.clear();
591
592 let hits = core::mem::take(&mut self.hits);
593 let crossings = core::mem::take(&mut self.crossings);
594 let result = self.sweep_rows(grid, input, &hits, &crossings, out);
595 self.hits = hits;
596 self.crossings = crossings;
597 result
598 }
599
600 fn sweep_rows<V: PolyVertex>(
601 &mut self,
602 grid: Grid,
603 input: &Input<V>,
604 hits: &[Hit],
605 crossings: &[Crossing],
606 out: &mut Pieces<V>,
607 ) -> Result<(), TileError> {
608 let (mut h, mut c) = (0, 0);
609 loop {
610 let ty = match (hits.get(h), crossings.get(c)) {
611 (Some(a), Some(b)) => a.ty.min(b.ty),
612 (Some(a), None) => a.ty,
613 (None, Some(b)) => b.ty,
614 (None, None) => return Ok(()),
615 };
616 let h_end = h + hits[h..].partition_point(|x| x.ty == ty);
617 let c_end = c + crossings[c..].partition_point(|x| x.ty == ty);
618 self.sweep_row(grid, input, ty, &hits[h..h_end], &crossings[c..c_end], out)?;
619 (h, c) = (h_end, c_end);
620 }
621 }
622
623 fn sweep_row<V: PolyVertex>(
628 &mut self,
629 grid: Grid,
630 input: &Input<V>,
631 ty: i32,
632 hits: &[Hit],
633 cs: &[Crossing],
634 out: &mut Pieces<V>,
635 ) -> Result<(), TileError> {
636 self.by_x.clear();
637 self.by_x.extend(0..offset(cs.len())?);
638 self.by_x.sort_unstable_by_key(|&i| cs[i as usize].right_of);
639 fenwick_build(&mut self.fenwick, cs.iter().map(|c| c.sign()));
640
641 let row_runs = out.runs.len();
642 let (mut k, mut h) = (0, 0);
643 let mut next = i64::MIN;
645 loop {
646 let bound = self
648 .by_x
649 .get(k)
650 .map_or(i64::MAX, |&i| cs[i as usize].right_of);
651 while let Some(hit) = hits.get(h)
652 && i64::from(hit.tx) <= bound
653 {
654 let tx = i64::from(hit.tx);
655 self.fill(input, ty, next, tx, row_runs, out)?;
656 let end = h + hits[h..].partition_point(|x| x.tx == hit.tx);
657 self.tile(grid, input, TileId::new(hit.tx, ty), &hits[h..end], cs, out)?;
658 if out.verts.len() > self.vert_limit {
660 return Err(TileError::OutputTooLarge);
661 }
662 (h, next) = (end, tx + 1);
663 }
664 if k == self.by_x.len() {
665 out.runs[row_runs..].sort_unstable_by_key(|r| (r.x.start, r.polygon));
668 return Ok(());
669 }
670 self.fill(input, ty, next, bound + 1, row_runs, out)?;
672 next = bound + 1;
673 while let Some(&i) = self.by_x.get(k)
675 && cs[i as usize].right_of == bound
676 {
677 let crossing = cs[i as usize];
678 self.toggle(input, crossing);
679 fenwick_add(&mut self.fenwick, i as usize, -crossing.sign());
680 k += 1;
681 }
682 }
683 }
684
685 fn fill<V>(
689 &mut self,
690 input: &Input<V>,
691 y: i32,
692 start: i64,
693 end: i64,
694 row_runs: usize,
695 out: &mut Pieces<V>,
696 ) -> Result<(), TileError> {
697 if start >= end || self.covering.is_empty() {
698 return Ok(());
699 }
700 if !self.fill_ok {
701 return Err(TileError::Overflow);
703 }
704 let start = i32::try_from(start).map_err(|_| TileError::Overflow)?;
705 let end = i32::try_from(end).map_err(|_| TileError::Overflow)?;
706 for &p in &self.covering {
707 let info = input.polys[p as usize];
708 let last = &mut self.last_run[p as usize];
709 match out.runs.get_mut(*last) {
710 Some(run)
711 if *last >= row_runs && run.polygon == info.index && run.x.end == start =>
712 {
713 run.x.end = end;
714 }
715 _ => {
716 *last = out.runs.len();
717 out.runs.push(FillRun {
718 y,
719 x: start..end,
720 polygon: info.index,
721 orient: info.orient,
722 });
723 }
724 }
725 }
726 Ok(())
727 }
728
729 fn toggle<V>(&mut self, input: &Input<V>, crossing: Crossing) {
731 let ring = input.rings[crossing.ring as usize];
732 let p = ring.poly as usize;
733 let ext = input.polys[p].first as usize;
734 let covers = |s: &Self| s.inside[ext] && s.holes_in[p] == 0;
735 let was = covers(self);
736 let r = crossing.ring as usize;
737 self.inside[r] = !self.inside[r];
738 if ring.hole {
739 if self.inside[r] {
740 self.holes_in[p] += 1;
741 } else {
742 self.holes_in[p] = self.holes_in[p].saturating_sub(1);
744 }
745 }
746 match (was, covers(self)) {
747 (false, true) => {
748 self.cover_pos[p] = self.covering.len();
749 self.covering.push(ring.poly);
750 }
751 (true, false) => {
752 let i = self.cover_pos[p];
753 self.covering.swap_remove(i);
754 if let Some(&moved) = self.covering.get(i) {
755 self.cover_pos[moved as usize] = i;
756 }
757 }
758 _ => {}
759 }
760 }
761
762 fn tile<V: PolyVertex>(
764 &mut self,
765 grid: Grid,
766 input: &Input<V>,
767 tile: TileId,
768 hits: &[Hit],
769 cs: &[Crossing],
770 out: &mut Pieces<V>,
771 ) -> Result<(), TileError> {
772 let (min, max) = grid.tile_buffered_bounds(tile)?;
773 let origin = tile.origin(grid.extent()).ok_or(TileError::Overflow)?;
774 self.touched.clear();
777 for hit in hits {
778 let p = input.rings[hit.ring as usize].poly;
779 if self.touched.last() != Some(&p) {
780 self.touched.push(p);
781 }
782 }
783 self.extra.clear();
786 let touched = &self.touched;
787 self.extra.extend(
788 self.covering
789 .iter()
790 .filter(|p| touched.binary_search(p).is_err()),
791 );
792 self.extra.sort_unstable();
793
794 let polys_before = out.poly_ends.len();
795 let (mut next_touched, mut next_extra, mut hit) = (0, 0, 0);
797 loop {
798 let touched = self.touched.get(next_touched).copied();
799 let extra = self.extra.get(next_extra).copied();
800 match (touched, extra) {
801 (Some(poly), fill) if fill.is_none_or(|fill| poly < fill) => {
802 let n =
803 hits[hit..].partition_point(|x| input.rings[x.ring as usize].poly == poly);
804 let poly_hits = &hits[hit..hit + n];
805 self.polygon(input, poly, poly_hits, cs, min, max, origin, out)?;
806 next_touched += 1;
807 hit += n;
808 }
809 (_, Some(fill)) => {
810 let ring_start = out.verts.len();
811 push_fill_box(&mut out.verts, input.polys[fill as usize].orient, min, max)?;
812 localize(&mut out.verts[ring_start..], origin)?;
813 out.ring_ends.push(offset(out.verts.len())?);
814 out.poly_ends.push(offset(out.ring_ends.len())?);
815 next_extra += 1;
816 }
817 _ => break,
818 }
819 }
820 if out.poly_ends.len() > polys_before {
821 out.tiles.push(TileEntry {
822 tile,
823 poly_end: offset(out.poly_ends.len())?,
824 });
825 }
826 Ok(())
827 }
828
829 #[expect(
836 clippy::too_many_arguments,
837 reason = "the tile context, passed down once per polygon"
838 )]
839 fn polygon<V: PolyVertex>(
840 &mut self,
841 input: &Input<V>,
842 p: u32,
843 hits: &[Hit],
844 cs: &[Crossing],
845 min: Coord<i32>,
846 max: Coord<i32>,
847 origin: Coord<i32>,
848 out: &mut Pieces<V>,
849 ) -> Result<(), TileError> {
850 let info = input.polys[p as usize];
851 let exterior_touched = hits.first().is_some_and(|x| x.ring == info.first);
853 if !exterior_touched && !self.inside[info.first as usize] {
854 return Ok(()); }
856 let holes_in = self.holes_in[p as usize] as usize;
860 if holes_in > 0
861 && holes_in
862 > ring_groups(hits)
863 .filter(|g| g[0].ring != info.first && self.inside[g[0].ring as usize])
864 .count()
865 {
866 return Ok(());
867 }
868 if !exterior_touched {
869 let ring_start = out.verts.len();
870 push_fill_box(&mut out.verts, info.orient, min, max)?;
871 localize(&mut out.verts[ring_start..], origin)?;
872 out.ring_ends.push(offset(out.verts.len())?);
873 }
874 for ring_hits in ring_groups(hits) {
875 let ring = input.rings[ring_hits[0].ring as usize];
876 let ring_start = out.verts.len();
877 self.arcs.clear();
878 for x in ring_hits {
879 keep_edge(&mut self.arcs, (x.edge - ring.start) as usize);
880 }
881 let fenwick = &self.fenwick;
882 let winding =
883 |first: usize, count: usize| excursion_winding(cs, fenwick, ring, first, count);
884 close_ring(
885 input.ring_pts(ring),
886 &mut self.arcs,
887 min,
888 max,
889 winding,
890 &mut out.verts,
891 )?;
892 localize(&mut out.verts[ring_start..], origin)?;
893 out.ring_ends.push(offset(out.verts.len())?);
894 }
895 out.poly_ends.push(offset(out.ring_ends.len())?);
896 Ok(())
897 }
898}
899
900fn ring_groups(mut hits: &[Hit]) -> impl Iterator<Item = &[Hit]> {
903 core::iter::from_fn(move || {
904 let ring = hits.first()?.ring;
905 let (group, rest) = hits.split_at(hits.partition_point(|x| x.ring == ring));
906 hits = rest;
907 Some(group)
908 })
909}
910
911fn excursion_winding(
914 cs: &[Crossing],
915 fenwick: &[i64],
916 ring: RingInfo,
917 first: usize,
918 count: usize,
919) -> i64 {
920 let (start, len) = (ring.start as usize, ring.len as usize);
921 let sum = |lo: usize, hi: usize| {
922 let i = cs.partition_point(|c| (c.edge as usize) < lo);
923 let j = cs.partition_point(|c| (c.edge as usize) < hi);
924 fenwick_prefix(fenwick, j) - fenwick_prefix(fenwick, i)
925 };
926 if first + count <= len {
927 sum(start + first, start + first + count)
928 } else {
929 sum(start + first, start + len) + sum(start, start + first + count - len)
930 }
931}
932
933#[derive(Debug, Clone)]
935struct FeatureEntry<A> {
936 tiles_end: u32,
937 runs_end: u32,
938 attr: A,
939}
940
941#[derive(Debug, Clone)]
958pub struct PolygonSlicerAll<V: PolyVertex = Coord<i32>, A = ()> {
959 grid: Grid,
960 pieces: Pieces<V>,
961 features: Vec<FeatureEntry<A>>,
963 input: Input<V>,
964 scratch: Scratch,
965 max_feature_verts: usize,
967 fill_box: Option<(Coord<i32>, Coord<i32>)>,
970}
971
972impl<V: PolyVertex, A> PolygonSlicerAll<V, A> {
973 pub fn new(extent: u32, buffer: u16) -> Result<Self, TileError> {
981 let grid = Grid::new(extent, buffer)?;
982 let fill_box = grid
984 .tile_buffered_bounds(TileId::new(0, 0))
985 .ok()
986 .and_then(|(min, max)| {
987 let sw = Coord {
988 x: min.x.checked_sub(1)?,
989 y: min.y.checked_sub(1)?,
990 };
991 let ne = Coord {
992 x: max.x.checked_add(1)?,
993 y: max.y.checked_add(1)?,
994 };
995 Some((sw, ne))
996 });
997 Ok(Self {
998 grid,
999 pieces: Pieces {
1000 verts: Vec::new(),
1001 ring_ends: Vec::new(),
1002 poly_ends: Vec::new(),
1003 tiles: Vec::new(),
1004 runs: Vec::new(),
1005 },
1006 features: Vec::new(),
1007 input: Input {
1008 pts: Vec::new(),
1009 rings: Vec::new(),
1010 polys: Vec::new(),
1011 },
1012 scratch: Scratch::new(),
1013 max_feature_verts: MAX_FEATURE_VERTICES,
1014 fill_box,
1015 })
1016 }
1017
1018 #[must_use]
1020 pub fn extent(&self) -> u32 {
1021 self.grid.extent()
1022 }
1023
1024 #[must_use]
1026 pub fn buffer(&self) -> u16 {
1027 self.grid.buffer()
1028 }
1029
1030 #[cfg_attr(feature = "hotpath", hotpath::measure)]
1051 pub fn add_feature_with<P>(&mut self, polygons: P, attr: A) -> Result<&mut Self, TileError>
1052 where
1053 P: IntoIterator,
1054 P::Item: IntoIterator,
1055 <P::Item as IntoIterator>::Item: AsRef<[V]>,
1056 {
1057 self.input.load(polygons)?;
1058 let points = self.input.pts.iter().map(Vertex::position);
1059 if let Some((tile, origin)) = self.grid.inner_tile(points) {
1060 return self.add_in_one_tile(tile, origin, attr);
1061 }
1062 self.input.orient_polygons();
1063 self.scratch
1064 .route(self.grid, &self.input, MAX_TILE_VISITS)?;
1065 let save = self.pieces.savepoint();
1066 let ends = self
1067 .scratch
1068 .sweep(
1069 self.grid,
1070 &self.input,
1071 &mut self.pieces,
1072 self.max_feature_verts,
1073 self.fill_box.is_some(),
1074 )
1075 .and_then(|()| {
1076 Ok((
1077 offset(self.pieces.tiles.len())?,
1078 offset(self.pieces.runs.len())?,
1079 ))
1080 });
1081 match ends {
1082 Ok((tiles_end, runs_end)) => {
1083 if self.pieces.tiles.len() > save.tiles || self.pieces.runs.len() > save.runs {
1084 self.features.push(FeatureEntry {
1085 tiles_end,
1086 runs_end,
1087 attr,
1088 });
1089 }
1090 Ok(self)
1091 }
1092 Err(err) => {
1093 self.pieces.rollback(save);
1094 Err(err)
1095 }
1096 }
1097 }
1098
1099 fn add_in_one_tile(
1103 &mut self,
1104 tile: TileId,
1105 origin: Coord<i32>,
1106 attr: A,
1107 ) -> Result<&mut Self, TileError> {
1108 let save = self.pieces.savepoint();
1109 let result = self.push_in_one_tile(tile, origin, save.verts);
1110 match result {
1111 Ok(()) => {
1112 self.features.push(FeatureEntry {
1113 tiles_end: offset(self.pieces.tiles.len())?,
1114 runs_end: offset(self.pieces.runs.len())?,
1115 attr,
1116 });
1117 Ok(self)
1118 }
1119 Err(err) => {
1120 self.pieces.rollback(save);
1121 Err(err)
1122 }
1123 }
1124 }
1125
1126 fn push_in_one_tile(
1127 &mut self,
1128 tile: TileId,
1129 origin: Coord<i32>,
1130 verts_before: usize,
1131 ) -> Result<(), TileError> {
1132 let (input, out) = (&self.input, &mut self.pieces);
1133 for (i, ring) in input.rings.iter().enumerate() {
1134 let start = out.verts.len();
1137 let closed = ring.start as usize..=(ring.start + ring.len) as usize;
1138 out.verts.extend_from_slice(&input.pts[closed]);
1139 localize(&mut out.verts[start..], origin)?;
1140 out.ring_ends.push(offset(out.verts.len())?);
1141 if input
1142 .rings
1143 .get(i + 1)
1144 .is_none_or(|next| next.poly != ring.poly)
1145 {
1146 out.poly_ends.push(offset(out.ring_ends.len())?);
1147 }
1148 }
1149 if out.verts.len() - verts_before > self.max_feature_verts {
1150 return Err(TileError::OutputTooLarge);
1151 }
1152 out.tiles.push(TileEntry {
1153 tile,
1154 poly_end: offset(out.poly_ends.len())?,
1155 });
1156 Ok(())
1157 }
1158
1159 pub fn iter_features(&self) -> impl Iterator<Item = PolygonFeatureView<'_, V, A>> {
1161 let pieces = &self.pieces;
1162 let features = &self.features;
1163 let fill_box = self.fill_box.unwrap_or_default();
1164 (0..features.len()).map(move |f| {
1165 let (tiles_start, runs_start) = f
1166 .checked_sub(1)
1167 .map_or((0, 0), |p| (features[p].tiles_end, features[p].runs_end));
1168 let feature = &features[f];
1169 PolygonFeatureView {
1170 pieces,
1171 tiles_start: tiles_start as usize,
1172 tiles_end: feature.tiles_end as usize,
1173 runs: &pieces.runs[runs_start as usize..feature.runs_end as usize],
1174 fill_box,
1175 attr: &feature.attr,
1176 }
1177 })
1178 }
1179
1180 #[must_use]
1182 pub fn len(&self) -> usize {
1183 self.features.len()
1184 }
1185
1186 #[must_use]
1188 pub fn is_empty(&self) -> bool {
1189 self.features.is_empty()
1190 }
1191
1192 pub fn clear(&mut self) {
1194 self.pieces.clear();
1195 self.features.clear();
1196 }
1197
1198 pub fn shrink_to_fit(&mut self) {
1202 self.pieces.shrink_to_fit();
1203 self.features.shrink_to_fit();
1204 self.input = Input {
1205 pts: Vec::new(),
1206 rings: Vec::new(),
1207 polys: Vec::new(),
1208 };
1209 self.scratch = Scratch::new();
1210 }
1211}
1212
1213impl<V: PolyVertex> PolygonSlicerAll<V, ()> {
1214 pub fn add_feature<P>(&mut self, polygons: P) -> Result<&mut Self, TileError>
1221 where
1222 P: IntoIterator,
1223 P::Item: IntoIterator,
1224 <P::Item as IntoIterator>::Item: AsRef<[V]>,
1225 {
1226 self.add_feature_with(polygons, ())
1227 }
1228}
1229
1230pub struct PolygonFeatureView<'a, V: PolyVertex, A = ()> {
1232 pieces: &'a Pieces<V>,
1233 tiles_start: usize,
1235 tiles_end: usize,
1236 runs: &'a [FillRun],
1237 fill_box: (Coord<i32>, Coord<i32>),
1239 attr: &'a A,
1240}
1241
1242impl<'a, V: PolyVertex, A> PolygonFeatureView<'a, V, A> {
1243 #[must_use]
1246 pub fn attr(&self) -> &'a A {
1247 self.attr
1248 }
1249
1250 pub fn iter_tiles(&self) -> impl Iterator<Item = PolygonTileView<'a, V, A>> + use<'a, V, A> {
1253 let (pieces, attr) = (self.pieces, self.attr);
1254 (self.tiles_start..self.tiles_end).map(move |index| PolygonTileView {
1255 pieces,
1256 index,
1257 attr,
1258 })
1259 }
1260
1261 pub fn iter_fill_runs(&self) -> impl Iterator<Item = FillRun> + use<'a, V, A> {
1264 self.runs.iter().cloned()
1265 }
1266
1267 #[must_use]
1271 pub fn fill_ring(&self, run: &FillRun) -> [V; 5] {
1272 let (sw, ne) = self.fill_box;
1273 fill_box(run.orient, sw, ne).map(V::synthetic_at)
1274 }
1275}
1276
1277pub struct PolygonTileView<'a, V: PolyVertex, A = ()> {
1279 pieces: &'a Pieces<V>,
1280 index: usize,
1281 attr: &'a A,
1282}
1283
1284impl<'a, V: PolyVertex, A> PolygonTileView<'a, V, A> {
1285 #[must_use]
1287 pub fn tile_id(&self) -> TileId {
1288 self.pieces.tiles[self.index].tile
1289 }
1290
1291 pub fn iter_polygons(&self) -> impl Iterator<Item = PolygonView<'a, V, A>> + use<'a, V, A> {
1294 let (pieces, attr) = (self.pieces, self.attr);
1295 let start = self
1296 .index
1297 .checked_sub(1)
1298 .map_or(0, |prev| pieces.tiles[prev].poly_end as usize);
1299 (start..pieces.tiles[self.index].poly_end as usize).map(move |p| {
1300 PolygonView::new(
1301 &pieces.verts,
1302 &pieces.ring_ends,
1303 span(&pieces.poly_ends, p),
1304 attr,
1305 )
1306 })
1307 }
1308}
1309
1310copy_view!(PolygonFeatureView<A>: PolyVertex, PolygonTileView<A>: PolyVertex);
1311
1312#[cfg(test)]
1313mod tests {
1314 use super::*;
1315
1316 #[test]
1317 fn fenwick_matches_brute_force() {
1318 let values = [3, -1, 4, 1, -5, 9, 2, -6, 5, 3, -5];
1319 let mut current = values.to_vec();
1320 let mut tree = Vec::new();
1321 fenwick_build(&mut tree, values.iter().copied());
1322 for (i, delta) in [(4, 5), (0, -3), (10, 7), (6, -2)] {
1323 fenwick_add(&mut tree, i, delta);
1324 current[i] += delta;
1325 for end in 0..=current.len() {
1326 assert_eq!(
1327 fenwick_prefix(&tree, end),
1328 current[..end].iter().sum::<i64>()
1329 );
1330 }
1331 }
1332 }
1333
1334 #[test]
1335 fn row_center_matches_midpoint() {
1336 for extent in [1, 2, 3, 4, 25, 256, 4096] {
1337 for buffer in [0, 1, (extent - 1) / 2] {
1338 for ty in -5..=5 {
1339 assert_eq!(
1340 row_center(ty, extent),
1341 i64::midpoint(ty * extent - buffer, ty * extent + extent - 1 + buffer),
1342 "extent {extent}, buffer {buffer}, row {ty}"
1343 );
1344 }
1345 }
1346 }
1347 }
1348
1349 #[test]
1350 fn sort_hits_matches_a_plain_sort() {
1351 let routed = |tiles: &[(i32, i32)], per_edge: u32| -> Vec<Hit> {
1355 (0..)
1356 .zip(tiles)
1357 .map(|(i, &(tx, ty))| Hit {
1358 ty,
1359 tx,
1360 edge: i / per_edge,
1361 ring: 0,
1362 })
1363 .collect()
1364 };
1365 let long_runs: Vec<_> = [(1, 1), (0, 1), (0, 0), (1, 0), (1, 1), (0, 1)]
1366 .iter()
1367 .flat_map(|&t| [t; 20])
1368 .collect();
1369 let short_runs: Vec<_> = (0..100).map(|i| (i % 7 - 3, i % 3 - 1)).collect();
1370 let diagonal: Vec<_> = (0..64).map(|i| ((i * 13) % 64, (i * 29) % 64)).collect();
1371 let sparse: Vec<_> = (0..40).map(|i| ((i * 977) % 5000, i % 2)).collect();
1372 for (tiles, per_edge) in [
1373 (&long_runs, 1),
1374 (&short_runs, 1),
1375 (&short_runs, 4),
1376 (&diagonal, 1),
1377 (&diagonal, 2),
1378 (&sparse, 1),
1379 ] {
1380 let mut hits = routed(tiles, per_edge);
1381 let mut expected = hits.clone();
1382 expected.sort_unstable_by_key(|h| (h.ty, h.tx, h.edge));
1383 sort_hits(&mut hits, &mut Vec::new(), &mut Vec::new());
1384 let key = |h: &Hit| (h.ty, h.tx, h.edge);
1385 assert_eq!(
1386 hits.iter().map(key).collect::<Vec<_>>(),
1387 expected.iter().map(key).collect::<Vec<_>>()
1388 );
1389 }
1390 }
1391
1392 #[test]
1393 fn output_cap_applies_to_a_feature_in_one_tile() {
1394 let square = [(5, 5), (20, 5), (20, 20), (5, 20)].map(|(x, y)| Coord { x, y });
1396 let mut s = PolygonSlicerAll::<Coord<i32>>::new(25, 2).expect("config");
1397 let empty = format!("{:?}", s.pieces);
1398 s.max_feature_verts = 3;
1399 let err = s.add_feature([[&square[..]]]).err();
1400 assert_eq!(err, Some(TileError::OutputTooLarge));
1401 assert!(s.is_empty(), "the rejected feature is not recorded");
1402 assert_eq!(format!("{:?}", s.pieces), empty, "nor any of its pieces");
1403 }
1404
1405 #[test]
1406 fn output_cap_rejects_the_feature_atomically() {
1407 let small = [(5, 5), (20, 5), (20, 20), (5, 20)].map(|(x, y)| Coord { x, y });
1408 let big = [(5, 5), (190, 5), (190, 190), (5, 190)].map(|(x, y)| Coord { x, y });
1409 let mut s = PolygonSlicerAll::<Coord<i32>>::new(25, 2).expect("config");
1410 s.add_feature([[&small[..]]]).expect("slice");
1411 let before = format!("{:?}", s.pieces);
1412 s.max_feature_verts = 40;
1413 let err = s.add_feature([[&big[..]]]).err();
1414 assert_eq!(err, Some(TileError::OutputTooLarge));
1415 assert_eq!(s.len(), 1, "the rejected feature is not recorded");
1416 assert_eq!(format!("{:?}", s.pieces), before, "nor any of its pieces");
1417 s.max_feature_verts = MAX_FEATURE_VERTICES;
1418 s.add_feature([[&big[..]]]).expect("under the real cap");
1419 assert_eq!(s.len(), 2);
1420 }
1421
1422 #[test]
1423 fn shrink_to_fit_releases_working_memory() {
1424 let ring = [(5, 5), (190, 5), (190, 190), (5, 190)].map(|(x, y)| Coord { x, y });
1425 let mut s = PolygonSlicerAll::<Coord<i32>>::new(25, 2).expect("config");
1426 s.add_feature([[&ring[..]]]).expect("slice");
1427 let output = format!("{:?}", s.pieces);
1428 s.clear();
1429 assert!(s.scratch.hits.capacity() > 0 && s.pieces.verts.capacity() > 0);
1430 s.shrink_to_fit();
1431 assert_eq!(s.scratch.hits.capacity(), 0);
1432 assert_eq!(s.input.pts.capacity(), 0);
1433 assert_eq!(s.pieces.verts.capacity(), 0);
1434 s.add_feature([[&ring[..]]]).expect("slice");
1435 assert_eq!(
1436 format!("{:?}", s.pieces),
1437 output,
1438 "a shrunk slicer works the same"
1439 );
1440 }
1441
1442 #[test]
1443 fn budget_counts_visited_tiles_across_rings() {
1444 let square = [(0, 0), (900, 0), (900, 900), (0, 900)].map(|(x, y)| Coord { x, y });
1445 let diagonal = [(3, 5), (2990, 2000), (40, 2900)].map(|(x, y)| Coord { x, y });
1446 let grid = Grid::new(10, 2).expect("config");
1447 let mut input = Input {
1448 pts: Vec::new(),
1449 rings: Vec::new(),
1450 polys: Vec::new(),
1451 };
1452 let mut scratch = Scratch::new();
1453 let mut visits = |rings: &[&[Coord<i32>]], budget| {
1455 input.load(rings.iter().map(|r| [*r])).expect("load");
1456 scratch
1457 .route(grid, &input, budget)
1458 .map(|()| i64::try_from(scratch.hits.len()).unwrap())
1459 };
1460 let alone = visits(&[&diagonal], MAX_TILE_VISITS).expect("route");
1461 let square_alone = visits(&[&square], MAX_TILE_VISITS).expect("route");
1462 let both = visits(&[&square, &diagonal], MAX_TILE_VISITS).expect("route");
1463 assert_eq!(alone + square_alone, both);
1466 assert_eq!(visits(&[&diagonal], alone), Ok(alone));
1467 assert_eq!(visits(&[&square, &diagonal], both), Ok(both));
1468 assert_eq!(
1469 visits(&[&square, &diagonal], both - 1),
1470 Err(TileError::TooManyTiles)
1471 );
1472 assert_eq!(
1473 visits(&[&diagonal], alone - 1),
1474 Err(TileError::TooManyTiles)
1475 );
1476 }
1477
1478 #[test]
1479 fn clear_keeps_capacity() {
1480 let ring = [(5, 5), (190, 5), (190, 190), (5, 190)].map(|(x, y)| Coord { x, y });
1481 let hole = [(60, 60), (60, 120), (120, 120), (120, 60)].map(|(x, y)| Coord { x, y });
1482 let mut s = PolygonSlicerAll::<Coord<i32>>::new(25, 2).expect("config");
1483 s.add_feature([[&ring[..], &hole[..]]]).expect("slice");
1484 let capacities = |s: &PolygonSlicerAll<Coord<i32>>| {
1485 [
1486 s.pieces.verts.capacity(),
1487 s.pieces.ring_ends.capacity(),
1488 s.pieces.tiles.capacity(),
1489 s.pieces.runs.capacity(),
1490 s.features.capacity(),
1491 s.input.pts.capacity(),
1492 s.scratch.hits.capacity(),
1493 s.scratch.crossings.capacity(),
1494 ]
1495 };
1496 let warm = capacities(&s);
1497 let output = format!("{:?}", s.pieces);
1498 s.clear();
1499 assert!(s.is_empty());
1500 assert_eq!(capacities(&s), warm, "clear keeps every buffer");
1501 s.add_feature([[&ring[..], &hole[..]]]).expect("slice");
1502 assert_eq!(
1503 capacities(&s),
1504 warm,
1505 "a warmed-up slicer does not grow for the same feature"
1506 );
1507 assert_eq!(format!("{:?}", s.pieces), output);
1508 }
1509}