Geometry Validity

Several functions and utilities in GDAL deal with the concepts of "valid" and "invalid" geometries. Validity in this context refers to the OGR Simple Features standard. Incorrect results may be obtained when invalid geometries are used in spatial algorithms such as intersection testing/computation.

Geometry validity can be checked using the gdal vector check-geometry command-line utility or the API functions OGRGeometry::IsValid() (C++) and ogr.Geometry.IsValid() (Python). In many cases, invalid geometries can be repaired using the gdal vector make-valid command-line utility or the API functions OGRGeometry::MakeValid() (C++) and ogr.Geometry.MakeValid() (Python).

Geometry validity does not consider interactions between features, such as gaps and overlaps, although gdal vector check-coverage provides some means for evaluating this. Qualitative errors such as spikes and slivers are outside the scope of validity testing.

Validity checking

GDAL relies on the GEOS library to check the validity of geometries. This library is widely used by open source geospatial software, so geometries considered valid by GDAL should be considered valid by QGIS, PostGIS, shapely, etc. Still, some geometries considered valid by GEOS may not be considered valid in other software. The following limitations apply to validity testing:

  • GEOS does not enforce any particular ring orientation for polygon shells and holes, and permits repeated points within a ring.

  • GEOS considers only two dimensions when checking geometry validity. For example, if two elements of a MultiPolygon occupy the same space but with different Z values, they will still be considered invalid by GEOS and therefore GDAL.

  • Curved geometries are approximated as linear geometries before being evaluated by GEOS. Linearized geometries may be valid where the original geometries are not, and vice-versa.

Finally, not all software uses the OGC model for invalid geometries. As a simple example, the self-touching ring shown below is considered valid in the Esri geometry model.

Geometry repair

In many cases, the correct representation of an invalid geometry is ambiguous. GEOS provides two different algorithms for constructing a valid geometry from an invalid one. The "linework" method attempts to preserve as many of the input lines as possible, in some cases converting polygon holes into shells and vice-versa. On the other hand, the "structure" method can remove input lines such that areas covered by a polygon shell in the input remain covered in the output.

In some cases, such as a polygon with a non-closed ring, an invalid geometry cannot be represented in the GEOS library and therefore cannot be repaired automatically.

Invalid geometry examples

The cases below illustrate a number of topological invalidities, how they are reported by gdal vector check-geometry, and how they may be resolved by the different methods of gdal vector make-valid.

Self-intersecting polygon

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_1.svg

Input geometry: POLYGON ((10 90,90 10,90 90,10 10,10 90))

Error message: Self-intersection

Error geometry: MULTIPOINT (50 50)

../_images/geometry_make_valid_linework_1.svg

MULTIPOLYGON (((10 10,10 90,50 50,10 10)),((90 10,50 50,90 90,90 10)))

../_images/geometry_make_valid_structure_1.svg

MULTIPOLYGON (((10 90,50 50,10 10,10 90)),((50 50,90 90,90 10,50 50)))

Polygon with self-touching ring

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_2.svg

Input geometry: POLYGON ((10 10,90 10,90 40,80 20,70 40,80 60,90 40,90 90,10 90,10 10))

Error message: Ring Self-intersection

Error geometry: MULTIPOINT (90 40)

../_images/geometry_make_valid_linework_2.svg

POLYGON ((90 10,10 10,10 90,90 90,90 40,90 10),(80 60,70 40,80 20,90 40,80 60))

../_images/geometry_make_valid_structure_2.svg

POLYGON ((10 10,10 90,90 90,90 40,90 10,10 10),(90 40,80 60,70 40,80 20,90 40))

Polygon hole outside shell

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_3.svg

Input geometry: POLYGON ((10 90,50 90,50 10,10 10,10 90),(60 80,90 80,90 20,60 20,60 80))

Error message: Hole lies outside shell

Error geometry: MULTIPOINT (60 80)

../_images/geometry_make_valid_linework_3.svg

MULTIPOLYGON (((50 10,10 10,10 90,50 90,50 10)),((90 20,60 20,60 80,90 80,90 20)))

../_images/geometry_make_valid_structure_3.svg

