1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
use crate::algorithm::geo::utils::zeroes;
use crate::array::{
GeometryArray, LineStringArray, MultiLineStringArray, MultiPointArray, MultiPolygonArray,
PointArray, PolygonArray, WKBArray,
};
use crate::GeometryArrayTrait;
use arrow_array::builder::Float64Builder;
use arrow_array::{Float64Array, OffsetSizeTrait};
use geo::prelude::ChamberlainDuquetteArea as GeoChamberlainDuquetteArea;
/// Calculate the signed approximate geodesic area of a `Geometry`.
///
/// # Units
///
/// - return value: meters²
///
/// # References
///
/// * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for Polygons on a Sphere",
///
/// JPL Publication 07-03, Jet Propulsion Laboratory, Pasadena, CA, June 2007 <https://trs.jpl.nasa.gov/handle/2014/41271>
///
/// # Examples
///
/// ```
/// use geo::{polygon, Polygon};
/// use geoarrow2::array::PolygonArray;
/// use geoarrow2::GeometryArrayTrait;
/// use geoarrow2::algorithm::geo::ChamberlainDuquetteArea;
///
/// // The O2 in London
/// let mut polygon: Polygon<f64> = polygon![
/// (x: 0.00388383, y: 51.501574),
/// (x: 0.00538587, y: 51.502278),
/// (x: 0.00553607, y: 51.503299),
/// (x: 0.00467777, y: 51.504181),
/// (x: 0.00327229, y: 51.504435),
/// (x: 0.00187754, y: 51.504168),
/// (x: 0.00087976, y: 51.503380),
/// (x: 0.00107288, y: 51.502324),
/// (x: 0.00185608, y: 51.501770),
/// (x: 0.00388383, y: 51.501574),
/// ];
/// let mut reversed_polygon = polygon.clone();
/// reversed_polygon.exterior_mut(|line_string| {
/// line_string.0.reverse();
/// });
///
/// let polygon_array: PolygonArray<i32> = vec![polygon].into();
/// let reversed_polygon_array: PolygonArray<i32> = vec![reversed_polygon].into();
///
/// // 78,478 meters²
/// assert_eq!(78_478., polygon_array.chamberlain_duquette_unsigned_area().value(0).round());
/// assert_eq!(78_478., polygon_array.chamberlain_duquette_signed_area().value(0).round());
///
/// assert_eq!(78_478., reversed_polygon_array.chamberlain_duquette_unsigned_area().value(0).round());
/// assert_eq!(-78_478., reversed_polygon_array.chamberlain_duquette_signed_area().value(0).round());
/// ```
pub trait ChamberlainDuquetteArea {
fn chamberlain_duquette_signed_area(&self) -> Float64Array;
fn chamberlain_duquette_unsigned_area(&self) -> Float64Array;
}
// Note: this can't (easily) be parameterized in the macro because PointArray is not generic over O
impl ChamberlainDuquetteArea for PointArray {
fn chamberlain_duquette_signed_area(&self) -> Float64Array {
zeroes(self.len(), self.nulls())
}
fn chamberlain_duquette_unsigned_area(&self) -> Float64Array {
zeroes(self.len(), self.nulls())
}
}
/// Generate a `ChamberlainDuquetteArea` implementation where the result is zero.
macro_rules! zero_impl {
($type:ty) => {
impl<O: OffsetSizeTrait> ChamberlainDuquetteArea for $type {
fn chamberlain_duquette_signed_area(&self) -> Float64Array {
zeroes(self.len(), self.nulls())
}
fn chamberlain_duquette_unsigned_area(&self) -> Float64Array {
zeroes(self.len(), self.nulls())
}
}
};
}
zero_impl!(LineStringArray<O>);
zero_impl!(MultiPointArray<O>);
zero_impl!(MultiLineStringArray<O>);
/// Implementation that iterates over geo objects
macro_rules! iter_geo_impl {
($type:ty) => {
impl<O: OffsetSizeTrait> ChamberlainDuquetteArea for $type {
fn chamberlain_duquette_signed_area(&self) -> Float64Array {
let mut output_array = Float64Builder::with_capacity(self.len());
self.iter_geo().for_each(|maybe_g| {
output_array
.append_option(maybe_g.map(|g| g.chamberlain_duquette_signed_area()))
});
output_array.finish()
}
fn chamberlain_duquette_unsigned_area(&self) -> Float64Array {
let mut output_array = Float64Builder::with_capacity(self.len());
self.iter_geo().for_each(|maybe_g| {
output_array
.append_option(maybe_g.map(|g| g.chamberlain_duquette_unsigned_area()))
});
output_array.finish()
}
}
};
}
iter_geo_impl!(PolygonArray<O>);
iter_geo_impl!(MultiPolygonArray<O>);
iter_geo_impl!(WKBArray<O>);
impl<O: OffsetSizeTrait> ChamberlainDuquetteArea for GeometryArray<O> {
crate::geometry_array_delegate_impl! {
fn chamberlain_duquette_signed_area(&self) -> Float64Array;
fn chamberlain_duquette_unsigned_area(&self) -> Float64Array;
}
}