Skip to content

Commit

Permalink
Implement RTreeObject for Geometry enum
Browse files Browse the repository at this point in the history
  • Loading branch information
urschrei committed Apr 11, 2023
1 parent c31ac45 commit b0fc46f
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 1 deletion.
56 changes: 56 additions & 0 deletions geo-types/src/geometry/geometry_collection.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
use crate::{coord, Point, Rect};
use crate::{CoordNum, Geometry};
#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
use num_traits::Bounded;

use alloc::vec;
use alloc::vec::Vec;
Expand Down Expand Up @@ -247,6 +251,58 @@ impl<'a, T: CoordNum> GeometryCollection<T> {
}
}

// Return a new rectangle that encompasses the provided rectangles
fn bounding_rect_merge<T: CoordNum>(a: Rect<T>, b: Rect<T>) -> Rect<T> {
Rect::new(
coord! {
x: crate::private_utils::partial_min(a.min().x, b.min().x),
y: crate::private_utils::partial_min(a.min().y, b.min().y),
},
coord! {
x: crate::private_utils::partial_max(a.max().x, b.max().x),
y: crate::private_utils::partial_max(a.max().y, b.max().y),
},
)
}

#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
macro_rules! impl_rstar_geometry_collection {
($rstar:ident) => {
impl<T> $rstar::RTreeObject for GeometryCollection<T>
where
T: ::num_traits::Float + ::$rstar::RTreeNum,
{
type Envelope = ::$rstar::AABB<Point<T>>;

fn envelope(&self) -> Self::Envelope {
let bounding_rect = self.iter().fold(None, |acc, next| {
let next_bounding_rect = next.envelope();
let lower = next_bounding_rect.lower();
let upper = next_bounding_rect.upper();
let rect = Rect::new(lower, upper);
Some(bounding_rect_merge(acc.unwrap(), rect))
});
match bounding_rect {
None => ::$rstar::AABB::from_corners(
Point::new(Bounded::min_value(), Bounded::min_value()),
Point::new(Bounded::max_value(), Bounded::max_value()),
),
Some(b) => ::$rstar::AABB::from_corners(
Point::new(b.min().x, b.min().y),
Point::new(b.max().x, b.max().y),
),
}
}
}
};
}

#[cfg(feature = "rstar_0_8")]
impl_rstar_geometry_collection!(rstar_0_8);

#[cfg(feature = "rstar_0_9")]
impl_rstar_geometry_collection!(rstar_0_9);

#[cfg(any(feature = "approx", test))]
impl<T> RelativeEq for GeometryCollection<T>
where
Expand Down
33 changes: 33 additions & 0 deletions geo-types/src/geometry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,39 @@ where
}
}

#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
macro_rules! impl_rstar_geometry {
($rstar:ident) => {
impl<T> $rstar::RTreeObject for Geometry<T>
where
T: ::num_traits::Float + ::$rstar::RTreeNum,
{
type Envelope = ::$rstar::AABB<Point<T>>;

fn envelope(&self) -> Self::Envelope {
match self {
Self::Point(x) => x.envelope(),
Self::Line(x) => x.envelope(),
Self::LineString(x) => x.envelope(),
Self::Polygon(x) => x.envelope(),
Self::Rect(x) => x.envelope(),
Self::Triangle(x) => x.envelope(),
Self::MultiPoint(x) => x.envelope(),
Self::MultiLineString(x) => x.envelope(),
Self::MultiPolygon(x) => x.envelope(),
Self::GeometryCollection(x) => x.envelope(),
}
}
}
};
}

#[cfg(feature = "rstar_0_8")]
impl_rstar_geometry!(rstar_0_8);

#[cfg(feature = "rstar_0_9")]
impl_rstar_geometry!(rstar_0_9);

#[cfg(any(feature = "approx", test))]
impl<T> RelativeEq for Geometry<T>
where
Expand Down
39 changes: 39 additions & 0 deletions geo-types/src/geometry/multi_line_string.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
use crate::Point;
#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
use num_traits::Bounded;

use crate::{CoordNum, LineString};

use alloc::vec;
Expand Down Expand Up @@ -118,6 +123,40 @@ impl<T: CoordNum> MultiLineString<T> {
}
}

