Skip to content

Commit

Permalink
Add Geometry::difference
Browse files Browse the repository at this point in the history
  • Loading branch information
lnicola committed Dec 4, 2023
1 parent f37c7de commit 30fea92
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 1 deletion.
6 changes: 5 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

## Unreleased

- Added `Geometry::difference`.

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

- Added support for digital elevation model raster processing: `aspect`, `color_relief`, `hillshade`, `roughness`, `slope`, `terrain_ruggedness_index`, `topographic_position_index`.

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

- Added pre-built bindings for GDAL 3.8

Expand Down
72 changes: 72 additions & 0 deletions src/vector/ops/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,41 @@ impl Geometry {
Some(Geometry::with_c_geometry(ogr_geom, true))
}
}

/// Computes the [geometric difference][difference] of `self` and `other`.
///
/// Generates a new geometry which is the difference of the two geometries operated on.
///
/// # Notes
/// * Geometry validity is not checked, and invalid geometry will generate unpredictable results.
/// Use [`Geometry::is_valid`] if validity might be in question.
/// * If GEOS is *not* enabled, this function will always return `None`.
/// You may check for GEOS support with [`VersionInfo::has_geos`][has_geos].
///
/// # Returns
/// * `Some(geometry)`: a new `Geometry` representing the computed difference
/// * `None`: when the union could not be computed
///
/// See: [`OGR_G_Difference`][OGR_G_Difference]
///
/// [OGR_G_Difference]: https://gdal.org/api/vector_c_api.html#_CPPv416OGR_G_Difference12OGRGeometryH12OGRGeometryH
/// [difference]: https://en.wikipedia.org/wiki/Constructive_solid_geometry#Workings
/// [has_geos]: crate::version::VersionInfo::has_geos
pub fn difference(&self, other: &Self) -> Option<Self> {
if !self.has_gdal_ptr() {
return None;
}
if !other.has_gdal_ptr() {
return None;
}
unsafe {
let ogr_geom = gdal_sys::OGR_G_Difference(self.c_geometry(), other.c_geometry());
if ogr_geom.is_null() {
return None;
}
Some(Geometry::with_c_geometry(ogr_geom, true))
}
}
}

#[cfg(test)]
Expand Down Expand Up @@ -172,4 +207,41 @@ mod tests {

assert_eq!(res.unwrap().area(), 50.0);
}

#[test]
#[allow(clippy::float_cmp)]
fn test_difference_success() {
let geom =
Geometry::from_wkt("POLYGON ((0.0 10.0, 0.0 0.0, 10.0 0.0, 10.0 10.0, 0.0 10.0))")
.unwrap();
let other = Geometry::from_wkt("POLYGON ((1 -5, 1 1, -5 1, -5 -5, 1 -5))").unwrap();

let res = geom.difference(&other).unwrap();
assert_eq!(res.area(), 99.0);
}

#[test]
fn test_difference_no_gdal_ptr() {
let geom =
Geometry::from_wkt("POLYGON ((0.0 10.0, 0.0 0.0, 10.0 0.0, 10.0 10.0, 0.0 10.0))")
.unwrap();
let other = unsafe { Geometry::lazy_feature_geometry() };

let res = geom.difference(&other);
assert!(res.is_none());
}

#[test]
#[allow(clippy::float_cmp)]
fn test_difference_no_intersects() {
let geom =
Geometry::from_wkt("POLYGON ((0.0 5.0, 0.0 0.0, 5.0 0.0, 5.0 5.0, 0.0 5.0))").unwrap();

let other =
Geometry::from_wkt("POLYGON ((15.0 15.0, 15.0 20.0, 20.0 20.0, 20.0 15.0, 15.0 15.0))")
.unwrap();

let res = geom.difference(&other);
assert_eq!(res.unwrap().area(), 25.0);
}
}

0 comments on commit 30fea92

Please sign in to comment.