[GIS] How to fix ‘GEOSDifference: TopologyException’

postgispostgis-2.0

Why does Postgis throws an error in this SQL?

Error:

ERROR:  GEOSDifference: TopologyException: found non-noded intersection between LINESTRING (-5.67027 43.5374, -5.67085 43.5376) and LINESTRING (-5.67111 43.5377, -5.6706 43.5375) at -5.6708422794605911 43.537631835802237

Query:

select st_astext(
    st_difference(
        st_geomfromtext('POLYGON((-5.66666 43.53301,-5.66704 43.53335,-5.66931 43.53374,-5.66975299919511 43.533380063154,-5.66979 43.53335,-5.66971 43.53478,-5.66969091189271 43.5348058613067,-5.67026768864541 43.5374211525033,-5.67084666354158 43.5376334432986,-5.67111 43.53773,-5.67059550578171 43.53754135212,-5.66854 43.53971,-5.66854 43.53971,-5.66854 43.53971,-5.66758 43.53976,-5.6665 43.5402,-5.6665 43.5402,-5.66609712188377 43.539781395014,-5.66401 43.54013,-5.66401 43.54013,-5.66351576708437 43.5392869195307,-5.66281 43.53909,-5.6626 43.53851,-5.66159162498075 43.5369268527413,-5.66131 43.53695,-5.66196 43.53617,-5.66272791899155 43.5356642562857,-5.66378432333548 43.5344801289574,-5.66384 43.53414,-5.66452 43.53344,-5.6656 43.53337,-5.66611 43.5331,-5.66666 43.53301))', 4326),
        st_geomfromtext('POLYGON((-5.66577 43.53447,-5.66612 43.53455,-5.66675167677363 43.5349178897119,-5.66735 43.53529,-5.66811 43.5355,-5.66786 43.53678,-5.66816 43.53697,-5.66801 43.53717,-5.66729498033211 43.5375449497042,-5.6665 43.53782,-5.66634200990626 43.5386936730934,-5.66634 43.53876,-5.66554366174751 43.5384386684555,-5.66521 43.53856,-5.66457 43.53781,-5.6640744056249 43.5375662650614,-5.66341231504476 43.5372589777288,-5.66324 43.53718,-5.66334987968078 43.536344363177,-5.66304550704754 43.5357063513112,-5.66299 43.53559,-5.66358 43.53544,-5.66413 43.53529,-5.66521 43.535,-5.66577 43.53447,-5.66577 43.53447))', 4326)
    )
);

This is a example of shapes with this problem. All share a common pattern. Some parts of edge are near to be parallel.

example 1
example 2
example 3
example 4

The point reported in the error is pointing to this location. In example 4, I marked this point with a circle.

Versions:

  • PostgreSQL 9.1.6 / x86_64
  • POSTGIS 2.0.1 r9979
  • GEOS 3.3.5-CAPI-1.7.5
  • PROJ Rel. 4.7.1, 23 September 2009
  • LIBXML 2.7.8
  • Ubuntu Server 12.04.1 LTS x64

Thanks!

Best Answer

You're working with invalid geometries (at least the first one is invalid):

osm=# select st_isvalid(st_geomfromtext('POLYGON((-5.66666 43.53301,-5.66704 43.53335,-5.66931 43.53374,-5.66975299919511 43.533380063154,-5.66979 43.53335,-5.66971 43.53478,-5.66969091189271 43.5348058613067,-5.67026768864541 43.5374211525033,-5.67084666354158 43.5376334432986,-5.67111 43.53773,-5.67059550578171 43.53754135212,-5.66854 43.53971,-5.66854 43.53971,-5.66854 43.53971,-5.66758 43.53976,-5.6665 43.5402,-5.6665 43.5402,-5.66609712188377 43.539781395014,-5.66401 43.54013,-5.66401 43.54013,-5.66351576708437 43.5392869195307,-5.66281 43.53909,-5.6626 43.53851,-5.66159162498075 43.5369268527413,-5.66131 43.53695,-5.66196 43.53617,-5.66272791899155 43.5356642562857,-5.66378432333548 43.5344801289574,-5.66384 43.53414,-5.66452 43.53344,-5.6656 43.53337,-5.66611 43.5331,-5.66666 43.53301))', 4326));
NOTICE:  Self-intersection at or near point -5.6708422794605911 43.537631835802237
 st_isvalid 
------------
 f
(1 row)

A quick and dirty fix (not guaranteed to work) is to use st_buffer to fix your invalid geometries. Postgis returns a result if you do, I haven't checked if it's correct:

select st_astext(
    st_difference(
    st_buffer(st_geomfromtext('POLYGON((-5.66666 43.53301,-5.66704 ...))', 4326), 0), 
    st_buffer(st_geomfromtext('POLYGON((-5.66577 43.53447,-5.66612 ...))', 4326), 0)
));
Related Question