Skip to main content

map_tile_toolkit/
polygon_view.rs

1//! Borrowed views of clipped polygons, shared by [`PolygonSlicerOne`](crate::PolygonSlicerOne) and
2//! [`PolygonSlicerAll`](crate::PolygonSlicerAll), over their flat arenas: tile-local ring vertices
3//! and each ring's end offset.
4
5use core::ops::Range;
6
7use crate::TileError;
8use crate::vertex::PolyVertex;
9
10/// `len` as a `u32` arena offset. The flat storage indexes with `u32`; geometry beyond that is
11/// rejected rather than truncated.
12pub(crate) fn offset(len: usize) -> Result<u32, TileError> {
13    u32::try_from(len).map_err(|_| TileError::GeometryTooLarge)
14}
15
16/// The arena span of item `i`, given every item's end offset.
17pub(crate) fn span(ends: &[u32], i: usize) -> Range<usize> {
18    let start = if i == 0 { 0 } else { ends[i - 1] as usize };
19    start..ends[i] as usize
20}
21
22/// A borrowed view of one clipped polygon in one tile: its exterior ring, then its holes, and the
23/// attribute of the feature it comes from.
24pub struct PolygonView<'a, V: PolyVertex, A = ()> {
25    verts: &'a [V],
26    ring_ends: &'a [u32],
27    /// This polygon's rings, `first..end`, as indices into `ring_ends`.
28    first: usize,
29    end: usize,
30    attr: &'a A,
31}
32
33impl<'a, V: PolyVertex, A> PolygonView<'a, V, A> {
34    pub(crate) fn new(
35        verts: &'a [V],
36        ring_ends: &'a [u32],
37        rings: Range<usize>,
38        attr: &'a A,
39    ) -> Self {
40        Self {
41            verts,
42            ring_ends,
43            first: rings.start,
44            end: rings.end,
45            attr,
46        }
47    }
48
49    /// The attribute of the feature this polygon comes from, as passed to `add_feature_with`.
50    #[must_use]
51    pub fn attr(&self) -> &'a A {
52        self.attr
53    }
54
55    /// Iterate the polygon's rings (exterior first, then holes), each closed and in the tile-local
56    /// frame.
57    pub fn iter_rings(&self) -> impl Iterator<Item = RingView<'a, V>> + use<'a, V, A> {
58        let (verts, ends, first) = (self.verts, self.ring_ends, self.first);
59        (first..self.end).map(move |r| RingView {
60            verts: &verts[span(ends, r)],
61            is_hole: r != first,
62        })
63    }
64}
65
66/// A borrowed view of one clipped ring.
67pub struct RingView<'a, V: PolyVertex> {
68    verts: &'a [V],
69    is_hole: bool,
70}
71
72impl<'a, V: PolyVertex> RingView<'a, V> {
73    /// The ring's vertices in the tile-local frame, closed (first vertex repeated at the end).
74    #[must_use]
75    pub fn vertices(&self) -> &'a [V] {
76        self.verts
77    }
78
79    /// Whether this ring is an interior ring (a hole).
80    #[must_use]
81    pub fn is_hole(&self) -> bool {
82        self.is_hole
83    }
84}
85
86/// `Clone` and `Copy` for borrowed views, without requiring them of the attribute or vertex type.
87macro_rules! copy_view {
88    ($($view:ident<$($param:ident),*>: $bound:path),* $(,)?) => {$(
89        #[allow(
90            clippy::expl_impl_clone_on_copy,
91            reason = "a derive would require the vertex and attribute types to be Copy too; some views trip the lint and some do not"
92        )]
93        impl<V: $bound, $($param),*> Clone for $view<'_, V, $($param),*> {
94            fn clone(&self) -> Self {
95                *self
96            }
97        }
98        impl<V: $bound, $($param),*> Copy for $view<'_, V, $($param),*> {}
99    )*};
100}
101pub(crate) use copy_view;
102
103copy_view!(PolygonView<A>: PolyVertex, RingView<>: PolyVertex);