MULTIPOLYGON (((50 90,50 10,10 10,10 90,50 90)),((90 80,90 20,60 20,60 80,90 80)))

Hole partially outside polygon shell

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_4.svg

Input geometry: POLYGON ((10 90,60 90,60 10,10 10,10 90),(30 70,90 70,90 30,30 30,30 70))

Error message: Self-intersection

Error geometry: MULTIPOINT (60 70)

../_images/geometry_make_valid_linework_4.svg

MULTIPOLYGON (((90 70,90 30,60 30,60 70,90 70)),((60 10,10 10,10 90,60 90,60 70,30 70,30 30,60 30,60 10)))

../_images/geometry_make_valid_structure_4.svg

POLYGON ((60 90,60 70,30 70,30 30,60 30,60 10,10 10,10 90,60 90))

Polygon hole equal to shell

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_5.svg

Input geometry: POLYGON ((10 90,90 90,90 10,10 10,10 90),(10 90,90 90,90 10,10 10,10 90))

Error message: Self-intersection

Error geometry: MULTIPOINT (10 90)

../_images/geometry_make_valid_linework_5.svg

POLYGON ((90 90,90 10,10 10,10 90,90 90))

../_images/geometry_make_valid_structure_5.svg

POLYGON EMPTY

Polygon holes overlap

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_6.svg

Input geometry: POLYGON ((10 90,90 90,90 10,10 10,10 90),(80 80,80 30,30 30,30 80,80 80),(20 20,20 70,70 70,70 20,20 20))

Error message: Self-intersection

Error geometry: MULTIPOINT (70 30)

../_images/geometry_make_valid_linework_6.svg

MULTIPOLYGON (((90 90,90 10,10 10,10 90,90 90),(80 30,80 80,30 80,30 70,20 70,20 20,70 20,70 30,80 30)),((30 30,30 70,70 70,70 30,30 30)))

../_images/geometry_make_valid_structure_6.svg

POLYGON ((90 90,90 10,10 10,10 90,90 90),(20 20,70 20,70 30,80 30,80 80,30 80,30 70,20 70,20 20))

Polygon shell inside hole

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_7.svg

Input geometry: POLYGON ((30 70,70 70,70 30,30 30,30 70),(10 90,90 90,90 10,10 10,10 90))

Error message: Hole lies outside shell

Error geometry: MULTIPOINT (10 90)

../_images/geometry_make_valid_linework_7.svg

POLYGON ((90 90,90 10,10 10,10 90,90 90),(30 30,70 30,70 70,30 70,30 30))

../_images/geometry_make_valid_structure_7.svg

POLYGON EMPTY

Self-crossing polygon shell

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_8.svg

Input geometry: POLYGON ((10 70,90 70,90 50,30 50,30 30,50 30,50 90,70 90,70 10,10 10,10 70))

Error message: Self-intersection

Error geometry: MULTIPOINT (50 70)

../_images/geometry_make_valid_linework_8.svg

MULTIPOLYGON (((10 70,50 70,50 50,70 50,70 10,10 10,10 70),(30 50,30 30,50 30,50 50,30 50)),((50 90,70 90,70 70,50 70,50 90)),((90 70,90 50,70 50,70 70,90 70)))

../_images/geometry_make_valid_structure_8.svg

POLYGON ((10 70,50 70,50 90,70 90,70 70,90 70,90 50,70 50,70 10,10 10,10 70),(50 50,30 50,30 30,50 30,50 50))

Self-overlapping polygon shell

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_9.svg

Input geometry: POLYGON ((10 90,50 90,50 30,70 30,70 50,30 50,30 70,90 70,90 10,10 10,10 90))

Error message: Self-intersection

Error geometry: MULTIPOINT (50 70)

../_images/geometry_make_valid_linework_9.svg

POLYGON ((50 90,50 70,90 70,90 10,10 10,10 90,50 90),(30 70,30 50,50 50,50 70,30 70),(50 30,70 30,70 50,50 50,50 30))

../_images/geometry_make_valid_structure_9.svg

POLYGON ((10 90,50 90,50 70,90 70,90 10,10 10,10 90),(50 50,50 30,70 30,70 50,50 50))

Nested MultiPolygons

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_10.svg

