s2json_core/geometry/
vector.rs

1use crate::*;
2use alloc::vec::Vec;
3use serde::{Deserialize, Serialize};
4
5/// Enum to represent specific vector geometry types as strings
6#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Default)]
7pub enum VectorGeometryType {
8    /// Point
9    #[default]
10    Point,
11    /// MultiPoint
12    MultiPoint,
13    /// LineString
14    LineString,
15    /// MultiLineString
16    MultiLineString,
17    /// Polygon
18    Polygon,
19    /// MultiPolygon
20    MultiPolygon,
21}
22impl From<&str> for VectorGeometryType {
23    fn from(s: &str) -> Self {
24        match s {
25            "Point" => VectorGeometryType::Point,
26            "MultiPoint" => VectorGeometryType::MultiPoint,
27            "LineString" => VectorGeometryType::LineString,
28            "MultiLineString" => VectorGeometryType::MultiLineString,
29            "Polygon" => VectorGeometryType::Polygon,
30            "MultiPolygon" => VectorGeometryType::MultiPolygon,
31            _ => panic!("Invalid vector geometry type: {}", s),
32        }
33    }
34}
35
36/// Definition of a Vector MultiPoint
37pub type VectorMultiPoint<M = MValue> = Vec<VectorPoint<M>>;
38/// Definition of a Vector LineString
39pub type VectorLineString<M = MValue> = Vec<VectorPoint<M>>;
40/// Definition of a Vector MultiLineString
41pub type VectorMultiLineString<M = MValue> = Vec<VectorLineString<M>>;
42/// Definition of a Vector Polygon
43pub type VectorPolygon<M = MValue> = Vec<VectorLineString<M>>;
44/// Definition of a Vector MultiPolygon
45pub type VectorMultiPolygon<M = MValue> = Vec<VectorPolygon<M>>;
46
47/// # Vector Geometry
48///
49/// ## Description
50/// All possible geometry shapes. Builds ontop of [`VectorBaseGeometry`].
51///
52/// ## Usage
53/// - [`VectorGeometry::bbox`]: Get the bbox of the geometry
54/// - [`VectorGeometry::vec_bbox`]: Get the internal 0-1 clipping style vector bbox
55/// - [`VectorGeometry::point`]: Get the geometry point
56/// - [`VectorGeometry::new_point`]: Create a new point
57/// - [`VectorGeometry::multipoint`]: Get the geometry multi point
58/// - [`VectorGeometry::new_multipoint`]: Create a new multipoint
59/// - [`VectorGeometry::linestring`]: Get the geometry line string
60/// - [`VectorGeometry::new_linestring`]: Create a new linestring
61/// - [`VectorGeometry::multilinestring`]: Get the geometry multi line string
62/// - [`VectorGeometry::new_multilinestring`]: Create a new multi line string
63/// - [`VectorGeometry::polygon`]: Get the geometry polygon
64/// - [`VectorGeometry::new_polygon`]: Create a new polygon
65/// - [`VectorGeometry::multipolygon`]: Get the geometry multi polygon
66/// - [`VectorGeometry::new_multipolygon`]: Create a new multi polygon
67/// - [`VectorGeometry::set_tess`]: Set the tessellation of the geometry (polygon and multipolygon only)
68/// - [`VectorGeometry::set_indices`]: Set the indices of the geometry (polygon and multipolygon only)
69/// - [`VectorGeometry::to_m_geometry`]: Convert the geometry so that all m-values are MValue rather then user defined
70#[derive(Clone, Serialize, Debug, PartialEq)]
71#[serde(untagged)]
72pub enum VectorGeometry<M: Clone + Default = MValue> {
73    /// Point Shape
74    Point(VectorPointGeometry<M>),
75    /// MultiPoint Shape
76    MultiPoint(VectorMultiPointGeometry<M>),
77    /// LineString Shape
78    LineString(VectorLineStringGeometry<M>),
79    /// MultiLineString Shape
80    MultiLineString(VectorMultiLineStringGeometry<M>),
81    /// Polygon Shape
82    Polygon(VectorPolygonGeometry<M>),
83    /// MultiPolygon Shape
84    MultiPolygon(VectorMultiPolygonGeometry<M>),
85}
86impl<M: Clone + Default> VectorGeometry<M> {
87    /// Get the bbox of the geometry
88    pub fn bbox(&self) -> &Option<BBox3D> {
89        match self {
90            VectorGeometry::Point(g) => &g.bbox,
91            VectorGeometry::MultiPoint(g) => &g.bbox,
92            VectorGeometry::LineString(g) => &g.bbox,
93            VectorGeometry::MultiLineString(g) => &g.bbox,
94            VectorGeometry::Polygon(g) => &g.bbox,
95            VectorGeometry::MultiPolygon(g) => &g.bbox,
96        }
97    }
98
99    /// Get the vec_bbox of the geometry
100    pub fn vec_bbox(&self) -> &Option<BBox3D> {
101        match self {
102            VectorGeometry::Point(g) => &g.vec_bbox,
103            VectorGeometry::MultiPoint(g) => &g.vec_bbox,
104            VectorGeometry::LineString(g) => &g.vec_bbox,
105            VectorGeometry::MultiLineString(g) => &g.vec_bbox,
106            VectorGeometry::Polygon(g) => &g.vec_bbox,
107            VectorGeometry::MultiPolygon(g) => &g.vec_bbox,
108        }
109    }
110
111    /// Get the geometry point
112    pub fn point(&self) -> Option<&VectorPoint<M>> {
113        match self {
114            VectorGeometry::Point(g) => Some(&g.coordinates),
115            _ => None,
116        }
117    }
118
119    /// Create a new point
120    pub fn new_point(coordinates: VectorPoint<M>, bbox: Option<BBox3D>) -> Self {
121        VectorGeometry::Point(VectorPointGeometry {
122            _type: VectorGeometryType::Point,
123            is_3d: coordinates.z.is_some(),
124            coordinates,
125            bbox,
126            ..Default::default()
127        })
128    }
129
130    /// Get the geometry multi point
131    pub fn multipoint(&self) -> Option<&VectorMultiPoint<M>> {
132        match self {
133            VectorGeometry::MultiPoint(g) => Some(&g.coordinates),
134            _ => None,
135        }
136    }
137
138    /// Create a new multipoint
139    pub fn new_multipoint(coordinates: VectorMultiPoint<M>, bbox: Option<BBox3D>) -> Self {
140        VectorGeometry::MultiPoint(VectorMultiPointGeometry {
141            _type: VectorGeometryType::MultiPoint,
142            is_3d: coordinates.iter().any(|point| point.z.is_some()),
143            coordinates,
144            bbox,
145            ..Default::default()
146        })
147    }
148
149    /// Get the geometry linestring
150    pub fn linestring(&self) -> Option<&VectorLineString<M>> {
151        match self {
152            VectorGeometry::LineString(g) => Some(&g.coordinates),
153            _ => None,
154        }
155    }
156
157    /// Create a new linestring
158    pub fn new_linestring(coordinates: VectorLineString<M>, bbox: Option<BBox3D>) -> Self {
159        VectorGeometry::LineString(VectorLineStringGeometry {
160            _type: VectorGeometryType::LineString,
161            is_3d: coordinates.iter().any(|point| point.z.is_some()),
162            coordinates,
163            bbox,
164            ..Default::default()
165        })
166    }
167
168    /// Get the geometry multilinestring
169    pub fn multilinestring(&self) -> Option<&VectorMultiLineString<M>> {
170        match self {
171            VectorGeometry::MultiLineString(g) => Some(&g.coordinates),
172            _ => None,
173        }
174    }
175
176    /// Create a new multilinestring
177    pub fn new_multilinestring(
178        coordinates: VectorMultiLineString<M>,
179        bbox: Option<BBox3D>,
180    ) -> Self {
181        VectorGeometry::MultiLineString(VectorMultiLineStringGeometry {
182            _type: VectorGeometryType::MultiLineString,
183            is_3d: coordinates.iter().any(|line| line.iter().any(|point| point.z.is_some())),
184            coordinates,
185            bbox,
186            ..Default::default()
187        })
188    }
189
190    /// Get the geometry polygon
191    pub fn polygon(&self) -> Option<&VectorPolygon<M>> {
192        match self {
193            VectorGeometry::Polygon(g) => Some(&g.coordinates),
194            _ => None,
195        }
196    }
197
198    /// Create a new polygon
199    pub fn new_polygon(coordinates: VectorPolygon<M>, bbox: Option<BBox3D>) -> Self {
200        VectorGeometry::Polygon(VectorPolygonGeometry {
201            _type: VectorGeometryType::Polygon,
202            is_3d: coordinates.iter().any(|ring| ring.iter().any(|point| point.z.is_some())),
203            coordinates,
204            bbox,
205            ..Default::default()
206        })
207    }
208
209    /// Get the geometry multipolygon
210    pub fn multipolygon(&self) -> Option<&VectorMultiPolygon<M>> {
211        match self {
212            VectorGeometry::MultiPolygon(g) => Some(&g.coordinates),
213            _ => None,
214        }
215    }
216
217    /// Create a new multipolygon
218    pub fn new_multipolygon(coordinates: VectorMultiPolygon<M>, bbox: Option<BBox3D>) -> Self {
219        VectorGeometry::MultiPolygon(VectorMultiPolygonGeometry {
220            _type: VectorGeometryType::MultiPolygon,
221            is_3d: coordinates.iter().any(|polygon| {
222                polygon.iter().any(|ring| ring.iter().any(|point| point.z.is_some()))
223            }),
224            coordinates,
225            bbox,
226            ..Default::default()
227        })
228    }
229
230    /// set the tessellation of the geometry (polygon and multipolygon only)
231    pub fn set_tess(&mut self, tessellation: Vec<f64>) {
232        match self {
233            VectorGeometry::Polygon(g) => g.tessellation = Some(tessellation),
234            VectorGeometry::MultiPolygon(g) => g.tessellation = Some(tessellation),
235            _ => {}
236        }
237    }
238
239    /// set the indices of the geometry (polygon and multipolygon only)
240    pub fn set_indices(&mut self, indices: Vec<u32>) {
241        match self {
242            VectorGeometry::Polygon(g) => g.indices = Some(indices),
243            VectorGeometry::MultiPolygon(g) => g.indices = Some(indices),
244            _ => {}
245        }
246    }
247
248    /// Convert the geometry so that all m-values are MValue rather then user defined
249    pub fn to_m_geometry(&self) -> VectorGeometry<MValue>
250    where
251        M: MValueCompatible,
252    {
253        match self {
254            VectorGeometry::Point(g) => VectorGeometry::Point(VectorPointGeometry {
255                _type: g._type,
256                is_3d: g.is_3d,
257                coordinates: g.coordinates.to_m_value(),
258                offset: g.offset.clone(),
259                bbox: g.bbox,
260                vec_bbox: g.vec_bbox,
261                ..Default::default()
262            }),
263            VectorGeometry::MultiPoint(g) => VectorGeometry::MultiPoint(VectorMultiPointGeometry {
264                _type: g._type,
265                is_3d: g.is_3d,
266                coordinates: g.coordinates.iter().map(|point| point.to_m_value()).collect(),
267                offset: g.offset,
268                bbox: g.bbox,
269                vec_bbox: g.vec_bbox,
270                ..Default::default()
271            }),
272            VectorGeometry::LineString(g) => VectorGeometry::LineString(VectorLineStringGeometry {
273                _type: g._type,
274                is_3d: g.is_3d,
275                coordinates: g.coordinates.iter().map(|point| point.to_m_value()).collect(),
276                offset: g.offset,
277                bbox: g.bbox,
278                vec_bbox: g.vec_bbox,
279                ..Default::default()
280            }),
281            VectorGeometry::MultiLineString(g) => {
282                VectorGeometry::MultiLineString(VectorMultiLineStringGeometry {
283                    _type: g._type,
284                    is_3d: g.is_3d,
285                    coordinates: g
286                        .coordinates
287                        .iter()
288                        .map(|line| line.iter().map(|point| point.to_m_value()).collect())
289                        .collect(),
290                    offset: g.offset.clone(),
291                    bbox: g.bbox,
292                    vec_bbox: g.vec_bbox,
293                    ..Default::default()
294                })
295            }
296            VectorGeometry::Polygon(g) => VectorGeometry::Polygon(VectorPolygonGeometry {
297                _type: g._type,
298                is_3d: g.is_3d,
299                coordinates: g
300                    .coordinates
301                    .iter()
302                    .map(|ring| ring.iter().map(|point| point.to_m_value()).collect())
303                    .collect(),
304                offset: g.offset.clone(),
305                bbox: g.bbox,
306                vec_bbox: g.vec_bbox,
307                ..Default::default()
308            }),
309            VectorGeometry::MultiPolygon(g) => {
310                VectorGeometry::MultiPolygon(VectorMultiPolygonGeometry {
311                    _type: g._type,
312                    is_3d: g.is_3d,
313                    coordinates: g
314                        .coordinates
315                        .iter()
316                        .map(|polygon| {
317                            polygon
318                                .iter()
319                                .map(|ring| ring.iter().map(|point| point.to_m_value()).collect())
320                                .collect()
321                        })
322                        .collect(),
323                    offset: g.offset.clone(),
324                    bbox: g.bbox,
325                    vec_bbox: g.vec_bbox,
326                    ..Default::default()
327                })
328            }
329        }
330    }
331}
332impl<M: Clone + Default> Default for VectorGeometry<M> {
333    fn default() -> Self {
334        VectorGeometry::Point(VectorPointGeometry::default())
335    }
336}
337
338/// BaseGeometry is the a generic geometry type
339#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
340pub struct VectorBaseGeometry<G = VectorGeometry, O = VectorOffsets> {
341    /// The geometry type
342    #[serde(rename = "type")]
343    pub _type: VectorGeometryType,
344    /// Specifies if the geometry is 3D or 2D
345    #[serde(rename = "is3D", default)]
346    pub is_3d: bool,
347    /// The geometry shape
348    pub coordinates: G,
349    /// The geometry offsets if applicable
350    #[serde(skip_serializing_if = "Option::is_none")]
351    pub offset: Option<O>,
352    /// The BBox shape - always in lon-lat
353    #[serde(skip_serializing_if = "Option::is_none")]
354    pub bbox: Option<BBox3D>,
355    /// temporary bbox to track 0->1 clipping
356    #[serde(skip)]
357    pub vec_bbox: Option<BBox3D>,
358    /// Polygon and MultiPolygon specific property
359    #[serde(skip_serializing_if = "Option::is_none")]
360    pub indices: Option<Vec<u32>>,
361    /// Polygon and MultiPolygon specific property
362    #[serde(skip_serializing_if = "Option::is_none")]
363    pub tessellation: Option<Vec<f64>>,
364}
365
366/// All possible geometry offsets
367#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
368pub enum VectorOffsets {
369    /// LineString offset
370    LineOffset(VectorLineOffset),
371    /// MultiLineString offset
372    MultiLineOffset(VectorMultiLineOffset),
373    /// Polygon offset
374    PolygonOffset(VectorPolygonOffset),
375    /// MultiPolygon offset
376    MultiPolygonOffset(VectorMultiPolygonOffset),
377}
378impl Default for VectorOffsets {
379    fn default() -> Self {
380        VectorOffsets::LineOffset(0.0)
381    }
382}
383/// An offset defines how far the starting line is from the original starting point pre-slice
384pub type VectorLineOffset = f64;
385/// A collection of offsets
386pub type VectorMultiLineOffset = Vec<VectorLineOffset>;
387/// A collection of offsets
388pub type VectorPolygonOffset = VectorMultiLineOffset;
389/// A collection of collections of offsets
390pub type VectorMultiPolygonOffset = Vec<VectorPolygonOffset>;
391
392/// PointGeometry is a point
393pub type VectorPointGeometry<M = MValue> = VectorBaseGeometry<VectorPoint<M>>;
394/// MultiPointGeometry contains multiple points
395pub type VectorMultiPointGeometry<M = MValue> =
396    VectorBaseGeometry<VectorMultiPoint<M>, VectorLineOffset>;
397/// LineStringGeometry is a line
398pub type VectorLineStringGeometry<M = MValue> =
399    VectorBaseGeometry<VectorLineString<M>, VectorLineOffset>;
400/// MultiLineStringGeometry contains multiple lines
401pub type VectorMultiLineStringGeometry<M = MValue> =
402    VectorBaseGeometry<VectorMultiLineString<M>, VectorMultiLineOffset>;
403/// PolygonGeometry is a polygon with potential holes
404pub type VectorPolygonGeometry<M = MValue> =
405    VectorBaseGeometry<VectorPolygon<M>, VectorPolygonOffset>;
406/// MultiPolygonGeometry is a polygon with multiple polygons with their own potential holes
407pub type VectorMultiPolygonGeometry<M = MValue> =
408    VectorBaseGeometry<VectorMultiPolygon<M>, VectorMultiPolygonOffset>;