Skip to content

Commit

Permalink
Added envelope* methods to Geometry.
Browse files Browse the repository at this point in the history
  • Loading branch information
metasim committed Feb 13, 2023
1 parent f6b2a16 commit eb15b5c
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 23 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@

- <https://github.com/georust/gdal/pull/366>

- Added `Geometry::envelope` and `Geometry::envelope_3d`.

- <https://github.com/georust/gdal/pull/370>

## 0.14

- Added new content to `README.md` and the root docs.
Expand Down
2 changes: 1 addition & 1 deletion src/spatial_ref/srs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl CoordTransform {
/// Some([f64; 4]) with bounds in axis order of target SpatialRef
/// None if there is an error.
#[cfg(all(major_ge_3, minor_ge_4))]
pub fn transform_bounds(&self, bounds: &[f64; 4], densify_pts: i32) -> Result<([f64; 4])> {
pub fn transform_bounds(&self, bounds: &[f64; 4], densify_pts: i32) -> Result<[f64; 4]> {
let mut out_xmin: f64 = 0.;
let mut out_ymin: f64 = 0.;
let mut out_xmax: f64 = 0.;
Expand Down
53 changes: 53 additions & 0 deletions src/vector/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::cell::RefCell;
use std::ffi::CString;
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::ptr::null_mut;

Expand All @@ -13,6 +14,7 @@ use gdal_sys::{self, OGRErr, OGRGeometryH, OGRwkbGeometryType};
use crate::errors::*;
use crate::spatial_ref::{CoordTransform, SpatialRef};
use crate::utils::{_last_null_pointer_err, _string};
use crate::vector::{Envelope, Envelope3D};

/// OGR Geometry
pub struct Geometry {
Expand Down Expand Up @@ -424,10 +426,38 @@ impl Geometry {
Ok(unsafe { Geometry::with_c_geometry(new_c_geom, true) })
}

/// Compute geometry area in square units of the spatial reference system in use.
///
/// Supported for `LinearRing`, `Polygon` or `MultiPolygon`.
/// Returns zero for all other geometry types.
///
/// See: [`OGR_G_Area`](https://gdal.org/api/vector_c_api.html#_CPPv410OGR_G_Area12OGRGeometryH)
pub fn area(&self) -> f64 {
unsafe { gdal_sys::OGR_G_Area(self.c_geometry()) }
}

/// Computes and returns the axis-aligned 2D bounding envelope for this geometry.
///
/// See: [`OGR_G_GetEnvelope`](https://gdal.org/api/vector_c_api.html#_CPPv417OGR_G_GetEnvelope12OGRGeometryHP11OGREnvelope)
pub fn envelope(&self) -> Envelope {
let mut envelope = MaybeUninit::uninit();
unsafe {
gdal_sys::OGR_G_GetEnvelope(self.c_geometry(), envelope.as_mut_ptr());
envelope.assume_init()
}
}

/// Computes and returns the axis aligned 3D bounding envelope for this geometry.
///
/// See: [`OGR_G_GetEnvelope3D`](https://gdal.org/api/vector_c_api.html#_CPPv419OGR_G_GetEnvelope3D12OGRGeometryHP13OGREnvelope3D)
pub fn envelope_3d(&self) -> Envelope3D {
let mut envelope = MaybeUninit::uninit();
unsafe {
gdal_sys::OGR_G_GetEnvelope3D(self.c_geometry(), envelope.as_mut_ptr());
envelope.assume_init()
}
}

/// Get the spatial reference system for this geometry.
///
/// Returns `Some(SpatialRef)`, or `None` if one isn't defined.
Expand Down Expand Up @@ -585,6 +615,7 @@ impl Debug for GeometryRef<'_> {
#[cfg(test)]
mod tests {
use super::*;
use crate::assert_almost_eq;
use crate::spatial_ref::SpatialRef;
use crate::test_utils::SuppressGDALErrorLog;

Expand Down Expand Up @@ -738,4 +769,26 @@ mod tests {
assert!(dst.is_ok(), "{dst:?}");
assert!(dst.unwrap().is_valid());
}

#[test]
fn test_envelope() {
let geom = Geometry::from_wkt("MULTIPOINT((1.0 2.0), (2.0 4.0))").unwrap();
let envelope = geom.envelope();
assert_almost_eq(envelope.MinX, 1.0);
assert_almost_eq(envelope.MaxX, 2.0);
assert_almost_eq(envelope.MinY, 2.0);
assert_almost_eq(envelope.MaxY, 4.0);
}

#[test]
fn test_envelope3d() {
let geom = Geometry::from_wkt("MULTIPOINT((1.0 2.0 3.0), (2.0 4.0 5.0))").unwrap();
let envelope = geom.envelope_3d();
assert_almost_eq(envelope.MinX, 1.0);
assert_almost_eq(envelope.MaxX, 2.0);
assert_almost_eq(envelope.MinY, 2.0);
assert_almost_eq(envelope.MaxY, 4.0);
assert_almost_eq(envelope.MinZ, 3.0);
assert_almost_eq(envelope.MaxZ, 5.0);
}
}
33 changes: 11 additions & 22 deletions src/vector/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ use crate::metadata::Metadata;
use crate::spatial_ref::SpatialRef;
use crate::utils::{_last_null_pointer_err, _string};
use crate::vector::defn::Defn;
use crate::vector::{Feature, FieldValue, Geometry};
use crate::vector::{Envelope, Feature, FieldValue, Geometry};
use crate::{dataset::Dataset, gdal_major_object::MajorObject};
use gdal_sys::{
self, GDALMajorObjectH, OGREnvelope, OGRErr, OGRFieldDefnH, OGRFieldType, OGRLayerH,
};
use gdal_sys::{self, GDALMajorObjectH, OGRErr, OGRFieldDefnH, OGRFieldType, OGRLayerH};
use libc::c_int;
use std::mem::MaybeUninit;
use std::ptr::null_mut;
use std::{convert::TryInto, ffi::CString, marker::PhantomData};

Expand Down Expand Up @@ -371,22 +370,17 @@ pub trait LayerAccess: Sized {
///
/// Layers without any geometry may return [`OGRErr::OGRERR_FAILURE`] to indicate that no
/// meaningful extents could be collected.
fn get_extent(&self) -> Result<gdal_sys::OGREnvelope> {
let mut envelope = OGREnvelope {
MinX: 0.0,
MaxX: 0.0,
MinY: 0.0,
MaxY: 0.0,
};
fn get_extent(&self) -> Result<Envelope> {
let mut envelope = MaybeUninit::uninit();
let force = 1;
let rv = unsafe { gdal_sys::OGR_L_GetExtent(self.c_layer(), &mut envelope, force) };
let rv = unsafe { gdal_sys::OGR_L_GetExtent(self.c_layer(), envelope.as_mut_ptr(), force) };
if rv != OGRErr::OGRERR_NONE {
return Err(GdalError::OgrError {
err: rv,
method_name: "OGR_L_GetExtent",
});
}
Ok(envelope)
Ok(unsafe { envelope.assume_init() })
}

/// Returns the extent of this layer as an axis-aligned bounding box, if it is possible to
Expand All @@ -398,15 +392,10 @@ pub trait LayerAccess: Sized {
/// Depending on the driver, the returned extent may or may not take the [spatial
/// filter](`Layer::set_spatial_filter`) into account. So it is safer to call `try_get_extent`
/// without setting a spatial filter.
fn try_get_extent(&self) -> Result<Option<gdal_sys::OGREnvelope>> {
let mut envelope = OGREnvelope {
MinX: 0.0,
MaxX: 0.0,
MinY: 0.0,
MaxY: 0.0,
};
fn try_get_extent(&self) -> Result<Option<Envelope>> {
let mut envelope = MaybeUninit::uninit();
let force = 0;
let rv = unsafe { gdal_sys::OGR_L_GetExtent(self.c_layer(), &mut envelope, force) };
let rv = unsafe { gdal_sys::OGR_L_GetExtent(self.c_layer(), envelope.as_mut_ptr(), force) };
if rv == OGRErr::OGRERR_FAILURE {
Ok(None)
} else {
Expand All @@ -416,7 +405,7 @@ pub trait LayerAccess: Sized {
method_name: "OGR_L_GetExtent",
});
}
Ok(Some(envelope))
Ok(Some(unsafe { envelope.assume_init() }))
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/vector/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,11 @@ pub trait ToGdal {
fn to_gdal(&self) -> Result<Geometry>;
}

/// Axis aligned 2D bounding box.
pub type Envelope = gdal_sys::OGREnvelope;

/// Axis aligned 3D bounding box.
pub type Envelope3D = gdal_sys::OGREnvelope3D;

#[cfg(test)]
mod vector_tests;

0 comments on commit eb15b5c

Please sign in to comment.