Skip to content

Commit

Permalink
Add more area functions (#7)
Browse files Browse the repository at this point in the history
* Add more area functions

* fmt
  • Loading branch information
kylebarron authored Jul 1, 2023
1 parent 1d80ac4 commit afc83d2
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 0 deletions.
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;

0 comments on commit afc83d2

Please sign in to comment.