Skip to content

Commit

Permalink
Merge 8bf248e into e46bdfe
Browse files Browse the repository at this point in the history
  • Loading branch information
frewsxcv committed Mar 3, 2020
2 parents e46bdfe + 8bf248e commit cb051be
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 54 deletions.
109 changes: 108 additions & 1 deletion geo-types/src/geometry.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::{
CoordinateType, GeometryCollection, Line, LineString, MultiLineString, MultiPoint,
MultiPolygon, Point, Polygon,
MultiPolygon, Point, Polygon, Rect, Triangle,
};
use num_traits::Float;
use std::borrow::Cow;
use std::convert::TryFrom;
use std::error::Error;
use std::fmt;
Expand Down Expand Up @@ -36,6 +37,8 @@ where
MultiLineString(MultiLineString<T>),
MultiPolygon(MultiPolygon<T>),
GeometryCollection(GeometryCollection<T>),
Rect(Rect<T>),
Triangle(Triangle<T>),
}

impl<T: CoordinateType> From<Point<T>> for Geometry<T> {
Expand Down Expand Up @@ -73,6 +76,110 @@ impl<T: CoordinateType> From<MultiPolygon<T>> for Geometry<T> {
Geometry::MultiPolygon(x)
}
}
impl<T: CoordinateType> From<Rect<T>> for Geometry<T> {
fn from(x: Rect<T>) -> Geometry<T> {
Geometry::Rect(x)
}
}
impl<T: CoordinateType> From<Triangle<T>> for Geometry<T> {
fn from(x: Triangle<T>) -> Geometry<T> {
Geometry::Triangle(x)
}
}

#[derive(PartialEq, Debug, Hash)]
pub enum GeometryCow<'a, T>
where
T: CoordinateType,
{
Point(Cow<'a, Point<T>>),
Line(Cow<'a, Line<T>>),
LineString(Cow<'a, LineString<T>>),
Polygon(Cow<'a, Polygon<T>>),
MultiPoint(Cow<'a, MultiPoint<T>>),
MultiLineString(Cow<'a, MultiLineString<T>>),
MultiPolygon(Cow<'a, MultiPolygon<T>>),
GeometryCollection(Cow<'a, GeometryCollection<T>>),
Rect(Cow<'a, Rect<T>>),
Triangle(Cow<'a, Triangle<T>>),
}

impl<'a, T: CoordinateType> From<&'a Geometry<T>> for GeometryCow<'a, T> {
fn from(geometry: &'a Geometry<T>) -> Self {
match geometry {
Geometry::Point(g) => GeometryCow::Point(Cow::Borrowed(g)),
Geometry::Line(g) => GeometryCow::Line(Cow::Borrowed(g)),
Geometry::LineString(g) => GeometryCow::LineString(Cow::Borrowed(g)),
Geometry::Polygon(g) => GeometryCow::Polygon(Cow::Borrowed(g)),
Geometry::MultiPoint(g) => GeometryCow::MultiPoint(Cow::Borrowed(g)),
Geometry::MultiLineString(g) => GeometryCow::MultiLineString(Cow::Borrowed(g)),
Geometry::MultiPolygon(g) => GeometryCow::MultiPolygon(Cow::Borrowed(g)),
Geometry::GeometryCollection(g) => GeometryCow::GeometryCollection(Cow::Borrowed(g)),
Geometry::Rect(g) => GeometryCow::Rect(Cow::Borrowed(g)),
Geometry::Triangle(g) => GeometryCow::Triangle(Cow::Borrowed(g)),
}
}
}

impl<'a, T: CoordinateType> From<&'a Point<T>> for GeometryCow<'a, T> {
fn from(point: &'a Point<T>) -> Self {
GeometryCow::Point(Cow::Borrowed(point))
}
}

impl<'a, T: CoordinateType> From<&'a LineString<T>> for GeometryCow<'a, T> {
fn from(line_string: &'a LineString<T>) -> Self {
GeometryCow::LineString(Cow::Borrowed(line_string))
}
}

impl<'a, T: CoordinateType> From<&'a Line<T>> for GeometryCow<'a, T> {
fn from(line: &'a Line<T>) -> Self {
GeometryCow::Line(Cow::Borrowed(line))
}
}

impl<'a, T: CoordinateType> From<&'a Polygon<T>> for GeometryCow<'a, T> {
fn from(polygon: &'a Polygon<T>) -> Self {
GeometryCow::Polygon(Cow::Borrowed(polygon))
}
}

impl<'a, T: CoordinateType> From<&'a MultiPoint<T>> for GeometryCow<'a, T> {
fn from(multi_point: &'a MultiPoint<T>) -> GeometryCow<'a, T> {
GeometryCow::MultiPoint(Cow::Borrowed(multi_point))
}
}

impl<'a, T: CoordinateType> From<&'a MultiLineString<T>> for GeometryCow<'a, T> {
fn from(multi_line_string: &'a MultiLineString<T>) -> Self {
GeometryCow::MultiLineString(Cow::Borrowed(multi_line_string))
}
}

impl<'a, T: CoordinateType> From<&'a MultiPolygon<T>> for GeometryCow<'a, T> {
fn from(multi_polygon: &'a MultiPolygon<T>) -> Self {
GeometryCow::MultiPolygon(Cow::Borrowed(multi_polygon))
}
}

impl<'a, T: CoordinateType> From<&'a GeometryCollection<T>> for GeometryCow<'a, T> {
fn from(geometry_collection: &'a GeometryCollection<T>) -> Self {
GeometryCow::GeometryCollection(Cow::Borrowed(geometry_collection))
}
}

impl<'a, T: CoordinateType> From<&'a Rect<T>> for GeometryCow<'a, T> {
fn from(rect: &'a Rect<T>) -> Self {
GeometryCow::Rect(Cow::Borrowed(rect))
}
}

impl<'a, T: CoordinateType> From<&'a Triangle<T>> for GeometryCow<'a, T> {
fn from(triangle: &'a Triangle<T>) -> Self {
GeometryCow::Triangle(Cow::Borrowed(triangle))
}
}

