Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more area functions #7

Merged
merged 2 commits into from
Jul 1, 2023
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
2 changes: 2 additions & 0 deletions src/algorithm/geo/area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::{GeometryArray, GeometryArrayTrait};
use arrow2::array::{MutablePrimitiveArray, PrimitiveArray};
use geo::prelude::Area;

/// Unsigned planar area of the input geometries
pub fn area(array: GeometryArray) -> Result<PrimitiveArray<f64>> {
let mut output_array = MutablePrimitiveArray::<f64>::with_capacity(array.len());

Expand Down Expand Up @@ -40,6 +41,7 @@ pub fn area(array: GeometryArray) -> Result<PrimitiveArray<f64>> {
Ok(output_array.into())
}

/// Signed planar area of the input geometries
pub fn signed_area(array: GeometryArray) -> Result<PrimitiveArray<f64>> {
let mut output_array = MutablePrimitiveArray::<f64>::with_capacity(array.len());

Expand Down
96 changes: 96 additions & 0 deletions src/algorithm/geo/chamberlain_duquette_area.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use crate::error::Result;
use crate::{GeometryArray, GeometryArrayTrait};
use arrow2::array::{MutablePrimitiveArray, PrimitiveArray};
use geo::prelude::ChamberlainDuquetteArea;

/// Calculate the unsigned approximate geodesic area of geometries on a sphere using the algorithm
/// presented in Some Algorithms for Polygons on a Sphere by Chamberlain and Duquette (2007)
pub fn chamberlain_duquette_unsigned_area(array: GeometryArray) -> Result<PrimitiveArray<f64>> {
let mut output_array = MutablePrimitiveArray::<f64>::with_capacity(array.len());

match array {
GeometryArray::WKB(arr) => {
arr.iter_geo().for_each(|maybe_g| {
output_array.push(maybe_g.map(|g| g.chamberlain_duquette_unsigned_area()))
});
}
GeometryArray::Point(arr) => {
arr.iter_geo().for_each(|maybe_g| {
output_array.push(maybe_g.map(|g| g.chamberlain_duquette_unsigned_area()))
});
}
GeometryArray::LineString(arr) => {
arr.iter_geo().for_each(|maybe_g| {
output_array.push(maybe_g.map(|g| g.chamberlain_duquette_unsigned_area()))
});
}
GeometryArray::Polygon(arr) => {
arr.iter_geo().for_each(|maybe_g| {
output_array.push(maybe_g.map(|g| g.chamberlain_duquette_unsigned_area()))
});
}
GeometryArray::MultiPoint(arr) => {
arr.iter_geo().for_each(|maybe_g| {
output_array.push(maybe_g.map(|g| g.chamberlain_duquette_unsigned_area()))
});
}
GeometryArray::MultiLineString(arr) => {
arr.iter_geo().for_each(|maybe_g| {
output_array.push(maybe_g.map(|g| g.chamberlain_duquette_unsigned_area()))
});
}
GeometryArray::MultiPolygon(arr) => {
arr.iter_geo().for_each(|maybe_g| {
output_array.push(maybe_g.map(|g| g.chamberlain_duquette_unsigned_area()))
});
}
}

Ok(output_array.into())
}

/// Calculate the signed approximate geodesic area of geometries on a sphere using the algorithm
/// presented in Some Algorithms for Polygons on a Sphere by Chamberlain and Duquette (2007)
pub fn chamberlain_duquette_signed_area(array: GeometryArray) -> Result<PrimitiveArray<f64>> {
let mut output_array = MutablePrimitiveArray::<f64>::with_capacity(array.len());

match array {
GeometryArray::WKB(arr) => {
arr.iter_geo().for_each(|maybe_g| {
output_array.push(maybe_g.map(|g| g.chamberlain_duquette_signed_area()))
});
}
GeometryArray::Point(arr) => {
arr.iter_geo().for_each(|maybe_g| {
output_array.push(maybe_g.map(|g| g.chamberlain_duquette_signed_area()))
});
}
GeometryArray::LineString(arr) => {
arr.iter_geo().for_each(|maybe_g| {
output_array.push(maybe_g.map(|g| g.chamberlain_duquette_signed_area()))
});
}
GeometryArray::Polygon(arr) => {
arr.iter_geo().for_each(|maybe_g| {
output_array.push(maybe_g.map(|g| g.chamberlain_duquette_signed_area()))
});
}
GeometryArray::MultiPoint(arr) => {
arr.iter_geo().for_each(|maybe_g| {
output_array.push(maybe_g.map(|g| g.chamberlain_duquette_signed_area()))
});
}
GeometryArray::MultiLineString(arr) => {
arr.iter_geo().for_each(|maybe_g| {
output_array.push(maybe_g.map(|g| g.chamberlain_duquette_signed_area()))
});
}
GeometryArray::MultiPolygon(arr) => {
arr.iter_geo().for_each(|maybe_g| {
output_array.push(maybe_g.map(|g| g.chamberlain_duquette_signed_area()))
});
}
}

Ok(output_array.into())
}
122 changes: 122 additions & 0 deletions src/algorithm/geo/geodesic_area.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use crate::error::Result;
use crate::{GeometryArray, GeometryArrayTrait};
use arrow2::array::{MutablePrimitiveArray, PrimitiveArray};
use geo::prelude::GeodesicArea;

/// Calculate the unsigned geodesic area of a geometry on an ellipsoid using the algorithm
/// presented in Algorithms for geodesics by Charles Karney (2013)
pub fn geodesic_area_unsigned(array: GeometryArray) -> Result<PrimitiveArray<f64>> {
let mut output_array = MutablePrimitiveArray::<f64>::with_capacity(array.len());

match array {
GeometryArray::WKB(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_area_unsigned())));
}
GeometryArray::Point(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_area_unsigned())));
}
GeometryArray::LineString(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_area_unsigned())));
}
GeometryArray::Polygon(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_area_unsigned())));
}
GeometryArray::MultiPoint(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_area_unsigned())));
}
GeometryArray::MultiLineString(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_area_unsigned())));
}
GeometryArray::MultiPolygon(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_area_unsigned())));
}
}