#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
macro_rules! impl_rstar_multi_linestring {
($rstar:ident) => {
impl<T> $rstar::RTreeObject for MultiLineString<T>
where
T: ::num_traits::Float + ::$rstar::RTreeNum,
{
type Envelope = ::$rstar::AABB<Point<T>>;

fn envelope(&self) -> Self::Envelope {
let bounding_rect = crate::private_utils::get_bounding_rect(
self.iter().flat_map(|line| line.0.iter().cloned()),
);
match bounding_rect {
None => ::$rstar::AABB::from_corners(
Point::new(Bounded::min_value(), Bounded::min_value()),
Point::new(Bounded::max_value(), Bounded::max_value()),
),
Some(b) => ::$rstar::AABB::from_corners(
Point::new(b.min().x, b.min().y),
Point::new(b.max().x, b.max().y),
),
}
}
}
};
}

#[cfg(feature = "rstar_0_8")]
impl_rstar_multi_linestring!(rstar_0_8);

#[cfg(feature = "rstar_0_9")]
impl_rstar_multi_linestring!(rstar_0_9);

#[cfg(any(feature = "approx", test))]
impl<T> RelativeEq for MultiLineString<T>
where
Expand Down
36 changes: 35 additions & 1 deletion geo-types/src/geometry/multi_point.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::{CoordNum, Point};

#[cfg(any(feature = "approx", test))]
use approx::{AbsDiffEq, RelativeEq};
#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
use num_traits::Bounded;

use alloc::vec;
use alloc::vec::Vec;
Expand Down Expand Up @@ -99,6 +100,39 @@ impl<T: CoordNum> MultiPoint<T> {
}
}

#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
macro_rules! impl_rstar_multi_point {
($rstar:ident) => {
impl<T> $rstar::RTreeObject for MultiPoint<T>
where
T: ::num_traits::Float + ::$rstar::RTreeNum,
{
type Envelope = ::$rstar::AABB<Point<T>>;

fn envelope(&self) -> Self::Envelope {
let bounding_rect =
crate::private_utils::get_bounding_rect(self.0.iter().map(|p| p.0));
match bounding_rect {
None => ::$rstar::AABB::from_corners(
Point::new(Bounded::min_value(), Bounded::min_value()),
Point::new(Bounded::max_value(), Bounded::max_value()),
),
Some(b) => ::$rstar::AABB::from_corners(
Point::new(b.min().x, b.min().y),
Point::new(b.max().x, b.max().y),
),
}
}
}
};
}

#[cfg(feature = "rstar_0_8")]
impl_rstar_multi_point!(rstar_0_8);

#[cfg(feature = "rstar_0_9")]
impl_rstar_multi_point!(rstar_0_9);

#[cfg(any(feature = "approx", test))]
impl<T> RelativeEq for MultiPoint<T>
where
Expand Down
39 changes: 39 additions & 0 deletions geo-types/src/geometry/multi_polygon.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
use crate::Point;
use crate::{CoordNum, Polygon};
#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
use num_traits::Bounded;

use alloc::vec;
use alloc::vec::Vec;
Expand Down Expand Up @@ -91,6 +95,41 @@ impl<T: CoordNum> MultiPolygon<T> {
}
}

#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
macro_rules! impl_rstar_multi_polygon {
($rstar:ident) => {
impl<T> $rstar::RTreeObject for MultiPolygon<T>
where
T: ::num_traits::Float + ::$rstar::RTreeNum,
{
type Envelope = ::$rstar::AABB<Point<T>>;

fn envelope(&self) -> Self::Envelope {
let bounding_rect = crate::private_utils::get_bounding_rect(
self.iter()
.flat_map(|poly| poly.exterior().0.iter().cloned()),
);
match bounding_rect {
None => ::$rstar::AABB::from_corners(
Point::new(Bounded::min_value(), Bounded::min_value()),
Point::new(Bounded::max_value(), Bounded::max_value()),
),
Some(b) => ::$rstar::AABB::from_corners(
Point::new(b.min().x, b.min().y),
Point::new(b.max().x, b.max().y),
),
}
}
}
};
}

#[cfg(feature = "rstar_0_8")]
impl_rstar_multi_polygon!(rstar_0_8);