impl<T: CoordinateType> Geometry<T> {
/// If this Geometry is a Point, then return that, else None.
Expand Down
2 changes: 1 addition & 1 deletion geo-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ mod multi_polygon;
pub use crate::multi_polygon::MultiPolygon;

mod geometry;
pub use crate::geometry::Geometry;
pub use crate::geometry::{Geometry, GeometryCow};

mod geometry_collection;
pub use crate::geometry_collection::GeometryCollection;
Expand Down
12 changes: 11 additions & 1 deletion geo-types/src/rect.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{Coordinate, CoordinateType};
use crate::{polygon, Coordinate, CoordinateType, Polygon};

/// A bounded 2D quadrilateral whose area is defined by minimum and maximum `Coordinates`.
#[derive(PartialEq, Clone, Copy, Debug, Hash)]
Expand Down Expand Up @@ -73,6 +73,16 @@ impl<T: CoordinateType> Rect<T> {
self.max().y - self.min().y
}

pub fn to_polygon(self) -> Polygon<T> {
polygon![
(x: self.min.x, y: self.min.y),
(x: self.min.x, y: self.max.y),
(x: self.max.x, y: self.max.y),
(x: self.max.x, y: self.min.y),
(x: self.min.x, y: self.min.y),
]
}

fn assert_valid_bounds(min: Coordinate<T>, max: Coordinate<T>) {
assert!(
min.x <= max.x && min.y <= max.y,
Expand Down
8 changes: 6 additions & 2 deletions geo-types/src/triangle.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{Coordinate, CoordinateType, Line};
use crate::{polygon, Coordinate, CoordinateType, Line, Polygon};

/// A bounded 2D area whose three vertices are defined by `Coordinate`s.
#[derive(Copy, Clone, Debug, Hash)]
#[derive(Copy, Clone, Debug, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Triangle<T: CoordinateType>(pub Coordinate<T>, pub Coordinate<T>, pub Coordinate<T>);

Expand All @@ -17,6 +17,10 @@ impl<T: CoordinateType> Triangle<T> {
Line::new(self.2, self.0),
]
}

pub fn to_polygon(self) -> Polygon<T> {
polygon![self.0, self.1, self.2, self.0]
}
}

impl<IC: Into<Coordinate<T>> + Copy, T: CoordinateType> From<[IC; 3]> for Triangle<T> {
Expand Down
96 changes: 50 additions & 46 deletions geo/src/algorithm/area.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::{CoordinateType, Line, LineString, MultiPolygon, Polygon, Rect, Triangle};
use num_traits::Float;
use crate::{
CoordinateType, GeometryCollection, GeometryCow, LineString, MultiPolygon, Polygon, Rect,
Triangle,
};

use crate::algorithm::winding_order::twice_signed_ring_area;

Expand Down Expand Up @@ -27,72 +29,74 @@ use crate::algorithm::winding_order::twice_signed_ring_area;
///
/// assert_eq!(polygon.area(), -30.);
/// ```
pub trait Area<T>
pub trait Area<'a, T>
where
T: CoordinateType,
{
fn area(&self) -> T;
fn area(&'a self) -> T;
}

// Calculation of simple (no interior holes) Polygon area
pub(crate) fn get_linestring_area<T>(linestring: &LineString<T>) -> T
where
T: Float,
T: CoordinateType,
{
twice_signed_ring_area(linestring) / (T::one() + T::one())
}

impl<T> Area<T> for Line<T>
where
T: CoordinateType,
{
fn area(&self) -> T {
T::zero()
}
fn area_polygon<T: CoordinateType>(polygon: &Polygon<T>) -> T {
polygon
.interiors()
.iter()
.fold(get_linestring_area(polygon.exterior()), |total, next| {
total - get_linestring_area(next)
})
}

impl<T> Area<T> for Polygon<T>
where
T: Float,
{
fn area(&self) -> T {
self.interiors()
.iter()
.fold(get_linestring_area(self.exterior()), |total, next| {
total - get_linestring_area(next)
})
}
fn area_multi_polygon<T: CoordinateType>(multi_polygon: &MultiPolygon<T>) -> T {
multi_polygon
.0
.iter()
.fold(T::zero(), |total, next| total + next.area())
}

impl<T> Area<T> for MultiPolygon<T>
where
T: Float,
{
fn area(&self) -> T {
self.0
.iter()
.fold(T::zero(), |total, next| total + next.area())
}
fn area_geometry_collection<T: CoordinateType>(geometry_collection: &GeometryCollection<T>) -> T {
geometry_collection
.iter()
.fold(T::zero(), |total, geometry| total + geometry.area())
}

impl<T> Area<T> for Rect<T>
where
T: CoordinateType,
{
fn area(&self) -> T {
self.width() * self.height()
}
fn area_rect<T: CoordinateType>(rect: &Rect<T>) -> T {
rect.width() * rect.height()
}

fn area_triangle<T: CoordinateType>(triangle: &Triangle<T>) -> T {
triangle
.to_lines()
.iter()
.fold(T::zero(), |total, line| total + line.determinant())
/ (T::one() + T::one())
}

impl<T> Area<T> for Triangle<T>
impl<'a, I: 'a, T: 'a> Area<'a, T> for I
where
T: Float,
&'a I: Into<GeometryCow<'a, T>>,
T: CoordinateType,
{
fn area(&self) -> T {
self.to_lines()
.iter()
.fold(T::zero(), |total, line| total + line.determinant())
/ (T::one() + T::one())
fn area(&'a self) -> T {
let geometry_cow: GeometryCow<'a, T> = self.into();
match geometry_cow {
GeometryCow::Point(_) => T::zero(),
GeometryCow::Line(_) => T::zero(),
GeometryCow::LineString(_) => T::zero(),
GeometryCow::Polygon(g) => area_polygon(&*g),
GeometryCow::MultiPoint(_) => T::zero(),
GeometryCow::MultiLineString(_) => T::zero(),
GeometryCow::MultiPolygon(g) => area_multi_polygon(&*g),
GeometryCow::GeometryCollection(g) => area_geometry_collection(&*g),
GeometryCow::Rect(g) => area_rect(&*g),
GeometryCow::Triangle(g) => area_triangle(&*g),
}
}
}

Expand Down

0 comments on commit cb051be

Please sign in to comment.