geo-validity-check

Expose a Valid trait to check if rust geo-types geometries are valid.

Valid trait has the following signature:

rust trait Valid { fn is_valid(&self) -> bool; fn explain_invalidity(&self) -> Option<ProblemReport>; }

The result of the invalidity reason is provided in a ProblemReport struct (it contains a Vec of (Problem, ProblemPosition), two enums that respectively represent the type of problem and the position of the problem in the tested geometry - having this machine-readable information could be useful to try to fix the geometry). This ProblemReport result can also be formatted as a string as it implements the Display trait.

Checks implemented

Verification is done against GEOS (any geometry invalid according to GEOS should be invalid according to this crate - the inverse doesn't have to be true since we are doing some extra check).

Example

```rust use geovaliditycheck::Valid; use geo_types::{Point, LineString, Polygon, MultiPolygon};

let line1 = LineString::from(vec![(0., 0.), (1., 1.)]); let line2 = LineString::from(vec![(0., 0.), (0., 0.)]); let line3 = LineString::from(vec![(0., 0.), (f64::NAN, f64::NAN), (1., 1.)]);

assert!(line1.isvalid()); assert!(!line2.isvalid()); assert!(!line3.is_valid());

println!("{}", line2.invalidityreason().unwrap()); // "LineString has too few points at coordinate 0 of the LineString" println!("{}", line3.invalidityreason().unwrap()); // "Coordinate is not finite (NaN or infinite) at coordinate 1 of the LineString"

let polygon = Polygon::new( LineString::from(vec![(0.5, 0.5), (3., 0.5), (3., 2.5), (0.5, 2.5), (0.5, 0.5)]), vec![LineString::from(vec![(1., 1.), (1., 2.), (2.5, 2.), (3.5, 1.), (1., 1.)])], );

assert!(!polygon.isvalid()); println!("{}", polygon.invalidityreason().unwrap()); // "The interior ring of a Polygon is not contained in the exterior ring on the interior ring n°0"

let multipolygon = MultiPolygon(vec![ Polygon::new( LineString::from(vec![(0.5, 0.5), (3., 0.5), (3., 2.5), (0.5, 2.5), (0.5, 0.5)]), vec![LineString::from(vec![(1., 1.), (1., 2.), (2.5, 2.), (3.5, 1.), (1., 1.)])], ), Polygon::new( LineString::from(vec![(0.5, 0.5), (3., 0.5), (3., 2.5), (0.5, 2.5), (0.5, 0.5)]), vec![LineString::from(vec![(1., 1.), (1., 2.), (2.5, 2.), (3.5, 1.), (1., 1.)])], ), ]);

assert!(!multipolygon.isvalid()); println!("{}", multipolygon.invalidityreason().unwrap()); // "The interior ring of a Polygon is not contained in the exterior ring on the interior ring n°0 of the Polygon n°0 of the MultiPolygon // Two Polygons of MultiPolygons are identical on the exterior ring of the Polygon n°0 of the MultiPolygon // The interior ring of a Polygon is not contained in the exterior ring on the interior ring n°0 of the Polygon n°1 of the MultiPolygon // Two Polygons of MultiPolygons are identical on the exterior ring of the Polygon n°1 of the MultiPolygon"

```

TODO / Ideas

License

Licensed under either of

at your option.