| Crates.io | geo-validity-check |
| lib.rs | geo-validity-check |
| version | 0.1.0 |
| created_at | 2023-04-11 15:19:49.649121+00 |
| updated_at | 2023-04-11 15:19:49.649121+00 |
| description | Expose a 'Valid' trait to check the validity of a geo-types geometry and report cause(s) of invalidity. |
| homepage | https://github.com/mthh/geo-validity-check |
| repository | https://github.com/mthh/geo-validity-check |
| max_upload_size | |
| id | 836119 |
| size | 100,072 |
Expose a Valid trait to check if rust geo-types geometries are valid.
Valid trait has the following signature:
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.
Coord and Point use finite numbersMultiPoint is made of valid pointsRect, Line and Triangle are made of valid coordsTriangle are not empty or degenerate (i.e. all points are different and not collinear)Line is not of 0-length (i.e. both points are not the same)LineString is made of valid pointsLineString is not emptyLineString has at least two different pointsMultiLineString is made of valid linestringsPolygon rings are made of valid pointsPolygon rings have at least 4 points (including the closing point)Polygon interior rings are contained in the exterior ring (but can touch it on a point)Polygon interior rings don't cross each other (but can touch on a point)MultiPolygon components don't cross each other (but can touch on a point)MultiPolygon is made of valid polygonsGeometryCollection is made of valid geometriesVerification 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).
use geo_validity_check::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.is_valid());
assert!(!line2.is_valid());
assert!(!line3.is_valid());
println!("{}", line2.invalidity_reason().unwrap()); // "LineString has too few points at coordinate 0 of the LineString"
println!("{}", line3.invalidity_reason().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.is_valid());
println!("{}", polygon.invalidity_reason().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.is_valid());
println!("{}", multipolygon.invalidity_reason().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"
Improve the description of the invalidity reason (e.g. "Interior ring 0 intersects the exterior ring" could be "Interior ring 0 intersects the exterior ring at point (1.5, 1.5)")
Add a make_valid or fix_invalidity method to try to fix the geometry (e.g. by removing the invalid points ?)
Return the first invalidity reason found (instead of all of them) in invalidity_reason method ? (because some other checks could fail because of the first invalidity reason)
Implement a rule that states that a Polygon is valid if 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) ?
Licensed under either of
at your option.