Ok(output_array.into())
}

/// Calculate the signed geodesic area of a geometry on an ellipsoid using the algorithm
/// presented in Algorithms for geodesics by Charles Karney (2013)
pub fn geodesic_area_signed(array: GeometryArray) -> Result<PrimitiveArray<f64>> {
let mut output_array = MutablePrimitiveArray::<f64>::with_capacity(array.len());

match array {
GeometryArray::WKB(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_area_signed())));
}
GeometryArray::Point(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_area_signed())));
}
GeometryArray::LineString(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_area_signed())));
}
GeometryArray::Polygon(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_area_signed())));
}
GeometryArray::MultiPoint(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_area_signed())));
}
GeometryArray::MultiLineString(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_area_signed())));
}
GeometryArray::MultiPolygon(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_area_signed())));
}
}

Ok(output_array.into())
}

/// Determine the perimeter of a geometry on an ellipsoidal model of the earth.
///
/// This uses the geodesic measurement methods given by Karney (2013).
pub fn geodesic_perimeter(array: GeometryArray) -> Result<PrimitiveArray<f64>> {
let mut output_array = MutablePrimitiveArray::<f64>::with_capacity(array.len());

match array {
GeometryArray::WKB(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_perimeter())));
}
GeometryArray::Point(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_perimeter())));
}
GeometryArray::LineString(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_perimeter())));
}
GeometryArray::Polygon(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_perimeter())));
}
GeometryArray::MultiPoint(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_perimeter())));
}
GeometryArray::MultiLineString(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_perimeter())));
}
GeometryArray::MultiPolygon(arr) => {
arr.iter_geo()
.for_each(|maybe_g| output_array.push(maybe_g.map(|g| g.geodesic_perimeter())));
}
}

Ok(output_array.into())
}
6 changes: 6 additions & 0 deletions src/algorithm/geo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,23 @@

mod area;
mod centroid;
mod chamberlain_duquette_area;
mod convex_hull;
mod envelope;
mod geodesic_area;
mod is_empty;
mod length;
mod simplify;

pub use area::area;
pub use area::signed_area;
pub use centroid::centroid;
pub use chamberlain_duquette_area::{
chamberlain_duquette_signed_area, chamberlain_duquette_unsigned_area,
};
pub use convex_hull::convex_hull;
pub use envelope::envelope;
pub use geodesic_area::{geodesic_area_signed, geodesic_area_unsigned, geodesic_perimeter};
pub use is_empty::is_empty;
pub use length::{euclidean_length, geodesic_length, haversine_length, vincenty_length};
pub use simplify::simplify;