#[cfg(feature = "rstar_0_9")]
impl_rstar_multi_polygon!(rstar_0_9);

#[cfg(any(feature = "approx", test))]
impl<T> RelativeEq for MultiPolygon<T>
where
Expand Down
27 changes: 27 additions & 0 deletions geo-types/src/geometry/rect.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::{coord, polygon, Coord, CoordFloat, CoordNum, Line, Polygon};

#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
use crate::Point;
#[cfg(any(feature = "approx", test))]
use approx::{AbsDiffEq, RelativeEq};

Expand Down Expand Up @@ -378,6 +380,31 @@ impl<T: CoordFloat> Rect<T> {

static RECT_INVALID_BOUNDS_ERROR: &str = "Failed to create Rect: 'min' coordinate's x/y value must be smaller or equal to the 'max' x/y value";

#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
macro_rules! impl_rstar_rect {
($rstar:ident) => {
impl<T> $rstar::RTreeObject for Rect<T>
where
T: ::num_traits::Float + ::$rstar::RTreeNum,
{
type Envelope = ::$rstar::AABB<Point<T>>;

fn envelope(&self) -> Self::Envelope {
::$rstar::AABB::from_corners(
Point::new(self.min().x, self.min().y),
Point::new(self.max().x, self.max().y),
)
}
}
};
}

#[cfg(feature = "rstar_0_8")]
impl_rstar_rect!(rstar_0_8);

#[cfg(feature = "rstar_0_9")]
impl_rstar_rect!(rstar_0_9);

#[cfg(any(feature = "approx", test))]
impl<T> RelativeEq for Rect<T>
where
Expand Down
39 changes: 39 additions & 0 deletions geo-types/src/geometry/triangle.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
use crate::{polygon, Coord, CoordNum, Line, Polygon};
#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
use num_traits::Bounded;

#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
use crate::private_utils::get_bounding_rect;
#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
use crate::Point;

#[cfg(any(feature = "approx", test))]
use approx::{AbsDiffEq, RelativeEq};
Expand Down Expand Up @@ -63,6 +70,38 @@ impl<IC: Into<Coord<T>> + Copy, T: CoordNum> From<[IC; 3]> for Triangle<T> {
}
}

#[cfg(any(feature = "rstar_0_8", feature = "rstar_0_9"))]
macro_rules! impl_rstar_triangle {
($rstar:ident) => {
impl<T> $rstar::RTreeObject for Triangle<T>
where
T: ::num_traits::Float + ::$rstar::RTreeNum,
{
type Envelope = ::$rstar::AABB<Point<T>>;

fn envelope(&self) -> Self::Envelope {
let bounding_rect = get_bounding_rect(self.to_array());
match bounding_rect {
None => ::$rstar::AABB::from_corners(
Point::new(Bounded::min_value(), Bounded::min_value()),
Point::new(Bounded::max_value(), Bounded::max_value()),
),
Some(b) => ::$rstar::AABB::from_corners(
Point::new(b.min().x, b.min().y),
Point::new(b.max().x, b.max().y),
),
}
}
}
};
}

#[cfg(feature = "rstar_0_8")]
impl_rstar_triangle!(rstar_0_8);

#[cfg(feature = "rstar_0_9")]
impl_rstar_triangle!(rstar_0_9);

#[cfg(any(feature = "approx", test))]
impl<T> RelativeEq for Triangle<T>
where
Expand Down
18 changes: 18 additions & 0 deletions geo-types/src/private_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,24 @@

use crate::{Coord, CoordFloat, CoordNum, Line, LineString, Point, Rect};

// The Rust standard library has `max` for `Ord`, but not for `PartialOrd`
pub fn partial_max<T: PartialOrd>(a: T, b: T) -> T {
if a > b {
a
} else {
b
}
}

// The Rust standard library has `min` for `Ord`, but not for `PartialOrd`
pub fn partial_min<T: PartialOrd>(a: T, b: T) -> T {
if a < b {
a
} else {
b
}
}

pub fn line_string_bounding_rect<T>(line_string: &LineString<T>) -> Option<Rect<T>>
where
T: CoordNum,
Expand Down

0 comments on commit b0fc46f

Please sign in to comment.