Skip to content

Commit

Permalink
All JTS tests passing: EMPTY geometries are considered valid.
Browse files Browse the repository at this point in the history
We follow JTS/GEOS convention here.
  • Loading branch information
michaelkirk committed Dec 10, 2024
1 parent a71b2e4 commit e028661
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 15 deletions.
21 changes: 8 additions & 13 deletions geo/src/algorithm/validation/line_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ use super::{
utils, CoordinatePosition, Problem, ProblemAtPosition, ProblemPosition, ProblemReport,
Validation,
};
use crate::{GeoFloat, LineString};
use crate::{GeoFloat, HasDimensions, LineString};

/// In postGIS, a LineString is valid if it has at least 2 points
/// and have a non-zero length (i.e. the first and last points are not the same).
/// Here we also check that all its points are finite numbers.
impl<F: GeoFloat> Validation for LineString<F> {
fn is_valid(&self) -> bool {
if self.is_empty() {
return true;
}

if utils::check_too_few_points(self, false) {
return false;
}
Expand Down Expand Up @@ -70,20 +74,11 @@ mod tests {
}

#[test]
fn test_linestring_invalid_empty() {
fn test_linestring_valid_empty() {
let ls = LineString(vec![]);
assert!(!ls.is_valid());
assert_eq!(
ls.explain_invalidity(),
Some(ProblemReport(vec![ProblemAtPosition(
Problem::TooFewPoints,
ProblemPosition::LineString(CoordinatePosition(0))
)]))
);

// This linestring is invalid according to this crate but valid according to GEOS
assert!(ls.is_valid());
let linestring_geos: geos::Geometry = (&ls).try_into().unwrap();
assert_eq!(ls.is_valid(), !linestring_geos.is_valid());
assert_eq!(ls.is_valid(), linestring_geos.is_valid());
}

#[test]
Expand Down
12 changes: 11 additions & 1 deletion geo/src/algorithm/validation/polygon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::{
};
use crate::coordinate_position::CoordPos;
use crate::dimensions::Dimensions;
use crate::{Contains, GeoFloat, Polygon, Relate};
use crate::{Contains, GeoFloat, HasDimensions, Polygon, Relate};

/// In PostGIS, polygons must follow the following rules to be valid:
/// - [x] the polygon boundary rings (the exterior shell ring and interior hole rings) are simple (do not cross or self-touch). Because of this a polygon cannnot have cut lines, spikes or loops. This implies that polygon holes must be represented as interior rings, rather than by the exterior ring self-touching (a so-called "inverted hole").
Expand All @@ -14,7 +14,14 @@ use crate::{Contains, GeoFloat, Polygon, Relate};
/// - [ ] the polygon interior is simply connected (i.e. the rings must not touch in a way that splits the polygon into more than one part)
impl<F: GeoFloat> Validation for Polygon<F> {
fn is_valid(&self) -> bool {
if self.is_empty() {
return true;
}

for ring in self.interiors().iter().chain([self.exterior()]) {
if ring.is_empty() {
continue;
}
if utils::check_too_few_points(ring, true) {
return false;
}
Expand All @@ -31,6 +38,9 @@ impl<F: GeoFloat> Validation for Polygon<F> {
let polygon_exterior = Polygon::new(self.exterior().clone(), vec![]);

for interior_ring in self.interiors() {
if interior_ring.is_empty() {
continue;
}
// geo::contains::Contains return true if the interior
// is contained in the exterior even if they touches on one or more points
if !polygon_exterior.contains(interior_ring) {
Expand Down
2 changes: 1 addition & 1 deletion jts-test-runner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ mod tests {
//
// We'll need to increase this number as more tests are added, but it should never be
// decreased.
let expected_test_count: usize = 3020;
let expected_test_count: usize = 3775;
let actual_test_count = runner.failures().len() + runner.successes().len();
match actual_test_count.cmp(&expected_test_count) {
Ordering::Less => {
Expand Down

0 comments on commit e028661

Please sign in to comment.