Skip to main content

map_tile_toolkit/
vertex.rs

1//! The [`Vertex`] abstraction: what the slicer needs from a polyline vertex.
2//!
3//! The slicer keeps **original** vertices — it never cuts new ones at a tile edge — so a vertex's
4//! payload (an M / measure value, an id, anything `Copy + PartialEq`) rides through slicing unchanged, with
5//! no interpolation. A vertex therefore only has to expose its integer position for the clipping and
6//! tiling math and be able to produce a copy at a shifted position (for tile-local re-framing).
7//!
8//! [`Coord<i32>`] implements [`Vertex`] (the position *is* the whole vertex), so the
9//! `Geometry<i32>` API keeps working. [`Measured`] pairs a position with an arbitrary payload for
10//! callers that need M values, which `geo-types` cannot represent.
11
12use geo_types::Coord;
13
14/// A polyline vertex the slicer can clip: an integer position plus an opaque `Copy + PartialEq` payload
15/// that is preserved verbatim through slicing and merging.
16pub trait Vertex: Copy + PartialEq {
17    /// The integer `(x, y)` used for every clipping and tiling decision.
18    #[must_use]
19    fn position(&self) -> Coord<i32>;
20
21    /// A copy of `self` moved to `position`, keeping the payload unchanged. Used to re-express a
22    /// vertex in a tile-local frame (`position − origin`).
23    #[must_use]
24    fn with_position(self, position: Coord<i32>) -> Self;
25}
26
27impl Vertex for Coord<i32> {
28    fn position(&self) -> Coord<i32> {
29        *self
30    }
31
32    fn with_position(self, position: Coord<i32>) -> Self {
33        position
34    }
35}
36
37/// A [`Vertex`] carrying a measure/payload `m` (e.g. an M value) alongside its integer position.
38///
39/// The payload only needs to be `Copy + PartialEq`; it is never inspected by the slicer, just moved with
40/// the vertex. Two `Measured` vertices are equal iff both their position and payload are equal.
41#[derive(Debug, Clone, Copy, PartialEq, Hash)]
42pub struct Measured<M: Copy + PartialEq> {
43    /// The integer position used for clipping/tiling.
44    pub position: Coord<i32>,
45    /// The per-vertex payload, preserved through slicing.
46    pub m: M,
47}
48
49impl<M: Copy + PartialEq> Measured<M> {
50    /// A measured vertex at `(x, y)` carrying payload `m`.
51    #[must_use]
52    pub fn new(x: i32, y: i32, m: M) -> Self {
53        Self {
54            position: Coord { x, y },
55            m,
56        }
57    }
58}
59
60impl<M: Copy + PartialEq> Vertex for Measured<M> {
61    fn position(&self) -> Coord<i32> {
62        self.position
63    }
64
65    fn with_position(self, position: Coord<i32>) -> Self {
66        Self { position, ..self }
67    }
68}