Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 46 additions & 10 deletions geo-generic-alg/src/algorithm/area.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use geo_traits_ext::*;

use crate::{CoordFloat, CoordNum};
use core::borrow::Borrow;

pub(crate) fn twice_signed_ring_area<T: CoordNum, LS: LineStringTraitExt<T = T>>(
linestring: &LS,
Expand Down Expand Up @@ -260,16 +261,6 @@ where
}
}

impl<T, G: GeometryTraitExt<T = T>> AreaTrait<T, GeometryTag> for G
where
T: CoordFloat,
{
crate::geometry_trait_ext_delegate_impl! {
fn signed_area_trait(&self) -> T;
fn unsigned_area_trait(&self) -> T;
}
}

impl<T, GC: GeometryCollectionTraitExt<T = T>> AreaTrait<T, GeometryCollectionTag> for GC
where
T: CoordFloat,
Expand All @@ -287,6 +278,51 @@ where
}
}

impl<T, G: GeometryTraitExt<T = T>> AreaTrait<T, GeometryTag> for G
where
T: CoordFloat,
{
fn signed_area_trait(&self) -> T {
if self.is_collection() {
self.geometries_ext()
.map(|g_inner| g_inner.borrow().signed_area_trait())
.fold(T::zero(), |acc, next| acc + next)
} else {
match self.as_type_ext() {
GeometryTypeExt::Point(g) => g.signed_area_trait(),
GeometryTypeExt::Line(g) => g.signed_area_trait(),
GeometryTypeExt::LineString(g) => g.signed_area_trait(),
GeometryTypeExt::Polygon(g) => g.signed_area_trait(),
GeometryTypeExt::MultiPoint(g) => g.signed_area_trait(),
GeometryTypeExt::MultiLineString(g) => g.signed_area_trait(),
GeometryTypeExt::MultiPolygon(g) => g.signed_area_trait(),
GeometryTypeExt::Rect(g) => g.signed_area_trait(),
GeometryTypeExt::Triangle(g) => g.signed_area_trait(),
}
}
}

fn unsigned_area_trait(&self) -> T {
if self.is_collection() {
self.geometries_ext()
.map(|g_inner| g_inner.borrow().unsigned_area_trait())
.fold(T::zero(), |acc, next| acc + next)
} else {
match self.as_type_ext() {
GeometryTypeExt::Point(g) => g.unsigned_area_trait(),
GeometryTypeExt::Line(g) => g.unsigned_area_trait(),
GeometryTypeExt::LineString(g) => g.unsigned_area_trait(),
GeometryTypeExt::Polygon(g) => g.unsigned_area_trait(),
GeometryTypeExt::MultiPoint(g) => g.unsigned_area_trait(),
GeometryTypeExt::MultiLineString(g) => g.unsigned_area_trait(),
GeometryTypeExt::MultiPolygon(g) => g.unsigned_area_trait(),
GeometryTypeExt::Rect(g) => g.unsigned_area_trait(),
GeometryTypeExt::Triangle(g) => g.unsigned_area_trait(),
}
}
}
}

#[cfg(test)]
mod test {
use crate::Area;
Expand Down
53 changes: 42 additions & 11 deletions geo-generic-alg/src/algorithm/bounding_rect.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::utils::{partial_max, partial_min};
use crate::{coord, geometry::*, CoordNum, GeometryCow};
use core::borrow::Borrow;
use geo_traits_ext::*;
use geo_types::private_utils::get_bounding_rect;

Expand Down Expand Up @@ -199,17 +200,6 @@ where
}
}

impl<T, G: GeometryTraitExt<T = T>> BoundingRectTrait<T, GeometryTag> for G
where
T: CoordNum,
{
type Output = Option<Rect<T>>;

crate::geometry_trait_ext_delegate_impl! {
fn bounding_rect_trait(&self) -> Self::Output;
}
}

impl<T, GC: GeometryCollectionTraitExt<T = T>> BoundingRectTrait<T, GeometryCollectionTag> for GC
where
T: CoordNum,
Expand All @@ -229,6 +219,39 @@ where
}
}

impl<T, G: GeometryTraitExt<T = T>> BoundingRectTrait<T, GeometryTag> for G
where
T: CoordNum,
{
type Output = Option<Rect<T>>;

fn bounding_rect_trait(&self) -> Self::Output {
if self.is_collection() {
self.geometries_ext().fold(None, |acc, next| {
let next_bounding_rect = next.borrow().bounding_rect_trait();

match (acc, next_bounding_rect) {
(None, None) => None,
(Some(r), None) | (None, Some(r)) => Some(r),
(Some(r1), Some(r2)) => Some(bounding_rect_merge(r1, r2)),
}
})
} else {
match self.as_type_ext() {
GeometryTypeExt::Point(g) => g.bounding_rect_trait().into(),
GeometryTypeExt::Line(g) => g.bounding_rect_trait().into(),
GeometryTypeExt::LineString(g) => g.bounding_rect_trait(),
GeometryTypeExt::Polygon(g) => g.bounding_rect_trait(),
GeometryTypeExt::MultiPoint(g) => g.bounding_rect_trait(),
GeometryTypeExt::MultiLineString(g) => g.bounding_rect_trait(),
GeometryTypeExt::MultiPolygon(g) => g.bounding_rect_trait(),
GeometryTypeExt::Rect(g) => g.bounding_rect_trait().into(),
GeometryTypeExt::Triangle(g) => g.bounding_rect_trait().into(),
}
}
}
}

