Skip to main content

s2json_core/geometry/
bbox.rs

1use crate::*;
2use alloc::{fmt, vec};
3use core::{
4    cmp::Ordering,
5    ops::{Mul, MulAssign, Sub},
6};
7use serde::{
8    Deserialize, Deserializer, Serialize, Serializer,
9    de::{self, SeqAccess, Visitor},
10    ser::SerializeTuple,
11};
12
13/// Trait for types that have a min and max value. Used by [`BBox`] and [`BBox3D`]
14pub trait Bounded {
15    /// Get the minimum value
16    fn min_value() -> Self;
17    /// Get the maximum value
18    fn max_value() -> Self;
19}
20macro_rules! impl_bounded {
21    ($($t:ty),*) => {
22        $(
23            impl Bounded for $t {
24                fn min_value() -> Self {
25                    <$t>::MIN
26                }
27                fn max_value() -> Self {
28                    <$t>::MAX
29                }
30            }
31        )*
32    };
33}
34
35// Implement for common numeric types
36impl_bounded!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, isize, usize, f32, f64);
37
38/// # Bounding Box
39///
40/// ## Description
41///
42/// A Bounding Box ensures a min-max range of values
43///
44/// The order is (left, bottom, right, top) when storing as a flattened array.
45///
46/// If WM, then the projection is lon-lat. If S2, then the projection is s-t
47///
48/// Defaults to f64 as the base type.
49///
50/// Implements [`MValueCompatible`]
51///
52/// ## Usage
53///
54/// ## From/To
55/// - [`MValue`]
56/// - [`ValueType`]
57///
58/// ### Any Type BBox
59/// - [`BBox::new`]: Creates a new BBox
60/// - [`BBox::point_overlap`]: Checks if a point is within the BBox
61/// - [`BBox::merge`]: Merges another bounding box with this one
62/// - [`BBox::merge_in_place`]: Merges in place another bounding box with this one
63/// - [`BBox::overlap`]: Checks if another bounding box overlaps with this one
64/// - [`BBox::clip`]: Clips the bounding box along an axis
65/// - [`BBox::inside`]: Checks if this bounding box is inside another
66/// - [`BBox::area`]: Returns the area of the bounding box
67///
68/// ### `f64` Type BBox
69/// Note that all the input geometry uses the [`GetXY`] trait.
70/// - [`BBox::from_point`]: Creates a new BBox from a point
71/// - [`BBox::from_linestring`]: Creates a new BBox from a linestring
72/// - [`BBox::from_multi_linestring`]: Creates a new BBox from a multi-linestring
73/// - [`BBox::from_polygon`]: Creates a new BBox from a polygon
74/// - [`BBox::from_multi_polygon`]: Creates a new BBox from a multi-polygon
75/// - [`BBox::extend_from_point`]: Extends the bounding box with a point
76/// - [`BBox::from_uv_zoom`]: Creates a new BBox from zoom-uv coordinates
77/// - [`BBox::from_st_zoom`]: Creates a new BBox from zoom-st coordinates
78#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
79pub struct BBox<T = f64> {
80    /// left most longitude (WM) or S (S2)
81    pub left: T,
82    /// bottom most latitude (WM) or T (S2)
83    pub bottom: T,
84    /// right most longitude (WM) or T (S2)
85    pub right: T,
86    /// top most latitude (WM) or S (S2)
87    pub top: T,
88}
89impl From<(f64, f64, f64, f64)> for BBox<f64> {
90    fn from(bbox: (f64, f64, f64, f64)) -> Self {
91        BBox { left: bbox.0, bottom: bbox.1, right: bbox.2, top: bbox.3 }
92    }
93}
94impl From<BBox<f64>> for (f64, f64, f64, f64) {
95    fn from(bbox: BBox<f64>) -> Self {
96        (bbox.left, bbox.bottom, bbox.right, bbox.top)
97    }
98}
99impl<T> From<BBox<T>> for MValue
100where
101    T: Into<ValueType>,
102{
103    fn from(bbox: BBox<T>) -> MValue {
104        MValue::from([
105            ("left".into(), bbox.left.into()),
106            ("bottom".into(), bbox.bottom.into()),
107            ("right".into(), bbox.right.into()),
108            ("top".into(), bbox.top.into()),
109        ])
110    }
111}
112impl<T> From<&BBox<T>> for MValue
113where
114    T: Copy + Into<ValueType>,
115{
116    fn from(bbox: &BBox<T>) -> MValue {
117        MValue::from([
118            ("left".into(), bbox.left.into()),
119            ("bottom".into(), bbox.bottom.into()),
120            ("right".into(), bbox.right.into()),
121            ("top".into(), bbox.top.into()),
122        ])
123    }
124}
125impl<T> From<MValue> for BBox<T>
126where
127    T: From<ValueType>,
128{
129    fn from(mvalue: MValue) -> Self {
130        BBox {
131            left: mvalue.get("left").unwrap().clone().into(),
132            bottom: mvalue.get("bottom").unwrap().clone().into(),
133            right: mvalue.get("right").unwrap().clone().into(),
134            top: mvalue.get("top").unwrap().clone().into(),
135        }
136    }
137}
138impl<T> From<&MValue> for BBox<T>
139where
140    T: From<ValueType>,
141{
142    fn from(mvalue: &MValue) -> Self {
143        BBox {
144            left: mvalue.get("left").unwrap().clone().into(),
145            bottom: mvalue.get("bottom").unwrap().clone().into(),
146            right: mvalue.get("right").unwrap().clone().into(),
147            top: mvalue.get("top").unwrap().clone().into(),
148        }
149    }
150}
151impl<T> From<BBox<T>> for ValueType
152where
153    T: Into<ValueType>,
154{
155    fn from(bbox: BBox<T>) -> Self {
156        MValue::from(bbox).into()
157    }
158}
159impl<T> From<&ValueType> for BBox<T>
160where
161    T: From<ValueType>,
162{
163    fn from(bbox: &ValueType) -> Self {
164        MValue::from(bbox).into()
165    }
166}
167impl From<BBox> for VectorFeature {
168    fn from(bbox: BBox) -> Self {
169        let BBox { left, bottom, right, top } = bbox;
170
171        VectorFeature::new_wm(
172            None,
173            Properties::from([("bbox".into(), bbox.into())]),
174            VectorGeometry::new_polygon(
175                vec![vec![
176                    VectorPoint::from_xy(left, bottom),
177                    VectorPoint::from_xy(right, bottom),
178                    VectorPoint::from_xy(right, top),
179                    VectorPoint::from_xy(left, top),
180                    VectorPoint::from_xy(left, bottom),
181                ]],
182                Some(bbox.into()),
183            ),
184            None,
185        )
186    }
187}
188impl<T> MValueCompatible for BBox<T>
189where
190    ValueType: From<T>,
191    T: From<ValueType> + Default + Bounded + Copy + Interpolate,
192{
193}
194impl<T> Default for BBox<T>
195where
196    T: Default + Bounded + Copy,
197{
198    fn default() -> Self {
199        BBox::new(T::max_value(), T::max_value(), T::min_value(), T::min_value())
200    }
201}
202impl<T> BBox<T> {
203    /// Creates a new BBox
204    pub fn new(left: T, bottom: T, right: T, top: T) -> Self
205    where
206        T: Copy,
207    {
208        BBox { left, bottom, right, top }
209    }
210
211    /// Checks if a point is within the BBox
212    pub fn point_overlap<P: GetXY>(&self, point: &P) -> bool
213    where
214        T: Into<f64> + Copy, // Ensures that comparison operators work for type T
215    {
216        point.x() >= self.left.into()
217            && point.x() <= self.right.into()
218            && point.y() >= self.bottom.into()
219            && point.y() <= self.top.into()
220    }
221
222    /// Merges another bounding box with this one
223    pub fn merge(&self, other: &Self) -> Self
224    where
225        T: PartialOrd + Copy,
226    {
227        let mut new_bbox = *self;
228        new_bbox.left = if new_bbox.left < other.left { new_bbox.left } else { other.left };
229        new_bbox.bottom =
230            if new_bbox.bottom < other.bottom { new_bbox.bottom } else { other.bottom };
231        new_bbox.right = if new_bbox.right > other.right { new_bbox.right } else { other.right };
232        new_bbox.top = if new_bbox.top > other.top { new_bbox.top } else { other.top };
233
234        new_bbox
235    }
236
237    /// Merges in place another bounding box with this one
238    pub fn merge_in_place(&mut self, other: &Self)
239    where
240        T: PartialOrd + Copy,
241    {
242        self.left = if self.left < other.left { self.left } else { other.left };
243        self.bottom = if self.bottom < other.bottom { self.bottom } else { other.bottom };
244        self.right = if self.right > other.right { self.right } else { other.right };
245        self.top = if self.top > other.top { self.top } else { other.top };
246    }
247
248    /// Checks if another bounding box overlaps with this one and returns the overlap
249    pub fn overlap(&self, other: &BBox<T>) -> Option<BBox<T>>
250    where
251        T: PartialOrd + Copy,
252    {
253        if self.left > other.right
254            || self.right < other.left
255            || self.bottom > other.top
256            || self.top < other.bottom
257        {
258            None
259        } else {
260            let left = if self.left > other.left { self.left } else { other.left };
261            let bottom = if self.bottom > other.bottom { self.bottom } else { other.bottom };
262            let right = if self.right < other.right { self.right } else { other.right };
263            let top = if self.top < other.top { self.top } else { other.top };
264
265            Some(BBox { left, bottom, right, top })
266        }
267    }
268
269    /// Clips the bounding box along an axis
270    pub fn clip(&self, axis: Axis, k1: T, k2: T) -> BBox<T>
271    where
272        T: PartialOrd + Copy,
273    {
274        let mut new_bbox = *self;
275        if axis == Axis::X {
276            new_bbox.left = if new_bbox.left > k1 { new_bbox.left } else { k1 };
277            new_bbox.right = if new_bbox.right < k2 { new_bbox.right } else { k2 };
278        } else {
279            new_bbox.bottom = if new_bbox.bottom > k1 { new_bbox.bottom } else { k1 };
280            new_bbox.top = if new_bbox.top < k2 { new_bbox.top } else { k2 };
281        }
282
283        new_bbox
284    }
285
286    /// Checks if this bounding box is inside another
287    pub fn inside(&self, other: &BBox<T>) -> bool
288    where
289        T: PartialOrd + Copy,
290    {
291        self.left >= other.left
292            && self.right <= other.right
293            && self.bottom >= other.bottom
294            && self.top <= other.top
295    }
296
297    /// Returns the area of the bounding box
298    pub fn area(&self) -> T
299    where
300        T: Sub<Output = T> + Mul<Output = T> + Copy,
301    {
302        (self.right - self.left) * (self.top - self.bottom)
303    }
304}
305impl BBox<f64> {
306    /// Creates a new BBox from a point
307    pub fn from_point<P: GetXY>(point: &P) -> Self {
308        BBox::new(point.x(), point.y(), point.x(), point.y())
309    }
310
311    /// Creates a new BBox from a linestring
312    pub fn from_linestring<P: GetXY>(line: &[P]) -> Self {
313        let mut bbox = BBox::default();
314        for point in line {
315            bbox.extend_from_point(point);
316        }
317        bbox
318    }
319
320    /// Creates a new BBox from a multi-linestring
321    pub fn from_multi_linestring<P: GetXY>(lines: &[Vec<P>]) -> Self {
322        let mut bbox = BBox::default();
323        for line in lines {
324            for point in line {
325                bbox.extend_from_point(point);
326            }
327        }
328        bbox
329    }
330
331    /// Creates a new BBox from a polygon
332    pub fn from_polygon<P: GetXY>(polygon: &[Vec<P>]) -> Self {
333        Self::from_multi_linestring(polygon)
334    }
335
336    /// Creates a new BBox from a multi-polygon
337    pub fn from_multi_polygon<P: GetXY>(polygons: &[Vec<Vec<P>>]) -> Self {
338        let mut bbox = BBox::default();
339        for polygon in polygons {
340            for line in polygon {
341                for point in line {
342                    bbox.extend_from_point(point);
343                }
344            }
345        }
346        bbox
347    }
348
349    /// Extends the bounding box with a point
350    pub fn extend_from_point<P: GetXY>(&mut self, point: &P) {
351        self.merge_in_place(&BBox::from_point(point));
352    }
353
354    /// Creates a new BBox from zoom-uv coordinates
355    pub fn from_uv_zoom(u: f64, v: f64, zoom: u8) -> Self {
356        let division_factor = 2. / (1 << zoom) as f64;
357
358        BBox {
359            left: division_factor * u - 1.0,
360            bottom: division_factor * v - 1.0,
361            right: division_factor * (u + 1.0) - 1.0,
362            top: division_factor * (v + 1.0) - 1.0,
363        }
364    }
365
366    /// Creates a new BBox from zoom-st coordinates
367    pub fn from_st_zoom(s: f64, t: f64, zoom: u8) -> Self {
368        let division_factor = (2. / (1 << zoom) as f64) * 0.5;
369
370        BBox {
371            left: division_factor * s,
372            bottom: division_factor * t,
373            right: division_factor * (s + 1.),
374            top: division_factor * (t + 1.),
375        }
376    }
377}
378impl<T> Serialize for BBox<T>
379where
380    T: Serialize + Copy,
381{
382    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
383    where
384        S: Serializer,
385    {
386        let mut seq = serializer.serialize_tuple(4)?;
387        seq.serialize_element(&self.left)?;
388        seq.serialize_element(&self.bottom)?;
389        seq.serialize_element(&self.right)?;
390        seq.serialize_element(&self.top)?;
391        seq.end()
392    }
393}
394impl<T: Copy> From<BBox3D<T>> for BBox<T> {
395    fn from(bbox: BBox3D<T>) -> Self {
396        BBox::new(bbox.left, bbox.bottom, bbox.right, bbox.top)
397    }
398}
399impl<'de, T> Deserialize<'de> for BBox<T>
400where
401    T: Deserialize<'de> + Copy,
402{
403    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
404    where
405        D: Deserializer<'de>,
406    {
407        struct BBoxVisitor<T> {
408            marker: core::marker::PhantomData<T>,
409        }
410
411        impl<'de, T> Visitor<'de> for BBoxVisitor<T>
412        where
413            T: Deserialize<'de> + Copy,
414        {
415            type Value = BBox<T>;
416
417            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
418                formatter.write_str("a sequence of four numbers")
419            }
420
421            fn visit_seq<V>(self, mut seq: V) -> Result<BBox<T>, V::Error>
422            where
423                V: SeqAccess<'de>,
424            {
425                let left =
426                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(0, &self))?;
427                let bottom =
428                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(1, &self))?;
429                let right =
430                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(2, &self))?;
431                let top = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(3, &self))?;
432                Ok(BBox { left, bottom, right, top })
433            }
434        }
435
436        deserializer.deserialize_tuple(4, BBoxVisitor { marker: core::marker::PhantomData })
437    }
438}
439
440/// # 3D Bounding Box
441///
442/// ## Description
443///
444/// A 3D Bounding Box ensures a min-max range of values and includes a near-far range
445///
446/// The order is (left, bottom, right, top, near, far) when storing as a flattened array.
447///
448/// If WM, then the projection is lon-lat. If S2, then the projection is s-t
449///
450/// Defaults to f64 as the base type.
451///
452/// Implements [`MValueCompatible`] as well as [`Interpolate`].
453///
454/// ## Usage
455///
456/// ## From/To
457/// - [`MValue`]
458/// - [`ValueType`]
459///
460/// ### Any Type BBox
461/// - [`BBox3D::new`]: Creates a new BBox
462/// - [`BBox3D::point_overlap`]: Checks if a point is within the BBox
463/// - [`BBox3D::merge`]: Merges another bounding box with this one
464/// - [`BBox3D::merge_in_place`]: Merges in place another bounding box with this one
465/// - [`BBox3D::overlap`]: Checks if another bounding box overlaps with this one
466/// - [`BBox3D::clip`]: Clips the bounding box along an axis
467/// - [`BBox3D::inside`]: Checks if this bounding box is inside another
468/// - [`BBox3D::from_bbox`]: Creates a new BBox3D from a BBox
469/// - [`BBox3D::area`]: Returns the area of the bounding box
470///
471/// ### `f64` Type BBox
472/// Note that all the input geometry uses the [`GetXY`] and [`GetZ`] traits.
473/// - [`BBox3D::from_point`]: Creates a new BBox from a point
474/// - [`BBox3D::from_linestring`]: Creates a new BBox from a linestring
475/// - [`BBox3D::from_multi_linestring`]: Creates a new BBox from a multi-linestring
476/// - [`BBox3D::from_polygon`]: Creates a new BBox from a polygon
477/// - [`BBox3D::from_multi_polygon`]: Creates a new BBox from a multi-polygon
478/// - [`BBox3D::extend_from_point`]: Extends the bounding box with a point
479/// - [`BBox3D::from_uv_zoom`]: Creates a new BBox from zoom-uv coordinates
480/// - [`BBox3D::from_st_zoom`]: Creates a new BBox from zoom-st coordinates
481#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
482pub struct BBox3D<T = f64> {
483    /// left most longitude (WM) or S (S2)
484    pub left: T,
485    /// bottom most latitude (WM) or T (S2)
486    pub bottom: T,
487    /// right most longitude (WM) or T (S2)
488    pub right: T,
489    /// top most latitude (WM) or S (S2)
490    pub top: T,
491    /// near most height (WM) or T (S2)
492    /// generic height is relative to the surface of the earth in meters
493    pub near: T,
494    /// far most height (WM) or T (S2)
495    /// generic height is relative to the surface of the earth in meters
496    pub far: T,
497}
498impl From<(f64, f64, f64, f64, f64, f64)> for BBox3D<f64> {
499    fn from(bbox: (f64, f64, f64, f64, f64, f64)) -> Self {
500        BBox3D {
501            left: bbox.0,
502            bottom: bbox.1,
503            right: bbox.2,
504            top: bbox.3,
505            near: bbox.4,
506            far: bbox.5,
507        }
508    }
509}
510impl From<BBox3D<f64>> for (f64, f64, f64, f64, f64, f64) {
511    fn from(bbox: BBox3D<f64>) -> Self {
512        (bbox.left, bbox.bottom, bbox.right, bbox.top, bbox.near, bbox.far)
513    }
514}
515impl<T> From<BBox3D<T>> for MValue
516where
517    T: Into<ValueType>,
518{
519    fn from(bbox: BBox3D<T>) -> MValue {
520        MValue::from([
521            ("left".into(), bbox.left.into()),
522            ("bottom".into(), bbox.bottom.into()),
523            ("right".into(), bbox.right.into()),
524            ("top".into(), bbox.top.into()),
525            ("near".into(), bbox.near.into()),
526            ("far".into(), bbox.far.into()),
527        ])
528    }
529}
530impl<T> From<&BBox3D<T>> for MValue
531where
532    T: Copy + Into<ValueType>,
533{
534    fn from(bbox: &BBox3D<T>) -> MValue {
535        MValue::from([
536            ("left".into(), bbox.left.into()),
537            ("bottom".into(), bbox.bottom.into()),
538            ("right".into(), bbox.right.into()),
539            ("top".into(), bbox.top.into()),
540            ("near".into(), bbox.near.into()),
541            ("far".into(), bbox.far.into()),
542        ])
543    }
544}
545impl<T> From<MValue> for BBox3D<T>
546where
547    T: From<ValueType>,
548{
549    fn from(mvalue: MValue) -> Self {
550        BBox3D {
551            left: mvalue.get("left").unwrap().clone().into(),
552            bottom: mvalue.get("bottom").unwrap().clone().into(),
553            right: mvalue.get("right").unwrap().clone().into(),
554            top: mvalue.get("top").unwrap().clone().into(),
555            near: mvalue.get("near").unwrap().clone().into(),
556            far: mvalue.get("far").unwrap().clone().into(),
557        }
558    }
559}
560impl<T> From<&MValue> for BBox3D<T>
561where
562    T: From<ValueType>,
563{
564    fn from(mvalue: &MValue) -> Self {
565        BBox3D {
566            left: mvalue.get("left").unwrap().clone().into(),
567            bottom: mvalue.get("bottom").unwrap().clone().into(),
568            right: mvalue.get("right").unwrap().clone().into(),
569            top: mvalue.get("top").unwrap().clone().into(),
570            near: mvalue.get("near").unwrap().clone().into(),
571            far: mvalue.get("far").unwrap().clone().into(),
572        }
573    }
574}
575impl<T> From<BBox3D<T>> for ValueType
576where
577    T: Into<ValueType>,
578{
579    fn from(bbox: BBox3D<T>) -> Self {
580        MValue::from(bbox).into()
581    }
582}
583impl<T> From<&ValueType> for BBox3D<T>
584where
585    T: From<ValueType>,
586{
587    fn from(bbox: &ValueType) -> Self {
588        MValue::from(bbox).into()
589    }
590}
591impl From<BBox3D> for VectorFeature {
592    fn from(bbox: BBox3D) -> Self {
593        let BBox3D { left, bottom, right, top, .. } = bbox;
594
595        VectorFeature::new_wm(
596            None,
597            Properties::from([("bbox".into(), bbox.into())]),
598            VectorGeometry::new_polygon(
599                vec![vec![
600                    VectorPoint::from_xy(left, bottom),
601                    VectorPoint::from_xy(right, bottom),
602                    VectorPoint::from_xy(right, top),
603                    VectorPoint::from_xy(left, top),
604                    VectorPoint::from_xy(left, bottom),
605                ]],
606                Some(bbox),
607            ),
608            None,
609        )
610    }
611}
612impl<T> MValueCompatible for BBox3D<T>
613where
614    ValueType: From<T>,
615    T: From<ValueType> + Default + Bounded + Copy + Interpolate,
616{
617}
618impl<T> BBox3D<T> {
619    /// Creates a new BBox3D
620    pub fn new(left: T, bottom: T, right: T, top: T, near: T, far: T) -> Self
621    where
622        T: Copy,
623    {
624        BBox3D { left, bottom, right, top, near, far }
625    }
626
627    /// Checks if a point is within the BBox
628    pub fn point_overlap<P: GetXY + GetZ>(&self, point: &P) -> bool
629    where
630        T: Into<f64> + Copy, // Ensures that comparison operators work for type T
631    {
632        let z = point.z().unwrap_or_default();
633        point.x() >= self.left.into()
634            && point.x() <= self.right.into()
635            && point.y() >= self.bottom.into()
636            && point.y() <= self.top.into()
637            && z >= self.near.into()
638            && z <= self.far.into()
639    }
640
641    /// Merges another bounding box with this one
642    pub fn merge(&self, other: &BBox3D<T>) -> BBox3D<T>
643    where
644        T: PartialOrd + Copy,
645    {
646        let mut new_bbox = *self;
647        new_bbox.left = if new_bbox.left < other.left { new_bbox.left } else { other.left };
648        new_bbox.bottom =
649            if new_bbox.bottom < other.bottom { new_bbox.bottom } else { other.bottom };
650        new_bbox.right = if new_bbox.right > other.right { new_bbox.right } else { other.right };
651        new_bbox.top = if new_bbox.top > other.top { new_bbox.top } else { other.top };
652        new_bbox.near = if new_bbox.near < other.near { new_bbox.near } else { other.near };
653        new_bbox.far = if new_bbox.far > other.far { new_bbox.far } else { other.far };
654
655        new_bbox
656    }
657
658    /// Merges in place another bounding box with this one
659    pub fn merge_in_place(&mut self, other: &Self)
660    where
661        T: PartialOrd + Copy,
662    {
663        self.left = if self.left < other.left { self.left } else { other.left };
664        self.bottom = if self.bottom < other.bottom { self.bottom } else { other.bottom };
665        self.right = if self.right > other.right { self.right } else { other.right };
666        self.top = if self.top > other.top { self.top } else { other.top };
667        self.near = if self.near < other.near { self.near } else { other.near };
668        self.far = if self.far > other.far { self.far } else { other.far };
669    }
670
671    /// Checks if another bounding box overlaps with this one and returns the overlap
672    pub fn overlap(&self, other: &BBox3D<T>) -> Option<BBox3D<T>>
673    where
674        T: PartialOrd + Copy,
675    {
676        if self.left > other.right
677            || self.right < other.left
678            || self.bottom > other.top
679            || self.top < other.bottom
680            || self.near > other.far
681            || self.far < other.near
682        {
683            None
684        } else {
685            let left = if self.left > other.left { self.left } else { other.left };
686            let bottom = if self.bottom > other.bottom { self.bottom } else { other.bottom };
687            let right = if self.right < other.right { self.right } else { other.right };
688            let top = if self.top < other.top { self.top } else { other.top };
689
690            let near = if self.near > other.near { self.near } else { other.near };
691            let far = if self.far < other.far { self.far } else { other.far };
692
693            Some(BBox3D { left, bottom, right, top, near, far })
694        }
695    }
696
697    /// Clips the bounding box along an axis
698    pub fn clip(&self, axis: Axis, k1: T, k2: T) -> BBox3D<T>
699    where
700        T: PartialOrd + Copy,
701    {
702        let mut new_bbox = *self;
703        if axis == Axis::X {
704            new_bbox.left = if new_bbox.left > k1 { new_bbox.left } else { k1 };
705            new_bbox.right = if new_bbox.right < k2 { new_bbox.right } else { k2 };
706        } else {
707            new_bbox.bottom = if new_bbox.bottom > k1 { new_bbox.bottom } else { k1 };
708            new_bbox.top = if new_bbox.top < k2 { new_bbox.top } else { k2 };
709        }
710
711        new_bbox
712    }
713
714    /// Creates a new BBox3D from a BBox
715    pub fn from_bbox(bbox: &BBox<T>) -> Self
716    where
717        T: Copy + Default,
718    {
719        BBox3D::new(bbox.left, bbox.bottom, bbox.right, bbox.top, T::default(), T::default())
720    }
721
722    /// Checks if this bounding box is inside another
723    pub fn inside(&self, other: &BBox3D<T>) -> bool
724    where
725        T: PartialOrd + Copy,
726    {
727        self.left >= other.left
728            && self.right <= other.right
729            && self.bottom >= other.bottom
730            && self.top <= other.top
731            && self.near >= other.near
732            && self.far <= other.far
733    }
734
735    /// Returns the area of the bounding box
736    pub fn area(&self) -> T
737    where
738        T: Sub<Output = T> + Mul<Output = T> + MulAssign + Into<f64> + Copy,
739    {
740        let mut res = (self.right - self.left) * (self.top - self.bottom);
741        if self.far.into() != 0. || self.near.into() != 0. {
742            res *= self.far - self.near
743        }
744
745        res
746    }
747}
748impl<T> Serialize for BBox3D<T>
749where
750    T: Serialize + Copy,
751{
752    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
753    where
754        S: Serializer,
755    {
756        let mut seq = serializer.serialize_tuple(6)?;
757        seq.serialize_element(&self.left)?;
758        seq.serialize_element(&self.bottom)?;
759        seq.serialize_element(&self.right)?;
760        seq.serialize_element(&self.top)?;
761        seq.serialize_element(&self.near)?;
762        seq.serialize_element(&self.far)?;
763        seq.end()
764    }
765}
766impl<T> Default for BBox3D<T>
767where
768    T: Default + Bounded + Copy,
769{
770    fn default() -> Self {
771        BBox3D::new(
772            T::max_value(),
773            T::max_value(),
774            T::min_value(),
775            T::min_value(),
776            T::max_value(),
777            T::min_value(),
778        )
779    }
780}
781impl BBox3D<f64> {
782    /// Creates a new BBox3D from a point
783    pub fn from_point<P: GetXY + GetZ>(point: &P) -> Self {
784        BBox3D::new(
785            point.x(),
786            point.y(),
787            point.x(),
788            point.y(),
789            point.z().unwrap_or(f64::MAX),
790            point.z().unwrap_or(f64::MIN),
791        )
792    }
793
794    /// Creates a new BBox from a linestring
795    pub fn from_linestring<P: GetXY + GetZ>(line: &[P]) -> Self {
796        let mut bbox = BBox3D::default();
797        for point in line {
798            bbox.extend_from_point(point);
799        }
800        bbox
801    }
802
803    /// Creates a new BBox from a multi-linestring
804    pub fn from_multi_linestring<P: GetXY + GetZ>(lines: &[Vec<P>]) -> Self {
805        let mut bbox = BBox3D::default();
806        for line in lines {
807            for point in line {
808                bbox.extend_from_point(point);
809            }
810        }
811        bbox
812    }
813
814    /// Creates a new BBox from a polygon
815    pub fn from_polygon<P: GetXY + GetZ>(polygon: &[Vec<P>]) -> Self {
816        Self::from_multi_linestring(polygon)
817    }
818
819    /// Creates a new BBox from a multi-polygon
820    pub fn from_multi_polygon<P: GetXY + GetZ>(polygons: &[Vec<Vec<P>>]) -> Self {
821        let mut bbox = BBox3D::default();
822        for polygon in polygons {
823            for line in polygon {
824                for point in line {
825                    bbox.extend_from_point(point);
826                }
827            }
828        }
829        bbox
830    }
831
832    /// Extends the bounding box with a point
833    pub fn extend_from_point<P: GetXY + GetZ>(&mut self, point: &P) {
834        self.merge_in_place(&BBox3D::from_point(point));
835    }
836
837    /// Creates a new BBox3D from zoom-uv coordinates
838    pub fn from_uv_zoom(u: f64, v: f64, zoom: u8) -> Self {
839        let division_factor = 2. / (1 << zoom) as f64;
840
841        BBox3D {
842            left: division_factor * u - 1.0,
843            bottom: division_factor * v - 1.0,
844            right: division_factor * (u + 1.0) - 1.0,
845            top: division_factor * (v + 1.0) - 1.0,
846            near: f64::MAX,
847            far: f64::MIN,
848        }
849    }
850
851    /// Creates a new BBox from zoom-st coordinates
852    pub fn from_st_zoom(s: f64, t: f64, zoom: u8) -> Self {
853        let division_factor = (2. / (1 << zoom) as f64) * 0.5;
854
855        BBox3D {
856            left: division_factor * s,
857            bottom: division_factor * t,
858            right: division_factor * (s + 1.),
859            top: division_factor * (t + 1.),
860            near: f64::MAX,
861            far: f64::MIN,
862        }
863    }
864}
865impl<T: Default + Copy> From<BBox<T>> for BBox3D<T> {
866    fn from(bbox: BBox<T>) -> Self {
867        BBox3D::from_bbox(&bbox)
868    }
869}
870impl<'de, T> Deserialize<'de> for BBox3D<T>
871where
872    T: Deserialize<'de> + Copy,
873{
874    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
875    where
876        D: Deserializer<'de>,
877    {
878        struct BBox3DVisitor<T> {
879            marker: core::marker::PhantomData<T>,
880        }
881
882        impl<'de, T> Visitor<'de> for BBox3DVisitor<T>
883        where
884            T: Deserialize<'de> + Copy,
885        {
886            type Value = BBox3D<T>;
887
888            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
889                formatter.write_str("a sequence of six numbers")
890            }
891
892            fn visit_seq<V>(self, mut seq: V) -> Result<BBox3D<T>, V::Error>
893            where
894                V: SeqAccess<'de>,
895            {
896                let left =
897                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(0, &self))?;
898                let bottom =
899                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(1, &self))?;
900                let right =
901                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(2, &self))?;
902                let top = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(3, &self))?;
903                let near =
904                    seq.next_element()?.ok_or_else(|| de::Error::invalid_length(4, &self))?;
905                let far = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(5, &self))?;
906                Ok(BBox3D { left, bottom, right, top, near, far })
907            }
908        }
909
910        deserializer.deserialize_tuple(6, BBox3DVisitor { marker: core::marker::PhantomData })
911    }
912}
913
914/// BBox or BBox3D. Mostly an internal tool
915#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)]
916pub enum BBOX {
917    /// 2D bounding box
918    BBox(BBox),
919    /// 3D bounding box
920    BBox3D(BBox3D),
921}
922impl Default for BBOX {
923    fn default() -> Self {
924        BBOX::BBox(BBox::default())
925    }
926}
927impl From<BBox> for BBOX {
928    fn from(bbox: BBox) -> Self {
929        BBOX::BBox(bbox)
930    }
931}
932impl From<BBox3D> for BBOX {
933    fn from(bbox: BBox3D) -> Self {
934        BBOX::BBox3D(bbox)
935    }
936}
937impl From<BBOX> for ValueType {
938    fn from(bbox: BBOX) -> Self {
939        match bbox {
940            BBOX::BBox(b) => b.into(),
941            BBOX::BBox3D(b) => b.into(),
942        }
943    }
944}
945impl From<BBOX> for VectorFeature {
946    fn from(bbox: BBOX) -> Self {
947        match bbox {
948            BBOX::BBox(b) => b.into(),
949            BBOX::BBox3D(b) => b.into(),
950        }
951    }
952}
953impl Eq for BBOX {}
954impl PartialOrd for BBOX {
955    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
956        Some(self.cmp(other))
957    }
958}
959impl Ord for BBOX {
960    fn cmp(&self, other: &Self) -> Ordering {
961        match (self, other) {
962            (BBOX::BBox(a), BBOX::BBox(b)) => a.partial_cmp(b).unwrap_or(Ordering::Equal),
963            (BBOX::BBox3D(a), BBOX::BBox3D(b)) => a.partial_cmp(b).unwrap_or(Ordering::Equal),
964            // Ensure that BBox and BBox3D are ordered correctly
965            (BBOX::BBox(_), BBOX::BBox3D(_)) => Ordering::Less,
966            (BBOX::BBox3D(_), BBOX::BBox(_)) => Ordering::Greater,
967        }
968    }
969}