s2json_core/geometry/
bbox.rs

1use crate::*;
2use alloc::fmt;
3use serde::{
4    de::{self, SeqAccess, Visitor},
5    ser::SerializeTuple,
6    Deserialize, Deserializer, Serialize, Serializer,
7};
8
9trait Bounded {
10    fn min_value() -> Self;
11    fn max_value() -> Self;
12}
13macro_rules! impl_bounded {
14    ($($t:ty),*) => {
15        $(
16            impl Bounded for $t {
17                fn min_value() -> Self {
18                    <$t>::MIN
19                }
20                fn max_value() -> Self {
21                    <$t>::MAX
22                }
23            }
24        )*
25    };
26}
27
28// Implement for common numeric types
29impl_bounded!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, isize, usize, f32, f64);
30
31/// A BBOX is defined in lon-lat space and helps with zooming motion to
32/// see the entire line or polygon
33/// The order is (left, bottom, right, top)
34/// If WM, then the projection is lon-lat
35/// If S2, then the projection is s-t
36#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
37pub struct BBox<T = f64> {
38    /// left most longitude (WM) or S (S2)
39    pub left: T,
40    /// bottom most latitude (WM) or T (S2)
41    pub bottom: T,
42    /// right most longitude (WM) or T (S2)
43    pub right: T,
44    /// top most latitude (WM) or S (S2)
45    pub top: T,
46}
47impl<T> From<BBox<T>> for MValue
48where
49    T: Into<ValueType>,
50{
51    fn from(bbox: BBox<T>) -> MValue {
52        MValue::from([
53            ("left".into(), bbox.left.into()),
54            ("bottom".into(), bbox.bottom.into()),
55            ("right".into(), bbox.right.into()),
56            ("top".into(), bbox.top.into()),
57        ])
58    }
59}
60impl<T> From<&BBox<T>> for MValue
61where
62    T: Copy + Into<ValueType>,
63{
64    fn from(bbox: &BBox<T>) -> MValue {
65        MValue::from([
66            ("left".into(), bbox.left.into()),
67            ("bottom".into(), bbox.bottom.into()),
68            ("right".into(), bbox.right.into()),
69            ("top".into(), bbox.top.into()),
70        ])
71    }
72}
73impl<T> From<MValue> for BBox<T>
74where
75    T: From<ValueType>,
76{
77    fn from(mvalue: MValue) -> Self {
78        BBox {
79            left: mvalue.get("left").unwrap().clone().into(),
80            bottom: mvalue.get("bottom").unwrap().clone().into(),
81            right: mvalue.get("right").unwrap().clone().into(),
82            top: mvalue.get("top").unwrap().clone().into(),
83        }
84    }
85}
86impl<T> From<&MValue> for BBox<T>
87where
88    T: From<ValueType>,
89{
90    fn from(mvalue: &MValue) -> Self {
91        BBox {
92            left: mvalue.get("left").unwrap().clone().into(),
93            bottom: mvalue.get("bottom").unwrap().clone().into(),
94            right: mvalue.get("right").unwrap().clone().into(),
95            top: mvalue.get("top").unwrap().clone().into(),
96        }
97    }
98}
99impl<T> MValueCompatible for BBox<T>
100where
101    ValueType: From<T>,
102    T: From<ValueType> + Default + Bounded + Copy,
103{
104}
105impl<T> Default for BBox<T>
106where
107    T: Default + Bounded + Copy,
108{
109    fn default() -> Self {
110        BBox::new(T::max_value(), T::max_value(), T::min_value(), T::min_value())
111    }
112}
113impl<T> BBox<T> {
114    /// Creates a new BBox
115    pub fn new(left: T, bottom: T, right: T, top: T) -> Self
116    where
117        T: Copy,
118    {
119        BBox { left, bottom, right, top }
120    }
121
122    /// Checks if a point is within the BBox
123    pub fn point_overlap<M: Clone>(&self, point: VectorPoint<M>) -> bool
124    where
125        T: Into<f64> + Copy, // Ensures that comparison operators work for type T
126    {
127        point.x >= self.left.into()
128            && point.x <= self.right.into()
129            && point.y >= self.bottom.into()
130            && point.y <= self.top.into()
131    }
132
133    /// Merges another bounding box with this one
134    pub fn merge(&self, other: &Self) -> Self
135    where
136        T: PartialOrd + Copy,
137    {
138        let mut new_bbox = *self;
139        new_bbox.left = if new_bbox.left < other.left { new_bbox.left } else { other.left };
140        new_bbox.bottom =
141            if new_bbox.bottom < other.bottom { new_bbox.bottom } else { other.bottom };
142        new_bbox.right = if new_bbox.right > other.right { new_bbox.right } else { other.right };
143        new_bbox.top = if new_bbox.top > other.top { new_bbox.top } else { other.top };
144
145        new_bbox
146    }
147
148    /// Merges in place another bounding box with this one
149    pub fn merge_in_place(&mut self, other: &Self)
150    where
151        T: PartialOrd + Copy,
152    {
153        self.left = if self.left < other.left { self.left } else { other.left };
154        self.bottom = if self.bottom < other.bottom { self.bottom } else { other.bottom };
155        self.right = if self.right > other.right { self.right } else { other.right };
156        self.top = if self.top > other.top { self.top } else { other.top };
157    }
158
159    /// Checks if another bounding box overlaps with this one and returns the overlap
160    pub fn overlap(&self, other: &BBox<T>) -> Option<BBox<T>>
161    where
162        T: PartialOrd + Copy,
163    {
164        if self.left > other.right
165            || self.right < other.left
166            || self.bottom > other.top
167            || self.top < other.bottom
168        {
169            None
170        } else {
171            let left = if self.left > other.left { self.left } else { other.left };
172            let bottom = if self.bottom > other.bottom { self.bottom } else { other.bottom };
173            let right = if self.right < other.right { self.right } else { other.right };
174            let top = if self.top < other.top { self.top } else { other.top };
175
176            Some(BBox { left, bottom, right, top })
177        }
178    }
179
180    /// Clips the bounding box along an axis
181    pub fn clip(&self, axis: Axis, k1: T, k2: T) -> BBox<T>
182    where
183        T: PartialOrd + Copy,
184    {
185        let mut new_bbox = *self;
186        if axis == Axis::X {
187            new_bbox.left = if new_bbox.left > k1 { new_bbox.left } else { k1 };
188            new_bbox.right = if new_bbox.right < k2 { new_bbox.right } else { k2 };
189        } else {
190            new_bbox.bottom = if new_bbox.bottom > k1 { new_bbox.bottom } else { k1 };
191            new_bbox.top = if new_bbox.top < k2 { new_bbox.top } else { k2 };
192        }
193
194        new_bbox
195    }
196}
197impl BBox<f64> {
198    /// Creates a new BBox from a point
199    pub fn from_point<M: Clone>(point: &VectorPoint<M>) -> Self {
200        BBox::new(point.x, point.y, point.x, point.y)
201    }
202
203    /// Creates a new BBox from a linestring
204    pub fn from_linestring<M: Clone>(line: &VectorLineString<M>) -> Self {
205        let mut bbox = BBox::from_point(&line[0]);
206        for point in line {
207            bbox.extend_from_point(point);
208        }
209        bbox
210    }
211
212    /// Creates a new BBox from a multi-linestring
213    pub fn from_multi_linestring<M: Clone>(lines: &VectorMultiLineString<M>) -> Self {
214        let mut bbox = BBox::from_point(&lines[0][0]);
215        for line in lines {
216            for point in line {
217                bbox.extend_from_point(point);
218            }
219        }
220        bbox
221    }
222
223    /// Creates a new BBox from a polygon
224    pub fn from_polygon<M: Clone>(polygon: &VectorPolygon<M>) -> Self {
225        BBox::<f64>::from_multi_linestring(polygon)
226    }
227
228    /// Creates a new BBox from a multi-polygon
229    pub fn from_multi_polygon<M: Clone>(polygons: &VectorMultiPolygon<M>) -> Self {
230        let mut bbox = BBox::from_point(&polygons[0][0][0]);
231        for polygon in polygons {
232            for line in polygon {
233                for point in line {
234                    bbox.extend_from_point(point);
235                }
236            }
237        }
238        bbox
239    }
240
241    /// Extends the bounding box with a point
242    pub fn extend_from_point<M: Clone>(&mut self, point: &VectorPoint<M>) {
243        self.merge_in_place(&BBox::from_point(point));
244    }
245
246    /// Creates a new BBox from zoom-uv coordinates
247    pub fn from_uv_zoom(u: f64, v: f64, zoom: u8) -> Self {
248        let division_factor = 2. / (1 << zoom) as f64;
249
250        BBox {
251            left: division_factor * u - 1.0,
252            bottom: division_factor * v - 1.0,
253            right: division_factor * (u + 1.0) - 1.0,
254            top: division_factor * (v + 1.0) - 1.0,
255        }
256    }
257
258    /// Creates a new BBox from zoom-st coordinates
259    pub fn from_st_zoom(s: f64, t: f64, zoom: u8) -> Self {
260        let division_factor = (2. / (1 << zoom) as f64) * 0.5;
261
262        BBox {
263            left: division_factor * s,
264            bottom: division_factor * t,
265            right: division_factor * (s + 1.),
266            top: division_factor * (t + 1.),
267        }
268    }
269}
270impl<T> Serialize for BBox<T>
271where
272    T: Serialize + Copy,
273{
274    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
275    where
276        S: Serializer,
277    {
278        let mut seq = serializer.serialize_tuple(4)?;
279        seq.serialize_element(&self.left)?;
280        seq.serialize_element(&self.bottom)?;
281        seq.serialize_element(&self.right)?;
282        seq.serialize_element(&self.top)?;
283        seq.end()
284    }
285}
286impl<'de, T> Deserialize<'de> for BBox<T>
287where
288    T: Deserialize<'de> + Copy,
289{
290    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
291    where
292        D: Deserializer<'de>,
293    {
294        struct BBoxVisitor<T> {
295            marker: core::marker::PhantomData<T>,
296        }
297
298        impl<'de, T> Visitor<'de> for BBoxVisitor<T>
299        where
300            T: Deserialize<'de> + Copy,
301        {
302            type Value = BBox<T>;
303
304            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
305                formatter.write_str("a sequence of four numbers")
306            }
307
308            fn visit_seq<V>(self, mut seq: V) -> Result<BBox<T>, V::Error>
309            where
310                V: SeqAccess<'de>,
311            {
312                let left =
313                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(0, &self))?;
314                let bottom =
315                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(1, &self))?;
316                let right =
317                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(2, &self))?;
318                let top = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(3, &self))?;
319                Ok(BBox { left, bottom, right, top })
320            }
321        }
322
323        deserializer.deserialize_tuple(4, BBoxVisitor { marker: core::marker::PhantomData })
324    }
325}
326
327/// A BBOX is defined in lon-lat space and helps with zooming motion to
328/// see the entire 3D line or polygon
329#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
330pub struct BBox3D<T = f64> {
331    /// left most longitude (WM) or S (S2)
332    pub left: T,
333    /// bottom most latitude (WM) or T (S2)
334    pub bottom: T,
335    /// right most longitude (WM) or T (S2)
336    pub right: T,
337    /// top most latitude (WM) or S (S2)
338    pub top: T,
339    /// near most height (WM) or T (S2)
340    /// generic height is relative to the surface of the earth in meters
341    pub near: T,
342    /// far most height (WM) or T (S2)
343    /// generic height is relative to the surface of the earth in meters
344    pub far: T,
345}
346impl<T> BBox3D<T> {
347    /// Creates a new BBox3D
348    pub fn new(left: T, bottom: T, right: T, top: T, near: T, far: T) -> Self
349    where
350        T: Copy,
351    {
352        BBox3D { left, bottom, right, top, near, far }
353    }
354
355    /// Checks if a point is within the BBox
356    pub fn point_overlap<M: Clone>(&self, point: VectorPoint<M>) -> bool
357    where
358        T: Into<f64> + Copy, // Ensures that comparison operators work for type T
359    {
360        let z = point.z.unwrap_or_default();
361        point.x >= self.left.into()
362            && point.x <= self.right.into()
363            && point.y >= self.bottom.into()
364            && point.y <= self.top.into()
365            && z >= self.near.into()
366            && z <= self.far.into()
367    }
368
369    /// Merges another bounding box with this one
370    pub fn merge(&self, other: &BBox3D<T>) -> BBox3D<T>
371    where
372        T: PartialOrd + Copy,
373    {
374        let mut new_bbox = *self;
375        new_bbox.left = if new_bbox.left < other.left { new_bbox.left } else { other.left };
376        new_bbox.bottom =
377            if new_bbox.bottom < other.bottom { new_bbox.bottom } else { other.bottom };
378        new_bbox.right = if new_bbox.right > other.right { new_bbox.right } else { other.right };
379        new_bbox.top = if new_bbox.top > other.top { new_bbox.top } else { other.top };
380        new_bbox.near = if new_bbox.near < other.near { new_bbox.near } else { other.near };
381        new_bbox.far = if new_bbox.far > other.far { new_bbox.far } else { other.far };
382
383        new_bbox
384    }
385
386    /// Merges in place another bounding box with this one
387    pub fn merge_in_place(&mut self, other: &Self)
388    where
389        T: PartialOrd + Copy,
390    {
391        self.left = if self.left < other.left { self.left } else { other.left };
392        self.bottom = if self.bottom < other.bottom { self.bottom } else { other.bottom };
393        self.right = if self.right > other.right { self.right } else { other.right };
394        self.top = if self.top > other.top { self.top } else { other.top };
395        self.near = if self.near < other.near { self.near } else { other.near };
396        self.far = if self.far > other.far { self.far } else { other.far };
397    }
398
399    /// Checks if another bounding box overlaps with this one and returns the overlap
400    pub fn overlap(&self, other: &BBox3D<T>) -> Option<BBox3D<T>>
401    where
402        T: PartialOrd + Copy,
403    {
404        if self.left > other.right
405            || self.right < other.left
406            || self.bottom > other.top
407            || self.top < other.bottom
408            || self.near > other.far
409            || self.far < other.near
410        {
411            None
412        } else {
413            let left = if self.left > other.left { self.left } else { other.left };
414            let bottom = if self.bottom > other.bottom { self.bottom } else { other.bottom };
415            let right = if self.right < other.right { self.right } else { other.right };
416            let top = if self.top < other.top { self.top } else { other.top };
417
418            let near = if self.near > other.near { self.near } else { other.near };
419            let far = if self.far < other.far { self.far } else { other.far };
420
421            Some(BBox3D { left, bottom, right, top, near, far })
422        }
423    }
424
425    /// Clips the bounding box along an axis
426    pub fn clip(&self, axis: Axis, k1: T, k2: T) -> BBox3D<T>
427    where
428        T: PartialOrd + Copy,
429    {
430        let mut new_bbox = *self;
431        if axis == Axis::X {
432            new_bbox.left = if new_bbox.left > k1 { new_bbox.left } else { k1 };
433            new_bbox.right = if new_bbox.right < k2 { new_bbox.right } else { k2 };
434        } else {
435            new_bbox.bottom = if new_bbox.bottom > k1 { new_bbox.bottom } else { k1 };
436            new_bbox.top = if new_bbox.top < k2 { new_bbox.top } else { k2 };
437        }
438
439        new_bbox
440    }
441}
442impl<T> Serialize for BBox3D<T>
443where
444    T: Serialize + Copy,
445{
446    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
447    where
448        S: Serializer,
449    {
450        let mut seq = serializer.serialize_tuple(6)?;
451        seq.serialize_element(&self.left)?;
452        seq.serialize_element(&self.bottom)?;
453        seq.serialize_element(&self.right)?;
454        seq.serialize_element(&self.top)?;
455        seq.serialize_element(&self.near)?;
456        seq.serialize_element(&self.far)?;
457        seq.end()
458    }
459}
460impl Default for BBox3D<f64> {
461    fn default() -> Self {
462        BBox3D::new(f64::MAX, f64::MAX, f64::MIN, f64::MIN, f64::MAX, f64::MIN)
463    }
464}
465impl BBox3D<f64> {
466    /// Creates a new BBox3D from a point
467    pub fn from_point<M: Clone>(point: &VectorPoint<M>) -> Self {
468        BBox3D::new(
469            point.x,
470            point.y,
471            point.x,
472            point.y,
473            point.z.unwrap_or(f64::MAX),
474            point.z.unwrap_or(f64::MIN),
475        )
476    }
477
478    /// Creates a new BBox from a linestring
479    pub fn from_linestring<M: Clone>(line: &VectorLineString<M>) -> Self {
480        let mut bbox = BBox3D::from_point(&line[0]);
481        for point in line {
482            bbox.extend_from_point(point);
483        }
484        bbox
485    }
486
487    /// Creates a new BBox from a multi-linestring
488    pub fn from_multi_linestring<M: Clone>(lines: &VectorMultiLineString<M>) -> Self {
489        let mut bbox = BBox3D::from_point(&lines[0][0]);
490        for line in lines {
491            for point in line {
492                bbox.extend_from_point(point);
493            }
494        }
495        bbox
496    }
497
498    /// Creates a new BBox from a polygon
499    pub fn from_polygon<M: Clone>(polygon: &VectorPolygon<M>) -> Self {
500        BBox3D::<f64>::from_multi_linestring(polygon)
501    }
502
503    /// Creates a new BBox from a multi-polygon
504    pub fn from_multi_polygon<M: Clone>(polygons: &VectorMultiPolygon<M>) -> Self {
505        let mut bbox = BBox3D::from_point(&polygons[0][0][0]);
506        for polygon in polygons {
507            for line in polygon {
508                for point in line {
509                    bbox.extend_from_point(point);
510                }
511            }
512        }
513        bbox
514    }
515
516    /// Creates a new BBox3D from a BBox
517    pub fn from_bbox(bbox: &BBox) -> Self {
518        BBox3D::new(bbox.left, bbox.bottom, bbox.right, bbox.top, 0., 0.)
519    }
520
521    /// Extends the bounding box with a point
522    pub fn extend_from_point<M: Clone>(&mut self, point: &VectorPoint<M>) {
523        self.merge_in_place(&BBox3D::from_point(point));
524    }
525
526    /// Creates a new BBox3D from zoom-uv coordinates
527    pub fn from_uv_zoom(u: f64, v: f64, zoom: u8) -> Self {
528        let division_factor = 2. / (1 << zoom) as f64;
529
530        BBox3D {
531            left: division_factor * u - 1.0,
532            bottom: division_factor * v - 1.0,
533            right: division_factor * (u + 1.0) - 1.0,
534            top: division_factor * (v + 1.0) - 1.0,
535            near: f64::MAX,
536            far: f64::MIN,
537        }
538    }
539
540    /// Creates a new BBox from zoom-st coordinates
541    pub fn from_st_zoom(s: f64, t: f64, zoom: u8) -> Self {
542        let division_factor = (2. / (1 << zoom) as f64) * 0.5;
543
544        BBox3D {
545            left: division_factor * s,
546            bottom: division_factor * t,
547            right: division_factor * (s + 1.),
548            top: division_factor * (t + 1.),
549            near: f64::MAX,
550            far: f64::MIN,
551        }
552    }
553}
554impl From<BBox> for BBox3D<f64> {
555    fn from(bbox: BBox) -> Self {
556        BBox3D::from_bbox(&bbox)
557    }
558}
559impl<'de, T> Deserialize<'de> for BBox3D<T>
560where
561    T: Deserialize<'de> + Copy,
562{
563    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
564    where
565        D: Deserializer<'de>,
566    {
567        struct BBox3DVisitor<T> {
568            marker: core::marker::PhantomData<T>,
569        }
570
571        impl<'de, T> Visitor<'de> for BBox3DVisitor<T>
572        where
573            T: Deserialize<'de> + Copy,
574        {
575            type Value = BBox3D<T>;
576
577            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
578                formatter.write_str("a sequence of six numbers")
579            }
580
581            fn visit_seq<V>(self, mut seq: V) -> Result<BBox3D<T>, V::Error>
582            where
583                V: SeqAccess<'de>,
584            {
585                let left =
586                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(0, &self))?;
587                let bottom =
588                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(1, &self))?;
589                let right =
590                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(2, &self))?;
591                let top = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(3, &self))?;
592                let near =
593                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(4, &self))?;
594                let far = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(5, &self))?;
595                Ok(BBox3D { left, bottom, right, top, near, far })
596            }
597        }
598
599        deserializer.deserialize_tuple(6, BBox3DVisitor { marker: core::marker::PhantomData })
600    }
601}
602
603/// BBox or BBox3D
604#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
605pub enum BBOX {
606    /// 2D bounding box
607    BBox(BBox),
608    /// 3D bounding box
609    BBox3D(BBox3D),
610}
611impl Default for BBOX {
612    fn default() -> Self {
613        BBOX::BBox(BBox::default())
614    }
615}