h3ron_polars/algorithm/
bounding_rect.rs

1use crate::{Error, IndexChunked, IndexValue};
2use geo::BoundingRect as GeoBoundingRect;
3use geo_types::{coord, CoordNum, Rect};
4use h3ron::to_geo::ToLine;
5use h3ron::{H3Cell, H3DirectedEdge, ToPolygon};
6
7pub trait BoundingRect {
8    fn bounding_rect(&self) -> Result<Option<Rect>, Error>;
9}
10
11impl BoundingRect for H3Cell {
12    fn bounding_rect(&self) -> Result<Option<Rect>, Error> {
13        Ok(self.to_polygon()?.bounding_rect())
14    }
15}
16
17impl BoundingRect for H3DirectedEdge {
18    fn bounding_rect(&self) -> Result<Option<Rect>, Error> {
19        Ok(Some(self.to_line()?.bounding_rect()))
20    }
21}
22
23impl<'a, IX: IndexValue> BoundingRect for IndexChunked<'a, IX>
24where
25    IX: BoundingRect,
26{
27    fn bounding_rect(&self) -> Result<Option<Rect>, Error> {
28        let mut rect = None;
29        for maybe_index in self.iter_indexes_validated().flatten() {
30            let new_rect = maybe_index?.bounding_rect()?;
31
32            match (rect.as_mut(), new_rect) {
33                (None, Some(r)) => rect = Some(r),
34                (Some(agg), Some(this)) => *agg = bounding_rect_merge(agg, &this),
35                _ => (),
36            }
37        }
38        Ok(rect)
39    }
40}
41
42// Return a new rectangle that encompasses the provided rectangles
43//
44// taken from `geo` crate
45fn bounding_rect_merge<T: CoordNum>(a: &Rect<T>, b: &Rect<T>) -> Rect<T> {
46    Rect::new(
47        coord! {
48            x: partial_min(a.min().x, b.min().x),
49            y: partial_min(a.min().y, b.min().y),
50        },
51        coord! {
52            x: partial_max(a.max().x, b.max().x),
53            y: partial_max(a.max().y, b.max().y),
54        },
55    )
56}
57
58// The Rust standard library has `max` for `Ord`, but not for `PartialOrd`
59pub fn partial_max<T: PartialOrd>(a: T, b: T) -> T {
60    if a > b {
61        a
62    } else {
63        b
64    }
65}
66
67// The Rust standard library has `min` for `Ord`, but not for `PartialOrd`
68pub fn partial_min<T: PartialOrd>(a: T, b: T) -> T {
69    if a < b {
70        a
71    } else {
72        b
73    }
74}