Skip to content

Commit

Permalink
move geodesic area to trait (#56)
Browse files Browse the repository at this point in the history
* Move to_ffi to ffi module

* Move geodesic area to trait
  • Loading branch information
kylebarron authored Jul 12, 2023
1 parent abd1774 commit 50af49c
Show file tree
Hide file tree
Showing 18 changed files with 461 additions and 160 deletions.
142 changes: 142 additions & 0 deletions js/src/algorithm/geo/geodesic_area.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
use crate::array::*;
use wasm_bindgen::prelude::*;

macro_rules! impl_geodesic_area {
($struct_name:ident) => {
#[wasm_bindgen]
impl $struct_name {
/// Determine the area of a geometry on an ellipsoidal model of the earth.
///
/// This uses the geodesic measurement methods given by [Karney (2013)].
///
/// # Assumptions
/// - Polygons are assumed to be wound in a counter-clockwise direction
/// for the exterior ring and a clockwise direction for interior rings.
/// This is the standard winding for geometries that follow the Simple Feature standard.
/// Alternative windings may result in a negative area. See "Interpreting negative area values" below.
/// - Polygons are assumed to be smaller than half the size of the earth. If you expect to be dealing
/// with polygons larger than this, please use the `unsigned` methods.
///
/// # Units
///
/// - return value: meter²
///
/// # Interpreting negative area values
///
/// A negative value can mean one of two things:
/// 1. The winding of the polygon is in the clockwise direction (reverse winding). If this is the case, and you know the polygon is smaller than half the area of earth, you can take the absolute value of the reported area to get the correct area.
/// 2. The polygon is larger than half the planet. In this case, the returned area of the polygon is not correct. If you expect to be dealing with very large polygons, please use the `unsigned` methods.
///
/// [Karney (2013)]: https://arxiv.org/pdf/1109.4448.pdf
#[wasm_bindgen]
pub fn geodesic_area_signed(&self) -> FloatArray {
use geoarrow::algorithm::geo::GeodesicArea;
FloatArray(GeodesicArea::geodesic_area_signed(&self.0))
}

/// Determine the area of a geometry on an ellipsoidal model of the earth. Supports very large geometries that cover a significant portion of the earth.
///
/// This uses the geodesic measurement methods given by [Karney (2013)].
///
/// # Assumptions
/// - Polygons are assumed to be wound in a counter-clockwise direction
/// for the exterior ring and a clockwise direction for interior rings.
/// This is the standard winding for geometries that follow the Simple Features standard.
/// Using alternative windings will result in incorrect results.
///
/// # Units
///
/// - return value: meter²
///
/// [Karney (2013)]: https://arxiv.org/pdf/1109.4448.pdf
#[wasm_bindgen]
pub fn geodesic_area_unsigned(&self) -> FloatArray {
use geoarrow::algorithm::geo::GeodesicArea;
FloatArray(GeodesicArea::geodesic_area_unsigned(&self.0))
}

/// Determine the perimeter of a geometry on an ellipsoidal model of the earth.
///
/// This uses the geodesic measurement methods given by [Karney (2013)].
///
/// For a polygon this returns the sum of the perimeter of the exterior ring and interior rings.
/// To get the perimeter of just the exterior ring of a polygon, do `polygon.exterior().geodesic_length()`.
///
/// # Units
///
/// - return value: meter
///
/// [Karney (2013)]: https://arxiv.org/pdf/1109.4448.pdf
#[wasm_bindgen]
pub fn geodesic_perimeter(&self) -> FloatArray {
use geoarrow::algorithm::geo::GeodesicArea;
FloatArray(GeodesicArea::geodesic_perimeter(&self.0))
}

// TODO: pass tuple of arrays across wasm boundary

// /// Determine the perimeter and area of a geometry on an ellipsoidal model of the earth, all in one operation.
// ///
// /// This returns the perimeter and area in a `(perimeter, area)` tuple and uses the geodesic measurement methods given by [Karney (2013)].
// ///
// /// # Area Assumptions
// /// - Polygons are assumed to be wound in a counter-clockwise direction
// /// for the exterior ring and a clockwise direction for interior rings.
// /// This is the standard winding for Geometries that follow the Simple Features standard.
// /// Alternative windings may result in a negative area. See "Interpreting negative area values" below.
// /// - Polygons are assumed to be smaller than half the size of the earth. If you expect to be dealing
// /// with polygons larger than this, please use the 'unsigned' methods.
// ///
// /// # Perimeter
// /// For a polygon this returns the sum of the perimeter of the exterior ring and interior rings.
// /// To get the perimeter of just the exterior ring of a polygon, do `polygon.exterior().geodesic_length()`.
// ///
// /// # Units
// ///
// /// - return value: (meter, meter²)
// ///
// /// # Interpreting negative area values
// ///
// /// A negative area value can mean one of two things:
// /// 1. The winding of the polygon is in the clockwise direction (reverse winding). If this is the case, and you know the polygon is smaller than half the area of earth, you can take the absolute value of the reported area to get the correct area.
// /// 2. The polygon is larger than half the planet. In this case, the returned area of the polygon is not correct. If you expect to be dealing with very large polygons, please use the 'unsigned' methods.
// ///
// /// [Karney (2013)]: https://arxiv.org/pdf/1109.4448.pdf
// #[wasm_bindgen]
// pub fn geodesic_perimeter_area_signed(&self) -> (FloatArray, FloatArray) {
// use geoarrow::algorithm::geo::GeodesicArea;
// let (perimeter, area) = GeodesicArea::geodesic_perimeter_area_signed(&self.0);
// (FloatArray(perimeter), FloatArray(area))
// }

// /// Determine the perimeter and area of a geometry on an ellipsoidal model of the earth, all in one operation. Supports very large geometries that cover a significant portion of the earth.
// ///
// /// This returns the perimeter and area in a `(perimeter, area)` tuple and uses the geodesic measurement methods given by [Karney (2013)].
// ///
// /// # Area Assumptions
// /// - Polygons are assumed to be wound in a counter-clockwise direction
// /// for the exterior ring and a clockwise direction for interior rings.
// /// This is the standard winding for Geometries that follow the Simple Features standard.
// /// Using alternative windings will result in incorrect results.
// ///
// /// # Perimeter
// /// For a polygon this returns the perimeter of the exterior ring and interior rings.
// /// To get the perimeter of just the exterior ring of a polygon, do `polygon.exterior().geodesic_length()`.
// ///
// /// # Units
// ///
// /// - return value: (meter, meter²)
// ///
// /// [Karney (2013)]: https://arxiv.org/pdf/1109.4448.pdf
// fn geodesic_perimeter_area_unsigned(&self) -> (FloatArray, FloatArray);
}
};
}

impl_geodesic_area!(PointArray);
impl_geodesic_area!(LineStringArray);
impl_geodesic_area!(PolygonArray);
impl_geodesic_area!(MultiPointArray);
impl_geodesic_area!(MultiLineStringArray);
impl_geodesic_area!(MultiPolygonArray);
impl_geodesic_area!(GeometryArray);
1 change: 1 addition & 0 deletions js/src/algorithm/geo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod chamberlain_duquette_area;
pub mod convex_hull;
pub mod dimensions;
pub mod euclidean_length;
pub mod geodesic_area;
pub mod geodesic_length;
pub mod haversine_length;
pub mod vincenty_length;
4 changes: 0 additions & 4 deletions js/src/array/geometry.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::array::ffi::FFIArrowArray;
use crate::array::polygon::PolygonArray;
use crate::array::primitive::FloatArray;
use crate::array::{
LineStringArray, MultiLineStringArray, MultiPointArray, MultiPolygonArray, PointArray,
};
Expand All @@ -11,8 +9,6 @@ use crate::log;
#[cfg(feature = "geodesy")]
use crate::reproject::ReprojectDirection;
use crate::TransformOrigin;
use arrow2::datatypes::Field;
use geoarrow::GeometryArrayTrait;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
Expand Down
4 changes: 0 additions & 4 deletions js/src/array/linestring.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::array::ffi::FFIArrowArray;
use crate::array::primitive::BooleanArray;
use crate::array::primitive::FloatArray;
use crate::array::CoordBuffer;
use crate::array::GeometryArray;
use crate::broadcasting::{BroadcastableAffine, BroadcastableFloat};
Expand All @@ -11,8 +9,6 @@ use crate::log;
use crate::reproject::ReprojectDirection;
use crate::utils::vec_to_offsets;
use crate::TransformOrigin;
use arrow2::datatypes::Field;
use geoarrow::GeometryArrayTrait;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
Expand Down
19 changes: 0 additions & 19 deletions js/src/array/macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,6 @@ macro_rules! impl_geometry_array {
Ok(GeometryArray(affine_transform(&self.into(), transform.0)?))
}

#[wasm_bindgen]
pub fn geodesic_area(&self) -> WasmResult<FloatArray> {
use geoarrow::algorithm::geo::geodesic_area_unsigned;
Ok(FloatArray(geodesic_area_unsigned(&self.into())?))
}

#[wasm_bindgen]
pub fn geodesic_area_signed(&self) -> WasmResult<FloatArray> {
use geoarrow::algorithm::geo::geodesic_area_signed;
Ok(FloatArray(geodesic_area_signed(&self.into())?))
}

#[cfg(feature = "geodesy")]
#[wasm_bindgen]
pub fn reproject_rs(
Expand Down Expand Up @@ -83,13 +71,6 @@ macro_rules! impl_geometry_array {
)?))
}

