gistools/geometry/
geo.rs

1use serde::de::{self, SeqAccess, Visitor};
2use serde::ser::SerializeTuple;
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4
5use alloc::fmt;
6use alloc::vec::Vec;
7
8use core::f64::consts::PI;
9
10use libm::{atan, log, pow, sin, sinh, sqrt};
11
12/// Importing necessary types (equivalent to importing from 'values')
13use crate::values::*;
14use crate::Face;
15
16/// The axis to apply an operation to
17#[derive(Debug, PartialEq, Eq, Clone, Copy)]
18pub enum Axis {
19    /// X axis
20    X = 0,
21    /// Y axis
22    Y = 1,
23}
24
25/// A BBOX is defined in lon-lat space and helps with zooming motion to
26/// see the entire line or polygon
27/// The order is (left, bottom, right, top)
28/// If WM, then the projection is lon-lat
29/// If S2, then the projection is s-t
30#[derive(Copy, Clone, Default, Debug, PartialEq, PartialOrd)]
31pub struct BBox<T = f64> {
32    /// left most longitude (WM) or S (S2)
33    pub left: T,
34    /// bottom most latitude (WM) or T (S2)
35    pub bottom: T,
36    /// right most longitude (WM) or T (S2)
37    pub right: T,
38    /// top most latitude (WM) or S (S2)
39    pub top: T,
40}
41impl<T> BBox<T> {
42    /// Creates a new BBox
43    pub fn new(left: T, bottom: T, right: T, top: T) -> Self
44    where
45        T: Copy,
46    {
47        BBox { left, bottom, right, top }
48    }
49
50    /// Checks if a point is within the BBox
51    pub fn point_overlap(&self, point: VectorPoint) -> bool
52    where
53        T: Into<f64> + Copy, // Ensures that comparison operators work for type T
54    {
55        point.x >= self.left.into()
56            && point.x <= self.right.into()
57            && point.y >= self.bottom.into()
58            && point.y <= self.top.into()
59    }
60
61    /// Merges another bounding box with this one
62    pub fn merge(&self, other: &BBox<T>) -> BBox<T>
63    where
64        T: PartialOrd + Copy,
65    {
66        let mut new_bbox = *self;
67        new_bbox.left = if new_bbox.left < other.left { new_bbox.left } else { other.left };
68        new_bbox.bottom =
69            if new_bbox.bottom < other.bottom { new_bbox.bottom } else { other.bottom };
70        new_bbox.right = if new_bbox.right > other.right { new_bbox.right } else { other.right };
71        new_bbox.top = if new_bbox.top > other.top { new_bbox.top } else { other.top };
72
73        new_bbox
74    }
75
76    /// Checks if another bounding box overlaps with this one and returns the overlap
77    pub fn overlap(&self, other: &BBox<T>) -> Option<BBox<T>>
78    where
79        T: PartialOrd + Copy,
80    {
81        if self.left > other.right
82            || self.right < other.left
83            || self.bottom > other.top
84            || self.top < other.bottom
85        {
86            None
87        } else {
88            let left = if self.left > other.left { self.left } else { other.left };
89            let bottom = if self.bottom > other.bottom { self.bottom } else { other.bottom };
90            let right = if self.right < other.right { self.right } else { other.right };
91            let top = if self.top < other.top { self.top } else { other.top };
92
93            Some(BBox { left, bottom, right, top })
94        }
95    }
96
97    /// Clips the bounding box along an axis
98    pub fn clip(&self, axis: Axis, k1: T, k2: T) -> BBox<T>
99    where
100        T: PartialOrd + Copy,
101    {
102        let mut new_bbox = *self;
103        if axis == Axis::X {
104            new_bbox.left = if new_bbox.left > k1 { new_bbox.left } else { k1 };
105            new_bbox.right = if new_bbox.right < k2 { new_bbox.right } else { k2 };
106        } else {
107            new_bbox.bottom = if new_bbox.bottom > k1 { new_bbox.bottom } else { k1 };
108            new_bbox.top = if new_bbox.top < k2 { new_bbox.top } else { k2 };
109        }
110
111        new_bbox
112    }
113}
114impl BBox<f64> {
115    /// Creates a new BBox from a point
116    pub fn from_point(point: &VectorPoint) -> Self {
117        BBox::new(point.x, point.y, point.x, point.y)
118    }
119
120    /// Extends the bounding box with a point
121    pub fn extend_from_point(&mut self, point: &VectorPoint) {
122        *self = self.merge(&BBox::from_point(point));
123    }
124
125    /// Creates a new BBox from zoom-uv coordinates
126    pub fn from_uv_zoom(u: f64, v: f64, zoom: u8) -> Self {
127        let division_factor = 2. / (1 << zoom) as f64;
128
129        BBox {
130            left: division_factor * u - 1.0,
131            bottom: division_factor * v - 1.0,
132            right: division_factor * (u + 1.0) - 1.0,
133            top: division_factor * (v + 1.0) - 1.0,
134        }
135    }
136
137    /// Creates a new BBox from zoom-st coordinates
138    pub fn from_st_zoom(s: f64, t: f64, zoom: u8) -> Self {
139        let division_factor = (2. / (1 << zoom) as f64) * 0.5;
140
141        BBox {
142            left: division_factor * s,
143            bottom: division_factor * t,
144            right: division_factor * (s + 1.),
145            top: division_factor * (t + 1.),
146        }
147    }
148}
149impl<T> Serialize for BBox<T>
150where
151    T: Serialize + Copy,
152{
153    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
154    where
155        S: Serializer,
156    {
157        let mut seq = serializer.serialize_tuple(4)?;
158        seq.serialize_element(&self.left)?;
159        seq.serialize_element(&self.bottom)?;
160        seq.serialize_element(&self.right)?;
161        seq.serialize_element(&self.top)?;
162        seq.end()
163    }
164}
165impl<'de, T> Deserialize<'de> for BBox<T>
166where
167    T: Deserialize<'de> + Copy,
168{
169    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
170    where
171        D: Deserializer<'de>,
172    {
173        struct BBoxVisitor<T> {
174            marker: core::marker::PhantomData<T>,
175        }
176
177        impl<'de, T> Visitor<'de> for BBoxVisitor<T>
178        where
179            T: Deserialize<'de> + Copy,
180        {
181            type Value = BBox<T>;
182
183            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
184                formatter.write_str("a sequence of four numbers")
185            }
186
187            fn visit_seq<V>(self, mut seq: V) -> Result<BBox<T>, V::Error>
188            where
189                V: SeqAccess<'de>,
190            {
191                let left =
192                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(0, &self))?;
193                let bottom =
194                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(1, &self))?;
195                let right =
196                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(2, &self))?;
197                let top = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(3, &self))?;
198                Ok(BBox { left, bottom, right, top })
199            }
200        }
201
202        deserializer.deserialize_tuple(4, BBoxVisitor { marker: core::marker::PhantomData })
203    }
204}
205
206/// A BBOX is defined in lon-lat space and helps with zooming motion to
207/// see the entire 3D line or polygon
208#[derive(Copy, Clone, Default, Debug, PartialEq, PartialOrd)]
209pub struct BBox3D<T = f64> {
210    /// left most longitude (WM) or S (S2)
211    pub left: T,
212    /// bottom most latitude (WM) or T (S2)
213    pub bottom: T,
214    /// right most longitude (WM) or T (S2)
215    pub right: T,
216    /// top most latitude (WM) or S (S2)
217    pub top: T,
218    /// near most height (WM) or T (S2)
219    /// generic height is relative to the surface of the earth in meters
220    pub near: T,
221    /// far most height (WM) or T (S2)
222    /// generic height is relative to the surface of the earth in meters
223    pub far: T,
224}
225impl<T> BBox3D<T> {
226    /// Creates a new BBox3D
227    pub fn new(left: T, bottom: T, right: T, top: T, near: T, far: T) -> Self
228    where
229        T: Copy,
230    {
231        BBox3D { left, bottom, right, top, near, far }
232    }
233
234    /// Checks if a point is within the BBox
235    pub fn point_overlap(&self, point: VectorPoint) -> bool
236    where
237        T: Into<f64> + Copy, // Ensures that comparison operators work for type T
238    {
239        let z = point.z.unwrap_or_default();
240        point.x >= self.left.into()
241            && point.x <= self.right.into()
242            && point.y >= self.bottom.into()
243            && point.y <= self.top.into()
244            && z >= self.near.into()
245            && z <= self.far.into()
246    }
247
248    /// Merges another bounding box with this one
249    pub fn merge(&self, other: &BBox3D<T>) -> BBox3D<T>
250    where
251        T: PartialOrd + Copy,
252    {
253        let mut new_bbox = *self;
254        new_bbox.left = if new_bbox.left < other.left { new_bbox.left } else { other.left };
255        new_bbox.bottom =
256            if new_bbox.bottom < other.bottom { new_bbox.bottom } else { other.bottom };
257        new_bbox.right = if new_bbox.right > other.right { new_bbox.right } else { other.right };
258        new_bbox.top = if new_bbox.top > other.top { new_bbox.top } else { other.top };
259        new_bbox.near = if new_bbox.near < other.near { new_bbox.near } else { other.near };
260        new_bbox.far = if new_bbox.far > other.far { new_bbox.far } else { other.far };
261
262        new_bbox
263    }
264
265    /// Checks if another bounding box overlaps with this one and returns the overlap
266    pub fn overlap(&self, other: &BBox3D<T>) -> Option<BBox3D<T>>
267    where
268        T: PartialOrd + Copy,
269    {
270        if self.left > other.right
271            || self.right < other.left
272            || self.bottom > other.top
273            || self.top < other.bottom
274            || self.near > other.far
275            || self.far < other.near
276        {
277            None
278        } else {
279            let left = if self.left > other.left { self.left } else { other.left };
280            let bottom = if self.bottom > other.bottom { self.bottom } else { other.bottom };
281            let right = if self.right < other.right { self.right } else { other.right };
282            let top = if self.top < other.top { self.top } else { other.top };
283
284            let near = if self.near > other.near { self.near } else { other.near };
285            let far = if self.far < other.far { self.far } else { other.far };
286
287            Some(BBox3D { left, bottom, right, top, near, far })
288        }
289    }
290
291    /// Clips the bounding box along an axis
292    pub fn clip(&self, axis: Axis, k1: T, k2: T) -> BBox3D<T>
293    where
294        T: PartialOrd + Copy,
295    {
296        let mut new_bbox = *self;
297        if axis == Axis::X {
298            new_bbox.left = if new_bbox.left > k1 { new_bbox.left } else { k1 };
299            new_bbox.right = if new_bbox.right < k2 { new_bbox.right } else { k2 };
300        } else {
301            new_bbox.bottom = if new_bbox.bottom > k1 { new_bbox.bottom } else { k1 };
302            new_bbox.top = if new_bbox.top < k2 { new_bbox.top } else { k2 };
303        }
304
305        new_bbox
306    }
307}
308impl<T> Serialize for BBox3D<T>
309where
310    T: Serialize + Copy,
311{
312    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
313    where
314        S: Serializer,
315    {
316        let mut seq = serializer.serialize_tuple(6)?;
317        seq.serialize_element(&self.left)?;
318        seq.serialize_element(&self.bottom)?;
319        seq.serialize_element(&self.right)?;
320        seq.serialize_element(&self.top)?;
321        seq.serialize_element(&self.near)?;
322        seq.serialize_element(&self.far)?;
323        seq.end()
324    }
325}
326impl BBox3D<f64> {
327    /// Creates a new BBox3D from a point
328    pub fn from_point(point: &VectorPoint) -> Self {
329        BBox3D::new(
330            point.x,
331            point.y,
332            point.x,
333            point.y,
334            point.z.unwrap_or(0.),
335            point.z.unwrap_or(1.),
336        )
337    }
338
339    /// Creates a new BBox3D from a BBox
340    pub fn from_bbox(bbox: &BBox) -> Self {
341        BBox3D::new(bbox.left, bbox.bottom, bbox.right, bbox.top, 0., 1.)
342    }
343
344    /// Extends the bounding box with a point
345    pub fn extend_from_point(&mut self, point: &VectorPoint) {
346        *self = self.merge(&BBox3D::from_point(point));
347    }
348
349    /// Creates a new BBox3D from zoom-uv coordinates
350    pub fn from_uv_zoom(u: f64, v: f64, zoom: u8) -> Self {
351        let division_factor = 2. / (1 << zoom) as f64;
352
353        BBox3D {
354            left: division_factor * u - 1.0,
355            bottom: division_factor * v - 1.0,
356            right: division_factor * (u + 1.0) - 1.0,
357            top: division_factor * (v + 1.0) - 1.0,
358            near: 0.,
359            far: 1.,
360        }
361    }
362
363    /// Creates a new BBox from zoom-st coordinates
364    pub fn from_st_zoom(s: f64, t: f64, zoom: u8) -> Self {
365        let division_factor = (2. / (1 << zoom) as f64) * 0.5;
366
367        BBox3D {
368            left: division_factor * s,
369            bottom: division_factor * t,
370            right: division_factor * (s + 1.),
371            top: division_factor * (t + 1.),
372            near: 0.,
373            far: 1.,
374        }
375    }
376}
377impl From<&BBox> for BBox3D<f64> {
378    fn from(bbox: &BBox) -> Self {
379        BBox3D::from_bbox(bbox)
380    }
381}
382impl<'de, T> Deserialize<'de> for BBox3D<T>
383where
384    T: Deserialize<'de> + Copy,
385{
386    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
387    where
388        D: Deserializer<'de>,
389    {
390        struct BBox3DVisitor<T> {
391            marker: core::marker::PhantomData<T>,
392        }
393
394        impl<'de, T> Visitor<'de> for BBox3DVisitor<T>
395        where
396            T: Deserialize<'de> + Copy,
397        {
398            type Value = BBox3D<T>;
399
400            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
401                formatter.write_str("a sequence of six numbers")
402            }
403
404            fn visit_seq<V>(self, mut seq: V) -> Result<BBox3D<T>, V::Error>
405            where
406                V: SeqAccess<'de>,
407            {
408                let left =
409                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(0, &self))?;
410                let bottom =
411                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(1, &self))?;
412                let right =
413                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(2, &self))?;
414                let top = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(3, &self))?;
415                let near =
416                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(4, &self))?;
417                let far = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(5, &self))?;
418                Ok(BBox3D { left, bottom, right, top, near, far })
419            }
420        }
421
422        deserializer.deserialize_tuple(6, BBox3DVisitor { marker: core::marker::PhantomData })
423    }
424}
425
426/// BBox or BBox3D
427#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
428pub enum BBOX {
429    /// 2D bounding box
430    BBox(BBox),
431    /// 3D bounding box
432    BBox3D(BBox3D),
433}
434impl Default for BBOX {
435    fn default() -> Self {
436        BBOX::BBox(BBox::default())
437    }
438}
439
440/// A Point in S2 Space with a Face
441#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
442pub struct STPoint {
443    /// The face of the point
444    pub face: Face,
445    /// The s coordinate
446    pub s: f64,
447    /// The t coordinate
448    pub t: f64,
449    /// The z coordinate
450    pub z: Option<f64>,
451    /// The m coordinate
452    pub m: Option<MValue>,
453}
454
455/// Enum to represent specific geometry types as strings
456#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
457pub enum GeometryType {
458    /// Point
459    Point,
460    /// MultiPoint
461    MultiPoint,
462    /// LineString
463    LineString,
464    /// MultiLineString
465    MultiLineString,
466    /// Polygon
467    Polygon,
468    /// MultiPolygon
469    MultiPolygon,
470    /// 3D Point
471    Point3D,
472    /// 3D MultiPoint
473    MultiPoint3D,
474    /// 3D LineString
475    LineString3D,
476    /// 3D MultiLineString
477    MultiLineString3D,
478    /// 3D Polygon
479    Polygon3D,
480    /// 3D MultiPolygon
481    MultiPolygon3D,
482}
483impl From<&str> for GeometryType {
484    fn from(s: &str) -> Self {
485        match s {
486            "Point" => GeometryType::Point,
487            "MultiPoint" => GeometryType::MultiPoint,
488            "LineString" => GeometryType::LineString,
489            "MultiLineString" => GeometryType::MultiLineString,
490            "Polygon" => GeometryType::Polygon,
491            "MultiPolygon" => GeometryType::MultiPolygon,
492            "Point3D" => GeometryType::Point3D,
493            "MultiPoint3D" => GeometryType::MultiPoint3D,
494            "LineString3D" => GeometryType::LineString3D,
495            "MultiLineString3D" => GeometryType::MultiLineString3D,
496            "Polygon3D" => GeometryType::Polygon3D,
497            "MultiPolygon3D" => GeometryType::MultiPolygon3D,
498            _ => GeometryType::Point,
499        }
500    }
501}
502
503/// Definition of a Point. May represent WebMercator Lon-Lat or S2Geometry S-T
504pub type Point = (f64, f64);
505/// Definition of a MultiPoint
506pub type MultiPoint = Vec<Point>;
507/// Definition of a LineString
508pub type LineString = Vec<Point>;
509/// Definition of a MultiLineString
510pub type MultiLineString = Vec<LineString>;
511/// Definition of a Polygon
512pub type Polygon = Vec<Vec<Point>>;
513/// Definition of a MultiPolygon
514pub type MultiPolygon = Vec<Polygon>;
515/// Definition of a 3D Point. May represent WebMercator Lon-Lat or S2Geometry S-T with a z-value
516pub type Point3D = (f64, f64, f64);
517/// Definition of a 3D MultiPoint
518pub type MultiPoint3D = Vec<Point3D>;
519/// Definition of a 3D LineString
520pub type LineString3D = Vec<Point3D>;
521/// Definition of a 3D MultiLineString
522pub type MultiLineString3D = Vec<LineString3D>;
523/// Definition of a 3D Polygon
524pub type Polygon3D = Vec<Vec<Point3D>>;
525/// Definition of a 3D MultiPolygon
526pub type MultiPolygon3D = Vec<Polygon3D>;
527
528/// All possible geometry shapes
529#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
530pub enum Geometry {
531    /// Point Shape
532    Point(PointGeometry),
533    /// MultiPoint Shape
534    MultiPoint(MultiPointGeometry),
535    /// LineString Shape
536    LineString(LineStringGeometry),
537    /// MultiLineString Shape
538    MultiLineString(MultiLineStringGeometry),
539    /// Polygon Shape
540    Polygon(PolygonGeometry),
541    /// MultiPolygon Shape
542    MultiPolygon(MultiPolygonGeometry),
543    /// Point3D Shape
544    Point3D(Point3DGeometry),
545    /// MultiPoint3D Shape
546    MultiPoint3D(MultiPoint3DGeometry),
547    /// LineString3D Shape
548    LineString3D(LineString3DGeometry),
549    /// MultiLineString3D Shape
550    MultiLineString3D(MultiLineString3DGeometry),
551    /// Polygon3D Shape
552    Polygon3D(Polygon3DGeometry),
553    /// MultiPolygon3D Shape
554    MultiPolygon3D(MultiPolygon3DGeometry),
555}
556
557/// BaseGeometry is the a generic geometry type
558#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
559pub struct BaseGeometry<G = Geometry, M = MValues, B = BBOX> {
560    /// The geometry type
561    #[serde(rename = "type")]
562    pub _type: GeometryType,
563    /// The geometry shape
564    pub coordinates: G,
565    /// The M-Values shape
566    #[serde(rename = "mValues", skip_serializing_if = "Option::is_none")]
567    pub m_values: Option<M>,
568    /// The BBox shape
569    #[serde(skip_serializing_if = "Option::is_none")]
570    pub bbox: Option<B>,
571}
572
573/// PointGeometry is a point
574pub type PointGeometry = BaseGeometry<Point, MValue, BBox>;
575/// MultiPointGeometry contains multiple points
576pub type MultiPointGeometry = BaseGeometry<MultiPoint, LineStringMValues, BBox>;
577/// LineStringGeometry is a line
578pub type LineStringGeometry = BaseGeometry<LineString, LineStringMValues, BBox>;
579/// MultiLineStringGeometry contains multiple lines
580pub type MultiLineStringGeometry = BaseGeometry<MultiLineString, MultiLineStringMValues, BBox>;
581/// PolygonGeometry is a polygon with potential holes
582pub type PolygonGeometry = BaseGeometry<Polygon, PolygonMValues, BBox>;
583/// MultiPolygonGeometry is a polygon with multiple polygons with their own potential holes
584pub type MultiPolygonGeometry = BaseGeometry<MultiPolygon, MultiPolygonMValues, BBox>;
585/// Point3DGeometry is a 3D point
586pub type Point3DGeometry = BaseGeometry<Point3D, MValue, BBox3D>;
587/// MultiPoint3DGeometry contains multiple 3D points
588pub type MultiPoint3DGeometry = BaseGeometry<MultiPoint3D, LineStringMValues, BBox3D>;
589/// LineString3DGeometry is a 3D line
590pub type LineString3DGeometry = BaseGeometry<LineString3D, LineStringMValues, BBox3D>;
591/// MultiLineString3DGeometry contains multiple 3D lines
592pub type MultiLineString3DGeometry =
593    BaseGeometry<MultiLineString3D, MultiLineStringMValues, BBox3D>;
594/// Polygon3DGeometry is a 3D polygon with potential holes
595pub type Polygon3DGeometry = BaseGeometry<Polygon3D, PolygonMValues, BBox3D>;
596/// MultiPolygon3DGeometry is a 3D polygon with multiple polygons with their own potential holes
597pub type MultiPolygon3DGeometry = BaseGeometry<MultiPolygon3D, MultiPolygonMValues, BBox3D>;
598
599/// Enum to represent specific vector geometry types as strings
600#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Default)]
601pub enum VectorGeometryType {
602    /// Point
603    #[default]
604    Point,
605    /// MultiPoint
606    MultiPoint,
607    /// LineString
608    LineString,
609    /// MultiLineString
610    MultiLineString,
611    /// Polygon
612    Polygon,
613    /// MultiPolygon
614    MultiPolygon,
615}
616impl From<&str> for VectorGeometryType {
617    fn from(s: &str) -> Self {
618        match s {
619            "Point" => VectorGeometryType::Point,
620            "MultiPoint" => VectorGeometryType::MultiPoint,
621            "LineString" => VectorGeometryType::LineString,
622            "MultiLineString" => VectorGeometryType::MultiLineString,
623            "Polygon" => VectorGeometryType::Polygon,
624            "MultiPolygon" => VectorGeometryType::MultiPolygon,
625            _ => VectorGeometryType::Point,
626        }
627    }
628}
629
630/// A Vector Point uses a structure for 2D or 3D points
631#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
632pub struct VectorPoint {
633    /// X coordinate
634    pub x: f64,
635    /// Y coordinate
636    pub y: f64,
637    /// Z coordinate or "altitude". May be None
638    pub z: Option<f64>,
639    /// M-Value
640    #[serde(skip_serializing_if = "Option::is_none")]
641    pub m: Option<MValue>,
642    /// T for tolerance. A tmp value used for simplification
643    #[serde(skip)]
644    pub t: Option<f64>,
645}
646impl VectorPoint {
647    /// Create a new point
648    pub fn new(x: f64, y: f64, z: Option<f64>) -> Self {
649        Self { x, y, z, m: None, t: None }
650    }
651
652    /// Project the point into the 0->1 coordinate system
653    pub fn project(&mut self, bbox: &mut Option<BBox3D>) {
654        let y = self.y;
655        let x = self.x;
656        let sin = sin((y * PI) / 180.);
657        let y2 = 0.5 - (0.25 * log((1. + sin) / (1. - sin))) / PI;
658        self.x = x / 360. + 0.5;
659        self.y = y2.clamp(0., 1.);
660
661        match bbox {
662            Some(bbox) => bbox.extend_from_point(self),
663            None => *bbox = Some(BBox3D::from_point(self)),
664        };
665    }
666
667    /// Unproject the point from the 0->1 coordinate system back to a lon-lat coordinate
668    pub fn unproject(&mut self) {
669        let lon = (self.x - 0.5) * 360.;
670        let y2 = 0.5 - self.y;
671        let lat = atan(sinh(PI * (y2 * 2.))).to_degrees();
672
673        self.x = lon;
674        self.y = lat;
675    }
676
677    /// Calculate the distance between two points
678    pub fn distance(&self, other: &VectorPoint) -> f64 {
679        sqrt(pow(other.x - self.x, 2.) + pow(other.y - self.y, 2.))
680    }
681}
682impl From<&Point> for VectorPoint {
683    fn from(p: &Point) -> Self {
684        Self { x: p.0, y: p.1, z: None, m: None, t: None }
685    }
686}
687impl From<&Point3D> for VectorPoint {
688    fn from(p: &Point3D) -> Self {
689        Self { x: p.0, y: p.1, z: Some(p.2), m: None, t: None }
690    }
691}
692/// Definition of a Vector MultiPoint
693pub type VectorMultiPoint = Vec<VectorPoint>;
694/// Definition of a Vector LineString
695pub type VectorLineString = Vec<VectorPoint>;
696/// Definition of a Vector MultiLineString
697pub type VectorMultiLineString = Vec<VectorLineString>;
698/// Definition of a Vector Polygon
699pub type VectorPolygon = Vec<VectorLineString>;
700/// Definition of a Vector MultiPolygon
701pub type VectorMultiPolygon = Vec<VectorPolygon>;
702
703/// All possible geometry shapes
704#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
705pub enum VectorGeometry {
706    /// Point Shape
707    Point(VectorPointGeometry),
708    /// MultiPoint Shape
709    MultiPoint(VectorMultiPointGeometry),
710    /// LineString Shape
711    LineString(VectorLineStringGeometry),
712    /// MultiLineString Shape
713    MultiLineString(VectorMultiLineStringGeometry),
714    /// Polygon Shape
715    Polygon(VectorPolygonGeometry),
716    /// MultiPolygon Shape
717    MultiPolygon(VectorMultiPolygonGeometry),
718}
719impl VectorGeometry {
720    /// Get the vec_bbox of the geometry
721    pub fn vec_bbox(&self) -> &Option<BBox3D> {
722        match self {
723            VectorGeometry::Point(g) => &g.vec_bbox,
724            VectorGeometry::MultiPoint(g) => &g.vec_bbox,
725            VectorGeometry::LineString(g) => &g.vec_bbox,
726            VectorGeometry::MultiLineString(g) => &g.vec_bbox,
727            VectorGeometry::Polygon(g) => &g.vec_bbox,
728            VectorGeometry::MultiPolygon(g) => &g.vec_bbox,
729        }
730    }
731}
732
733/// BaseGeometry is the a generic geometry type
734#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
735pub struct VectorBaseGeometry<G = VectorGeometry, O = VectorOffsets> {
736    /// The geometry type
737    #[serde(rename = "type")]
738    pub _type: VectorGeometryType,
739    /// Specifies if the geometry is 3D or 2D
740    #[serde(rename = "is3D")]
741    pub is_3d: bool,
742    /// The geometry shape
743    pub coordinates: G,
744    /// The geometry offsets if applicable
745    #[serde(skip_serializing_if = "Option::is_none")]
746    pub offset: Option<O>,
747    /// The BBox shape - always in lon-lat
748    #[serde(skip_serializing_if = "Option::is_none")]
749    pub bbox: Option<BBox3D>,
750    /// temporary bbox to track 0->1 clipping
751    #[serde(skip)]
752    pub vec_bbox: Option<BBox3D>,
753    /// Polygon and MultiPolygon specific property
754    pub indices: Option<Vec<u32>>,
755    /// Polygon and MultiPolygon specific property
756    pub tesselation: Option<f64>,
757}
758
759/** All possible geometry offsets */
760#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
761pub enum VectorOffsets {
762    /// LineString offset
763    LineOffset(VectorLineOffset),
764    /// MultiLineString offset
765    MultiLineOffset(VectorMultiLineOffset),
766    /// Polygon offset
767    PolygonOffset(VectorPolygonOffset),
768    /// MultiPolygon offset
769    MultiPolygonOffset(VectorMultiPolygonOffset),
770}
771/** An offset defines how far the starting line is from the original starting point pre-slice */
772pub type VectorLineOffset = f64;
773/** A collection of offsets */
774pub type VectorMultiLineOffset = Vec<VectorLineOffset>;
775/** A collection of offsets */
776pub type VectorPolygonOffset = VectorMultiLineOffset;
777/** A collection of collections of offsets */
778pub type VectorMultiPolygonOffset = Vec<VectorPolygonOffset>;
779
780/// PointGeometry is a point
781pub type VectorPointGeometry = VectorBaseGeometry<VectorPoint>;
782/// MultiPointGeometry contains multiple points
783pub type VectorMultiPointGeometry = VectorBaseGeometry<VectorMultiPoint, VectorLineOffset>;
784/// LineStringGeometry is a line
785pub type VectorLineStringGeometry = VectorBaseGeometry<VectorLineString, VectorLineOffset>;
786/// MultiLineStringGeometry contains multiple lines
787pub type VectorMultiLineStringGeometry =
788    VectorBaseGeometry<VectorMultiLineString, VectorMultiLineOffset>;
789/// PolygonGeometry is a polygon with potential holes
790pub type VectorPolygonGeometry = VectorBaseGeometry<VectorPolygon, VectorPolygonOffset>;
791/// MultiPolygonGeometry is a polygon with multiple polygons with their own potential holes
792pub type VectorMultiPolygonGeometry =
793    VectorBaseGeometry<VectorMultiPolygon, VectorMultiPolygonOffset>;
794
795#[cfg(test)]
796mod tests {
797    use super::*;
798    use alloc::vec;
799
800    #[test]
801    fn test_bbox() {
802        let bbox = BBox { left: 0.0, bottom: 0.0, right: 1.0, top: 1.0 };
803        assert_eq!(bbox, BBox { left: 0.0, bottom: 0.0, right: 1.0, top: 1.0 });
804        let bbox_str = serde_json::to_string(&bbox).unwrap();
805        assert_eq!(bbox_str, "[0.0,0.0,1.0,1.0]");
806        let str_bbox: BBox = serde_json::from_str(&bbox_str).unwrap();
807        assert_eq!(str_bbox, bbox);
808
809        let default_bbox = BBox::default();
810        assert_eq!(default_bbox, BBox { left: 0.0, bottom: 0.0, right: 0.0, top: 0.0 });
811
812        let default_bbox_2 = BBOX::default();
813        assert_eq!(
814            default_bbox_2,
815            BBOX::BBox(BBox { left: 0.0, bottom: 0.0, right: 0.0, top: 0.0 })
816        );
817    }
818
819    #[test]
820    fn test_bbox_functions() {
821        let bbox = BBox::new(0., 0., 1., 1.);
822        assert!(bbox.point_overlap(VectorPoint::new(0.5, 0.5, None)));
823        assert!(!bbox.point_overlap(VectorPoint::new(2.0, 2.0, None)));
824        let bbox2 = BBox { left: 0.5, bottom: 0.5, right: 1.5, top: 1.5 };
825        assert_eq!(
826            bbox.overlap(&bbox2),
827            Some(BBox { left: 0.5, bottom: 0.5, right: 1.0, top: 1.0 })
828        );
829        let bbox3 = BBox { left: 2.0, bottom: 2.0, right: 3.0, top: 3.0 };
830        assert_eq!(bbox3.overlap(&bbox), None);
831    }
832
833    #[test]
834    fn test_bbox_functions_2() {
835        let bbox = BBox::from_st_zoom(0., 0., 0);
836        assert_eq!(bbox, BBox { left: 0.0, bottom: 0.0, right: 1., top: 1. });
837
838        let bbox = BBox::from_st_zoom(1., 0., 1);
839        assert_eq!(bbox, BBox { left: 0.5, bottom: 0.0, right: 1., top: 0.5 });
840
841        let bbox = BBox::from_st_zoom(2., 0., 2);
842        assert_eq!(bbox, BBox { left: 0.5, bottom: 0.0, right: 0.75, top: 0.25 });
843
844        let bbox = BBox::from_uv_zoom(0., 0., 0);
845        assert_eq!(bbox, BBox { left: -1.0, bottom: -1.0, right: 1., top: 1. });
846
847        let bbox = BBox::from_uv_zoom(1., 0., 1);
848        assert_eq!(bbox, BBox { left: 0., bottom: -1.0, right: 1., top: 0. });
849
850        let bbox = BBox::from_uv_zoom(2., 0., 2);
851        assert_eq!(bbox, BBox { left: 0., bottom: -1.0, right: 0.5, top: -0.5 });
852    }
853
854    #[test]
855    fn test_bbox3d() {
856        let bbox = BBox3D { left: 0.0, bottom: 0.0, right: 1.0, top: 1.0, near: 0.0, far: 1.0 };
857        assert_eq!(
858            bbox,
859            BBox3D { left: 0.0, bottom: 0.0, right: 1.0, top: 1.0, near: 0.0, far: 1.0 }
860        );
861        let bbox_str = serde_json::to_string(&bbox).unwrap();
862        assert_eq!(bbox_str, "[0.0,0.0,1.0,1.0,0.0,1.0]");
863        let str_bbox: BBox3D = serde_json::from_str(&bbox_str).unwrap();
864        assert_eq!(str_bbox, bbox);
865
866        let default_bbox = BBox3D::default();
867        assert_eq!(
868            default_bbox,
869            BBox3D { left: 0.0, bottom: 0.0, right: 0.0, top: 0.0, near: 0.0, far: 0.0 }
870        );
871    }
872
873    #[test]
874    fn test_point_geometry() {
875        let point = PointGeometry {
876            _type: "Point".into(),
877            coordinates: (0.0, 0.0),
878            m_values: None,
879            bbox: None,
880        };
881        assert_eq!(
882            point,
883            PointGeometry {
884                _type: "Point".into(),
885                coordinates: (0.0, 0.0),
886                m_values: None,
887                bbox: None
888            }
889        );
890        let point_str = serde_json::to_string(&point).unwrap();
891        assert_eq!(point_str, "{\"type\":\"Point\",\"coordinates\":[0.0,0.0]}");
892        let str_point: PointGeometry = serde_json::from_str(&point_str).unwrap();
893        assert_eq!(str_point, point);
894    }
895
896    #[test]
897    fn test_point3d_geometry() {
898        let point = Point3DGeometry {
899            _type: "Point3D".into(),
900            coordinates: (0.0, 0.0, 0.0),
901            m_values: None,
902            bbox: Some(BBox3D {
903                left: 0.0,
904                bottom: 0.0,
905                right: 1.0,
906                top: 1.0,
907                near: 0.0,
908                far: 1.0,
909            }),
910        };
911        assert_eq!(
912            point,
913            Point3DGeometry {
914                _type: "Point3D".into(),
915                coordinates: (0.0, 0.0, 0.0),
916                m_values: None,
917                bbox: Some(BBox3D {
918                    left: 0.0,
919                    bottom: 0.0,
920                    right: 1.0,
921                    top: 1.0,
922                    near: 0.0,
923                    far: 1.0
924                })
925            }
926        );
927        let point_str = serde_json::to_string(&point).unwrap();
928        assert_eq!(
929            point_str,
930            "{\"type\":\"Point3D\",\"coordinates\":[0.0,0.0,0.0],\"bbox\":[0.0,0.0,1.0,1.0,0.0,1.\
931             0]}"
932        );
933        let str_point: Point3DGeometry = serde_json::from_str(&point_str).unwrap();
934        assert_eq!(str_point, point);
935    }
936
937    #[test]
938    fn test_line_string_geometry() {
939        let line = LineStringGeometry {
940            _type: "LineString".into(),
941            coordinates: vec![(0.0, 0.0), (1.0, 1.0)],
942            m_values: None,
943            bbox: None,
944        };
945        assert_eq!(
946            line,
947            LineStringGeometry {
948                _type: "LineString".into(),
949                coordinates: vec![(0.0, 0.0), (1.0, 1.0)],
950                m_values: None,
951                bbox: None
952            }
953        );
954        let line_str = serde_json::to_string(&line).unwrap();
955        assert_eq!(line_str, "{\"type\":\"LineString\",\"coordinates\":[[0.0,0.0],[1.0,1.0]]}");
956        let str_line: LineStringGeometry = serde_json::from_str(&line_str).unwrap();
957        assert_eq!(str_line, line);
958    }
959
960    #[test]
961    fn test_line_string3d_geometry() {
962        let line = LineString3DGeometry {
963            _type: "LineString3D".into(),
964            coordinates: vec![(0.0, 0.0, 0.0), (1.0, 1.0, 1.0)],
965            m_values: None,
966            bbox: None,
967        };
968        assert_eq!(
969            line,
970            LineString3DGeometry {
971                _type: "LineString3D".into(),
972                coordinates: vec![(0.0, 0.0, 0.0), (1.0, 1.0, 1.0)],
973                m_values: None,
974                bbox: None
975            }
976        );
977        let line_str = serde_json::to_string(&line).unwrap();
978        assert_eq!(
979            line_str,
980            "{\"type\":\"LineString3D\",\"coordinates\":[[0.0,0.0,0.0],[1.0,1.0,1.0]]}"
981        );
982        let str_line: LineString3DGeometry = serde_json::from_str(&line_str).unwrap();
983        assert_eq!(str_line, line);
984    }
985
986    #[test]
987    fn test_multi_point_geometry() {
988        let multi_point = MultiPointGeometry {
989            _type: "MultiPoint".into(),
990            coordinates: vec![(0.0, 0.0), (1.0, 1.0)],
991            m_values: None,
992            bbox: None,
993        };
994        assert_eq!(
995            multi_point,
996            MultiPointGeometry {
997                _type: "MultiPoint".into(),
998                coordinates: vec![(0.0, 0.0), (1.0, 1.0)],
999                m_values: None,
1000                bbox: None
1001            }
1002        );
1003        let multi_point_str = serde_json::to_string(&multi_point).unwrap();
1004        assert_eq!(
1005            multi_point_str,
1006            "{\"type\":\"MultiPoint\",\"coordinates\":[[0.0,0.0],[1.0,1.0]]}"
1007        );
1008        let str_multi_point: MultiPointGeometry = serde_json::from_str(&multi_point_str).unwrap();
1009        assert_eq!(str_multi_point, multi_point);
1010    }
1011
1012    #[test]
1013    fn test_multi_point3d_geometry() {
1014        let multi_point = MultiPoint3DGeometry {
1015            _type: "MultiPoint3D".into(),
1016            coordinates: vec![(0.0, 0.0, 0.0), (1.0, 1.0, 1.0)],
1017            m_values: None,
1018            bbox: None,
1019        };
1020        assert_eq!(
1021            multi_point,
1022            MultiPoint3DGeometry {
1023                _type: "MultiPoint3D".into(),
1024                coordinates: vec![(0.0, 0.0, 0.0), (1.0, 1.0, 1.0)],
1025                m_values: None,
1026                bbox: None
1027            }
1028        );
1029        let multi_point_str = serde_json::to_string(&multi_point).unwrap();
1030        assert_eq!(
1031            multi_point_str,
1032            "{\"type\":\"MultiPoint3D\",\"coordinates\":[[0.0,0.0,0.0],[1.0,1.0,1.0]]}"
1033        );
1034        let str_multi_point: MultiPoint3DGeometry = serde_json::from_str(&multi_point_str).unwrap();
1035        assert_eq!(str_multi_point, multi_point);
1036    }
1037
1038    #[test]
1039    fn test_polygon_geometry() {
1040        let polygon = PolygonGeometry {
1041            _type: "Polygon".into(),
1042            coordinates: vec![vec![(0.0, 0.0), (1.0, 1.0), (0.0, 1.0)]],
1043            m_values: None,
1044            bbox: None,
1045        };
1046        assert_eq!(
1047            polygon,
1048            PolygonGeometry {
1049                _type: "Polygon".into(),
1050                coordinates: vec![vec![(0.0, 0.0), (1.0, 1.0), (0.0, 1.0)]],
1051                m_values: None,
1052                bbox: None
1053            }
1054        );
1055        let polygon_str = serde_json::to_string(&polygon).unwrap();
1056        assert_eq!(
1057            polygon_str,
1058            "{\"type\":\"Polygon\",\"coordinates\":[[[0.0,0.0],[1.0,1.0],[0.0,1.0]]]}"
1059        );
1060        let str_polygon: PolygonGeometry = serde_json::from_str(&polygon_str).unwrap();
1061        assert_eq!(str_polygon, polygon);
1062    }
1063
1064    #[test]
1065    fn test_polygon3d_geometry() {
1066        let polygon = Polygon3DGeometry {
1067            _type: "Polygon3D".into(),
1068            coordinates: vec![vec![(0.0, 0.0, 0.0), (1.0, 1.0, 1.0), (0.0, 1.0, 1.0)]],
1069            m_values: None,
1070            bbox: None,
1071        };
1072        assert_eq!(
1073            polygon,
1074            Polygon3DGeometry {
1075                _type: "Polygon3D".into(),
1076                coordinates: vec![vec![(0.0, 0.0, 0.0), (1.0, 1.0, 1.0), (0.0, 1.0, 1.0)]],
1077                m_values: None,
1078                bbox: None
1079            }
1080        );
1081        let polygon_str = serde_json::to_string(&polygon).unwrap();
1082        assert_eq!(
1083            polygon_str,
1084            "{\"type\":\"Polygon3D\",\"coordinates\":[[[0.0,0.0,0.0],[1.0,1.0,1.0],[0.0,1.0,1.\
1085             0]]]}"
1086        );
1087        let str_polygon: Polygon3DGeometry = serde_json::from_str(&polygon_str).unwrap();
1088        assert_eq!(str_polygon, polygon);
1089    }
1090
1091    #[test]
1092    fn test_multi_polygon_geometry() {
1093        let multi_polygon = MultiPolygonGeometry {
1094            _type: "MultiPolygon".into(),
1095            coordinates: vec![vec![vec![(0.0, 0.0), (1.0, 1.0), (0.0, 1.0)]]],
1096            m_values: None,
1097            bbox: None,
1098        };
1099        assert_eq!(
1100            multi_polygon,
1101            MultiPolygonGeometry {
1102                _type: "MultiPolygon".into(),
1103                coordinates: vec![vec![vec![(0.0, 0.0), (1.0, 1.0), (0.0, 1.0)]]],
1104                m_values: None,
1105                bbox: None
1106            }
1107        );
1108        let multi_polygon_str = serde_json::to_string(&multi_polygon).unwrap();
1109        assert_eq!(
1110            multi_polygon_str,
1111            "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[0.0,0.0],[1.0,1.0],[0.0,1.0]]]]}"
1112        );
1113        let str_multi_polygon: MultiPolygonGeometry =
1114            serde_json::from_str(&multi_polygon_str).unwrap();
1115        assert_eq!(str_multi_polygon, multi_polygon);
1116    }
1117
1118    #[test]
1119    fn test_multi_polygon3d_geometry() {
1120        let multi_polygon = MultiPolygon3DGeometry {
1121            _type: "MultiPolygon3D".into(),
1122            coordinates: vec![vec![vec![(0.0, 0.0, 0.0), (1.0, 1.0, 1.0), (0.0, 1.0, 1.0)]]],
1123            m_values: None,
1124            bbox: None,
1125        };
1126        assert_eq!(
1127            multi_polygon,
1128            MultiPolygon3DGeometry {
1129                _type: "MultiPolygon3D".into(),
1130                coordinates: vec![vec![vec![(0.0, 0.0, 0.0), (1.0, 1.0, 1.0), (0.0, 1.0, 1.0)]]],
1131                m_values: None,
1132                bbox: None
1133            }
1134        );
1135        let multi_polygon_str = serde_json::to_string(&multi_polygon).unwrap();
1136        assert_eq!(
1137            multi_polygon_str,
1138            "{\"type\":\"MultiPolygon3D\",\"coordinates\":[[[[0.0,0.0,0.0],[1.0,1.0,1.0],[0.0,1.0,\
1139             1.0]]]]}"
1140        );
1141        let str_multi_polygon: MultiPolygon3DGeometry =
1142            serde_json::from_str(&multi_polygon_str).unwrap();
1143        assert_eq!(str_multi_polygon, multi_polygon);
1144    }
1145}