impl<T> BoundingRect<T> for GeometryCow<'_, T>
where
T: CoordNum,
Expand Down Expand Up @@ -379,5 +402,13 @@ mod test {
])
.bounding_rect(),
);
assert_eq!(
Some(Rect::new(coord! { x: 0., y: 0. }, coord! { x: 1., y: 2. })),
Geometry::GeometryCollection(GeometryCollection::new_from(vec![
Geometry::Point(point! { x: 0., y: 0. }),
Geometry::Point(point! { x: 1., y: 2. }),
]))
.bounding_rect(),
);
}
}
103 changes: 64 additions & 39 deletions geo-generic-alg/src/algorithm/centroid.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::borrow::Borrow;
use std::cmp::Ordering;

use geo_traits_ext::*;
Expand Down Expand Up @@ -390,32 +391,51 @@ where
{
type Output = Option<Point<T>>;

crate::geometry_trait_ext_delegate_impl! {
/// The Centroid of a [`Geometry`] is the centroid of its enum variant
///
/// # Examples
///
/// ```
/// use geo::Centroid;
/// use geo::{Geometry, Rect, point};
///
/// let rect = Rect::new(
/// point!(x: 0.0f32, y: 0.0),
/// point!(x: 1.0, y: 1.0),
/// );
/// let geometry = Geometry::from(rect.clone());
///
/// assert_eq!(
/// Some(rect.centroid()),
/// geometry.centroid(),
/// );
///
/// assert_eq!(
/// Some(point!(x: 0.5, y: 0.5)),
/// geometry.centroid(),
/// );
/// ```
fn centroid_trait(&self) -> Self::Output;
/// The Centroid of a [`Geometry`] is the centroid of its enum variant
///
/// # Examples
///
/// ```
/// use geo::Centroid;
/// use geo::{Geometry, Rect, point};
///
/// let rect = Rect::new(
/// point!(x: 0.0f32, y: 0.0),
/// point!(x: 1.0, y: 1.0),
/// );
/// let geometry = Geometry::from(rect.clone());
///
/// assert_eq!(
/// Some(rect.centroid()),
/// geometry.centroid(),
/// );
///
/// assert_eq!(
/// Some(point!(x: 0.5, y: 0.5)),
/// geometry.centroid(),
/// );
/// ```
fn centroid_trait(&self) -> Self::Output {
if self.is_collection() {
// Handle geometry collection by computing weighted centroid
let mut operation = CentroidOperation::new();
for g_inner in self.geometries_ext() {
operation.add_geometry(g_inner.borrow());
}
operation.centroid()
} else {
match self.as_type_ext() {
GeometryTypeExt::Point(g) => Some(g.centroid_trait()),
GeometryTypeExt::Line(g) => Some(g.centroid_trait()),
GeometryTypeExt::LineString(g) => g.centroid_trait(),
GeometryTypeExt::Polygon(g) => g.centroid_trait(),
GeometryTypeExt::MultiPoint(g) => g.centroid_trait(),
GeometryTypeExt::MultiLineString(g) => g.centroid_trait(),
GeometryTypeExt::MultiPolygon(g) => g.centroid_trait(),
GeometryTypeExt::Rect(g) => Some(g.centroid_trait()),
GeometryTypeExt::Triangle(g) => Some(g.centroid_trait()),
}
}
}
}

Expand Down Expand Up @@ -658,21 +678,26 @@ impl<T: GeoFloat> CentroidOperation<T> {
where
G: GeometryTraitExt<T = T>,
{
match geometry.as_type_ext() {
GeometryTypeExt::Point(g) => {
if let Some(coord) = g.geo_coord() {
self.add_coord(coord)
if geometry.is_collection() {
for g_inner in geometry.geometries_ext() {
self.add_geometry(g_inner.borrow());
}
} else {
match geometry.as_type_ext() {
GeometryTypeExt::Point(g) => {
if let Some(coord) = g.geo_coord() {
self.add_coord(coord)
}
}
GeometryTypeExt::Line(g) => self.add_line(g),
GeometryTypeExt::LineString(g) => self.add_line_string(g),
GeometryTypeExt::Polygon(g) => self.add_polygon(g),
GeometryTypeExt::MultiPoint(g) => self.add_multi_point(g),
GeometryTypeExt::MultiLineString(g) => self.add_multi_line_string(g),
GeometryTypeExt::MultiPolygon(g) => self.add_multi_polygon(g),
GeometryTypeExt::Rect(g) => self.add_rect(g),
GeometryTypeExt::Triangle(g) => self.add_triangle(g),
}
GeometryTypeExt::Line(g) => self.add_line(g),
GeometryTypeExt::LineString(g) => self.add_line_string(g),
GeometryTypeExt::Polygon(g) => self.add_polygon(g),
GeometryTypeExt::MultiPoint(g) => self.add_multi_point(g),
GeometryTypeExt::MultiLineString(g) => self.add_multi_line_string(g),
GeometryTypeExt::MultiPolygon(g) => self.add_multi_polygon(g),
GeometryTypeExt::GeometryCollection(g) => self.add_geometry_collection(g),
GeometryTypeExt::Rect(g) => self.add_rect(g),
GeometryTypeExt::Triangle(g) => self.add_triangle(g),
}
}

Expand Down
Loading