#[wasm_bindgen]
pub fn to_ffi(&self) -> FFIArrowArray {
let arrow_array = self.0.clone().into_boxed_arrow();
let field = Field::new("", arrow_array.data_type().clone(), true);
FFIArrowArray::new(&field, arrow_array)
}

#[wasm_bindgen]
pub fn translate(
&self,
Expand Down
1 change: 0 additions & 1 deletion js/src/array/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
pub mod coord;
pub mod ffi;
pub mod geometry;
pub mod linestring;
pub mod r#macro;
Expand Down
4 changes: 0 additions & 4 deletions js/src/array/multilinestring.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::array::ffi::FFIArrowArray;
use crate::array::primitive::BooleanArray;
use crate::array::primitive::FloatArray;
use crate::array::CoordBuffer;
use crate::array::GeometryArray;
use crate::broadcasting::{BroadcastableAffine, BroadcastableFloat};
Expand All @@ -11,8 +9,6 @@ use crate::log;
use crate::reproject::ReprojectDirection;
use crate::utils::vec_to_offsets;
use crate::TransformOrigin;
use arrow2::datatypes::Field;
use geoarrow::GeometryArrayTrait;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
Expand Down
4 changes: 0 additions & 4 deletions js/src/array/multipoint.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::array::ffi::FFIArrowArray;
use crate::array::primitive::BooleanArray;
use crate::array::primitive::FloatArray;
use crate::array::CoordBuffer;
use crate::array::GeometryArray;
use crate::broadcasting::{BroadcastableAffine, BroadcastableFloat};
Expand All @@ -11,8 +9,6 @@ use crate::log;
use crate::reproject::ReprojectDirection;
use crate::utils::vec_to_offsets;
use crate::TransformOrigin;
use arrow2::datatypes::Field;
use geoarrow::GeometryArrayTrait;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
Expand Down
4 changes: 0 additions & 4 deletions js/src/array/multipolygon.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::array::ffi::FFIArrowArray;
use crate::array::primitive::BooleanArray;
use crate::array::primitive::FloatArray;
use crate::array::CoordBuffer;
use crate::array::GeometryArray;
use crate::broadcasting::{BroadcastableAffine, BroadcastableFloat};
Expand All @@ -11,8 +9,6 @@ use crate::log;
use crate::reproject::ReprojectDirection;
use crate::utils::vec_to_offsets;
use crate::TransformOrigin;
use arrow2::datatypes::Field;
use geoarrow::GeometryArrayTrait;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
Expand Down
4 changes: 0 additions & 4 deletions js/src/array/point.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::array::ffi::FFIArrowArray;
use crate::array::primitive::BooleanArray;
use crate::array::primitive::FloatArray;
use crate::array::CoordBuffer;
use crate::array::GeometryArray;
use crate::broadcasting::{BroadcastableAffine, BroadcastableFloat};
Expand All @@ -10,8 +8,6 @@ use crate::log;
#[cfg(feature = "geodesy")]
use crate::reproject::ReprojectDirection;
use crate::TransformOrigin;
use arrow2::datatypes::Field;
use geoarrow::GeometryArrayTrait;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
Expand Down
4 changes: 0 additions & 4 deletions js/src/array/polygon.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::array::ffi::FFIArrowArray;
use crate::array::primitive::BooleanArray;
use crate::array::primitive::FloatArray;
use crate::array::CoordBuffer;
use crate::array::GeometryArray;
use crate::broadcasting::{BroadcastableAffine, BroadcastableFloat};
Expand All @@ -11,8 +9,6 @@ use crate::log;
use crate::reproject::ReprojectDirection;
use crate::utils::vec_to_offsets;
use crate::TransformOrigin;
use arrow2::datatypes::Field;
use geoarrow::GeometryArrayTrait;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
Expand Down
2 changes: 1 addition & 1 deletion js/src/array/primitive.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::array::ffi::FFIArrowArray;
use crate::ffi::FFIArrowArray;
use arrow2::datatypes::Field;
use wasm_bindgen::prelude::*;

Expand Down
File renamed without changes.
4 changes: 4 additions & 0 deletions js/src/ffi/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod array;
pub mod to_ffi;

pub use array::FFIArrowArray;
27 changes: 27 additions & 0 deletions js/src/ffi/to_ffi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use crate::array::*;
use crate::ffi::FFIArrowArray;
use arrow2::datatypes::Field;
use geoarrow::GeometryArrayTrait;
use wasm_bindgen::prelude::*;

macro_rules! impl_to_ffi {
($struct_name:ident) => {
#[wasm_bindgen]
impl $struct_name {
#[wasm_bindgen]
pub fn to_ffi(&self) -> FFIArrowArray {
let arrow_array = self.0.clone().into_boxed_arrow();
let field = Field::new("", arrow_array.data_type().clone(), true);
FFIArrowArray::new(&field, arrow_array)
}
}
};
}

impl_to_ffi!(PointArray);
impl_to_ffi!(LineStringArray);
impl_to_ffi!(PolygonArray);
impl_to_ffi!(MultiPointArray);
impl_to_ffi!(MultiLineStringArray);
impl_to_ffi!(MultiPolygonArray);
impl_to_ffi!(GeometryArray);
1 change: 1 addition & 0 deletions js/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod algorithm;
pub mod array;
pub mod broadcasting;
pub mod error;
pub mod ffi;
#[cfg(feature = "geodesy")]
pub mod reproject;
pub mod transform_origin;
Expand Down
Loading

0 comments on commit 50af49c

Please sign in to comment.