Skip to main content

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(&mut self) -> BBox3D {
89        match self {
90            VectorGeometry::Point(g) => {
91                if g.bbox.is_none() {
92                    g.bbox = Some(BBox3D::from_point(&g.coordinates));
93                }
94                g.bbox.unwrap()
95            }
96            VectorGeometry::MultiPoint(g) => {
97                if g.bbox.is_none() {
98                    g.bbox = Some(BBox3D::from_linestring(&g.coordinates));
99                }
100                g.bbox.unwrap()
101            }
102            VectorGeometry::LineString(g) => {
103                if g.bbox.is_none() {
104                    g.bbox = Some(BBox3D::from_linestring(&g.coordinates));
105                }
106                g.bbox.unwrap()
107            }
108            VectorGeometry::MultiLineString(g) => {
109                if g.bbox.is_none() {
110                    g.bbox = Some(BBox3D::from_multi_linestring(&g.coordinates));
111                }
112                g.bbox.unwrap()
113            }
114            VectorGeometry::Polygon(g) => {
115                if g.bbox.is_none() {
116                    g.bbox = Some(BBox3D::from_polygon(&g.coordinates));
117                }
118                g.bbox.unwrap()
119            }
120            VectorGeometry::MultiPolygon(g) => {
121                if g.bbox.is_none() {
122                    g.bbox = Some(BBox3D::from_multi_polygon(&g.coordinates));
123                }
124                g.bbox.unwrap()
125            }
126        }
127    }
128
129    /// Get the vec_bbox of the geometry
130    pub fn vec_bbox(&self) -> &Option<BBox3D> {
131        match self {
132            VectorGeometry::Point(g) => &g.vec_bbox,
133            VectorGeometry::MultiPoint(g) => &g.vec_bbox,
134            VectorGeometry::LineString(g) => &g.vec_bbox,
135            VectorGeometry::MultiLineString(g) => &g.vec_bbox,
136            VectorGeometry::Polygon(g) => &g.vec_bbox,
137            VectorGeometry::MultiPolygon(g) => &g.vec_bbox,
138        }
139    }
140
141    /// Get the geometry point
142    pub fn point(&self) -> Option<&VectorPoint<M>> {
143        match self {
144            VectorGeometry::Point(g) => Some(&g.coordinates),
145            _ => None,
146        }
147    }
148
149    /// Create a new point
150    pub fn new_point(coordinates: VectorPoint<M>, bbox: Option<BBox3D>) -> Self {
151        VectorGeometry::Point(VectorPointGeometry {
152            _type: VectorGeometryType::Point,
153            is_3d: coordinates.z.is_some(),
154            coordinates,
155            bbox,
156            ..Default::default()
157        })
158    }
159
160    /// Get the geometry multi point
161    pub fn multipoint(&self) -> Option<&VectorMultiPoint<M>> {
162        match self {
163            VectorGeometry::MultiPoint(g) => Some(&g.coordinates),
164            _ => None,
165        }
166    }
167
168    /// Create a new multipoint
169    pub fn new_multipoint(coordinates: VectorMultiPoint<M>, bbox: Option<BBox3D>) -> Self {
170        VectorGeometry::MultiPoint(VectorMultiPointGeometry {
171            _type: VectorGeometryType::MultiPoint,
172            is_3d: coordinates.iter().any(|point| point.z.is_some()),
173            coordinates,
174            bbox,
175            ..Default::default()
176        })
177    }
178
179    /// Get the geometry linestring
180    pub fn linestring(&self) -> Option<&VectorLineString<M>> {
181        match self {
182            VectorGeometry::LineString(g) => Some(&g.coordinates),
183            _ => None,
184        }
185    }
186
187    /// Create a new linestring
188    pub fn new_linestring(coordinates: VectorLineString<M>, bbox: Option<BBox3D>) -> Self {
189        VectorGeometry::LineString(VectorLineStringGeometry {
190            _type: VectorGeometryType::LineString,
191            is_3d: coordinates.iter().any(|point| point.z.is_some()),
192            coordinates,
193            bbox,
194            ..Default::default()
195        })
196    }
197
198    /// Get the geometry multilinestring
199    pub fn multilinestring(&self) -> Option<&VectorMultiLineString<M>> {
200        match self {
201            VectorGeometry::MultiLineString(g) => Some(&g.coordinates),
202            _ => None,
203        }
204    }
205
206    /// Create a new multilinestring
207    pub fn new_multilinestring(
208        coordinates: VectorMultiLineString<M>,
209        bbox: Option<BBox3D>,
210    ) -> Self {
211        VectorGeometry::MultiLineString(VectorMultiLineStringGeometry {
212            _type: VectorGeometryType::MultiLineString,
213            is_3d: coordinates.iter().any(|line| line.iter().any(|point| point.z.is_some())),
214            coordinates,
215            bbox,
216            ..Default::default()
217        })
218    }
219
220    /// Get the geometry polygon
221    pub fn polygon(&self) -> Option<&VectorPolygon<M>> {
222        match self {
223            VectorGeometry::Polygon(g) => Some(&g.coordinates),
224            _ => None,
225        }
226    }
227
228    /// Create a new polygon
229    pub fn new_polygon(coordinates: VectorPolygon<M>, bbox: Option<BBox3D>) -> Self {
230        VectorGeometry::Polygon(VectorPolygonGeometry {
231            _type: VectorGeometryType::Polygon,
232            is_3d: coordinates.iter().any(|ring| ring.iter().any(|point| point.z.is_some())),
233            coordinates,
234            bbox,
235            ..Default::default()
236        })
237    }
238
239    /// Get the geometry multipolygon
240    pub fn multipolygon(&self) -> Option<&VectorMultiPolygon<M>> {
241        match self {
242            VectorGeometry::MultiPolygon(g) => Some(&g.coordinates),
243            _ => None,
244        }
245    }
246
247    /// Create a new multipolygon
248    pub fn new_multipolygon(coordinates: VectorMultiPolygon<M>, bbox: Option<BBox3D>) -> Self {
249        VectorGeometry::MultiPolygon(VectorMultiPolygonGeometry {
250            _type: VectorGeometryType::MultiPolygon,
251            is_3d: coordinates.iter().any(|polygon| {
252                polygon.iter().any(|ring| ring.iter().any(|point| point.z.is_some()))
253            }),
254            coordinates,
255            bbox,
256            ..Default::default()
257        })
258    }
259
260    /// set the tessellation of the geometry (polygon and multipolygon only)
261    pub fn set_tess(&mut self, tessellation: Vec<f64>) {
262        match self {
263            VectorGeometry::Polygon(g) => g.tessellation = Some(tessellation),
264            VectorGeometry::MultiPolygon(g) => g.tessellation = Some(tessellation),
265            _ => {}
266        }
267    }
268
269    /// set the indices of the geometry (polygon and multipolygon only)
270    pub fn set_indices(&mut self, indices: Vec<u32>) {
271        match self {
272            VectorGeometry::Polygon(g) => g.indices = Some(indices),
273            VectorGeometry::MultiPolygon(g) => g.indices = Some(indices),
274            _ => {}
275        }
276    }
277
278    /// Convert the geometry so that all m-values are MValue rather then user defined
279    pub fn to_m_geometry(&self) -> VectorGeometry<MValue>
280    where
281        M: MValueCompatible,
282    {
283        match self {
284            VectorGeometry::Point(g) => VectorGeometry::Point(VectorPointGeometry {
285                _type: g._type,
286                is_3d: g.is_3d,
287                coordinates: g.coordinates.to_m_value(),
288                offset: g.offset.clone(),
289                bbox: g.bbox,
290                vec_bbox: g.vec_bbox,
291                ..Default::default()
292            }),
293            VectorGeometry::MultiPoint(g) => VectorGeometry::MultiPoint(VectorMultiPointGeometry {
294                _type: g._type,
295                is_3d: g.is_3d,
296                coordinates: g.coordinates.iter().map(|point| point.to_m_value()).collect(),
297                offset: g.offset,
298                bbox: g.bbox,
299                vec_bbox: g.vec_bbox,
300                ..Default::default()
301            }),
302            VectorGeometry::LineString(g) => VectorGeometry::LineString(VectorLineStringGeometry {
303                _type: g._type,
304                is_3d: g.is_3d,
305                coordinates: g.coordinates.iter().map(|point| point.to_m_value()).collect(),
306                offset: g.offset,
307                bbox: g.bbox,
308                vec_bbox: g.vec_bbox,
309                ..Default::default()
310            }),
311            VectorGeometry::MultiLineString(g) => {
312                VectorGeometry::MultiLineString(VectorMultiLineStringGeometry {
313                    _type: g._type,
314                    is_3d: g.is_3d,
315                    coordinates: g
316                        .coordinates
317                        .iter()
318                        .map(|line| line.iter().map(|point| point.to_m_value()).collect())
319                        .collect(),
320                    offset: g.offset.clone(),
321                    bbox: g.bbox,
322                    vec_bbox: g.vec_bbox,
323                    ..Default::default()
324                })
325            }
326            VectorGeometry::Polygon(g) => VectorGeometry::Polygon(VectorPolygonGeometry {
327                _type: g._type,
328                is_3d: g.is_3d,
329                coordinates: g
330                    .coordinates
331                    .iter()
332                    .map(|ring| ring.iter().map(|point| point.to_m_value()).collect())
333                    .collect(),
334                offset: g.offset.clone(),
335                bbox: g.bbox,
336                vec_bbox: g.vec_bbox,
337                ..Default::default()
338            }),
339            VectorGeometry::MultiPolygon(g) => {
340                VectorGeometry::MultiPolygon(VectorMultiPolygonGeometry {
341                    _type: g._type,
342                    is_3d: g.is_3d,
343                    coordinates: g
344                        .coordinates
345                        .iter()
346                        .map(|polygon| {
347                            polygon
348                                .iter()
349                                .map(|ring| ring.iter().map(|point| point.to_m_value()).collect())
350                                .collect()
351                        })
352                        .collect(),
353                    offset: g.offset.clone(),
354                    bbox: g.bbox,
355                    vec_bbox: g.vec_bbox,
356                    ..Default::default()
357                })
358            }
359        }
360    }
361}
362impl<M: Clone + Default> Default for VectorGeometry<M> {
363    fn default() -> Self {
364        VectorGeometry::Point(VectorPointGeometry::default())
365    }
366}
367
368/// BaseGeometry is the a generic geometry type
369#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
370pub struct VectorBaseGeometry<G = VectorGeometry, O = VectorOffsets> {
371    /// The geometry type
372    #[serde(rename = "type")]
373    pub _type: VectorGeometryType,
374    /// Specifies if the geometry is 3D or 2D
375    #[serde(rename = "is3D", default)]
376    pub is_3d: bool,
377    /// The geometry shape
378    pub coordinates: G,
379    /// The geometry offsets if applicable
380    #[serde(skip_serializing_if = "Option::is_none")]
381    pub offset: Option<O>,
382    /// The BBox shape - always in lon-lat
383    #[serde(skip_serializing_if = "Option::is_none")]
384    pub bbox: Option<BBox3D>,
385    /// temporary bbox to track 0->1 clipping
386    #[serde(skip)]
387    pub vec_bbox: Option<BBox3D>,
388    /// Polygon and MultiPolygon specific property
389    #[serde(skip_serializing_if = "Option::is_none")]
390    pub indices: Option<Vec<u32>>,
391    /// Polygon and MultiPolygon specific property
392    #[serde(skip_serializing_if = "Option::is_none")]
393    pub tessellation: Option<Vec<f64>>,
394}
395
396/// All possible geometry offsets
397#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
398pub enum VectorOffsets {
399    /// LineString offset
400    LineOffset(VectorLineOffset),
401    /// MultiLineString offset
402    MultiLineOffset(VectorMultiLineOffset),
403    /// Polygon offset
404    PolygonOffset(VectorPolygonOffset),
405    /// MultiPolygon offset
406    MultiPolygonOffset(VectorMultiPolygonOffset),
407}
408impl Default for VectorOffsets {
409    fn default() -> Self {
410        VectorOffsets::LineOffset(0.0)
411    }
412}
413/// An offset defines how far the starting line is from the original starting point pre-slice
414pub type VectorLineOffset = f64;
415/// A collection of offsets
416pub type VectorMultiLineOffset = Vec<VectorLineOffset>;
417/// A collection of offsets
418pub type VectorPolygonOffset = VectorMultiLineOffset;
419/// A collection of collections of offsets
420pub type VectorMultiPolygonOffset = Vec<VectorPolygonOffset>;
421
422/// PointGeometry is a point
423pub type VectorPointGeometry<M = MValue> = VectorBaseGeometry<VectorPoint<M>>;
424/// MultiPointGeometry contains multiple points
425pub type VectorMultiPointGeometry<M = MValue> =
426    VectorBaseGeometry<VectorMultiPoint<M>, VectorLineOffset>;
427/// LineStringGeometry is a line
428pub type VectorLineStringGeometry<M = MValue> =
429    VectorBaseGeometry<VectorLineString<M>, VectorLineOffset>;
430/// MultiLineStringGeometry contains multiple lines
431pub type VectorMultiLineStringGeometry<M = MValue> =
432    VectorBaseGeometry<VectorMultiLineString<M>, VectorMultiLineOffset>;
433/// PolygonGeometry is a polygon with potential holes
434pub type VectorPolygonGeometry<M = MValue> =
435    VectorBaseGeometry<VectorPolygon<M>, VectorPolygonOffset>;
436/// MultiPolygonGeometry is a polygon with multiple polygons with their own potential holes
437pub type VectorMultiPolygonGeometry<M = MValue> =
438    VectorBaseGeometry<VectorMultiPolygon<M>, VectorMultiPolygonOffset>;