Input geometry: MULTIPOLYGON (((30 70,70 70,70 30,30 30,30 70)),((10 90,90 90,90 10,10 10,10 90)))

Error message: Nested shells

Error geometry: MULTIPOINT (30 70)

../_images/geometry_make_valid_linework_10.svg

POLYGON ((90 90,90 10,10 10,10 90,90 90),(30 30,70 30,70 70,30 70,30 30))

../_images/geometry_make_valid_structure_10.svg

MULTIPOLYGON (((90 90,90 10,10 10,10 90,90 90)))

Overlapping MultiPolygons

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_11.svg

Input geometry: MULTIPOLYGON (((10 90,60 90,60 10,10 10,10 90)),((90 80,90 20,40 20,40 80,90 80)))

Error message: Self-intersection

Error geometry: MULTIPOINT (60 80)

../_images/geometry_make_valid_linework_11.svg

MULTIPOLYGON (((90 80,90 20,60 20,60 80,90 80)),((60 10,10 10,10 90,60 90,60 80,40 80,40 20,60 20,60 10)))

../_images/geometry_make_valid_structure_11.svg

MULTIPOLYGON (((60 90,60 80,90 80,90 20,60 20,60 10,10 10,10 90,60 90)))

MultiPolygon with multiple overlapping Polygons

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_12.svg

Input geometry: MULTIPOLYGON (((90 90,90 30,30 30,30 90,90 90)),((20 20,20 80,80 80,80 20,20 20)),((10 10,10 70,70 70,70 10,10 10)))

Error message: Self-intersection

Error geometry: MULTIPOINT (70 20)

../_images/geometry_make_valid_linework_12.svg

MULTIPOLYGON (((10 10,10 70,20 70,20 20,70 20,70 10,10 10)),((30 80,30 70,20 70,20 80,30 80)),((90 90,90 30,80 30,80 80,30 80,30 90,90 90)),((70 20,70 30,80 30,80 20,70 20)),((30 30,30 70,70 70,70 30,30 30)))

../_images/geometry_make_valid_structure_12.svg

MULTIPOLYGON (((10 70,20 70,20 80,30 80,30 90,90 90,90 30,80 30,80 20,70 20,70 10,10 10,10 70)))

MultiPolygon with two adjacent Polygons

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_13.svg

Input geometry: MULTIPOLYGON (((10 90,50 90,50 10,10 10,10 90)),((90 80,90 20,50 20,50 80,90 80)))

Error message: Self-intersection

Error geometry: MULTIPOINT (50 80)

../_images/geometry_make_valid_linework_13.svg

POLYGON ((50 80,90 80,90 20,50 20,50 10,10 10,10 90,50 90,50 80))

../_images/geometry_make_valid_structure_13.svg

MULTIPOLYGON (((50 90,50 80,90 80,90 20,50 20,50 10,10 10,10 90,50 90)))

Single-point polygon

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_14.svg

Input geometry: POLYGON ((70 30))

Error message: point array must contain 0 or >1 elements

Error geometry: MULTIPOINT (70 30)

../_images/geometry_make_valid_linework_14.svg

POINT (70 30)

../_images/geometry_make_valid_structure_14.svg

POLYGON EMPTY

Two-point polygon

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_15.svg

Input geometry: POLYGON ((10 10,90 90))

Error message: Points of LinearRing do not form a closed linestring

Error geometry: MULTIPOINT (10 10)

../_images/geometry_make_valid_linework_15.svg

LINESTRING (10 10,90 90)

../_images/geometry_make_valid_structure_15.svg

POLYGON EMPTY

Non-closed ring

Input geometry and result of gdal vector check-geometry

gdal vector make-valid --method=linework

gdal vector make-valid --method=structure

../_images/geometry_source_16.svg

Input geometry: POLYGON ((10 10,90 10,90 90,10 90))

Error message: Points of LinearRing do not form a closed linestring

Error geometry: MULTIPOINT (10 10)

../_images/geometry_make_valid_linework_16.svg

POLYGON ((10 10,90 10,90 90,10 90,10 10))

../_images/geometry_make_valid_structure_16.svg

POLYGON ((10 10,10 90,90 90,90 10,10 10))