1

I'm using ST_ReducePrecision in PostGIS to lower the tolerance of shapes so they can be read by ArcMap.

I'm applying ST_ReducePrecision(shape, 0.0001) with a tolerance of 0.0001 to match ArcMap's tolerance threshold. However, I'm encountering inconsistencies: some layers throw a TopologyException error when reducing their precision, and I have to lower the tolerance threshold further to avoid this error. I noticed that the function returns an empty polygon in some cases as well. Why does this happen, and how can I resolve it?

ERROR: lwgeom_reduceprecision: GEOS Error: TopologyException: Ring edge missing at -81.0762 40.416499999999999

Example shapes throwing error:

'POLYGON((-81.07617417999995 40.41644104000005,-81.07564138383023 40.41651771771441,-81.0761647459999 40.41641947000005,-81.07618946678375 40.4164759888721,-81.07617417999995 40.41644104000005))'

'POLYGON((-80.94533513799996 40.688838678000025,-80.94608381135927 40.68981923891161,-80.94607828799991 40.690919819999976,-80.94606284029669 40.69354660600186,-80.94606512299987 40.6935466450002,-80.94605917499985 40.69473439700005,-80.9460588479999 40.69479968600001,-80.94605846900004 40.694868292000194,-80.94605805499992 40.69495063800008,-80.9459727269998 40.70219608699995,-80.94597236899983 40.70222642900018,-80.94349159199993 40.70219077000013,-80.93963737799987 40.70213525999998,-80.93970467099984 40.70069341300018,-80.93982688900002 40.698453888000245,-80.9398648729998 40.69754836600009,-80.93979271300003 40.69754821200007,-80.93633854399991 40.69754077100009,-80.93633969399991 40.69738355100003,-80.9363453819999 40.696642410000095,-80.93528609999993 40.695559449000086,-80.93526858999991 40.69554154800011,-80.936313112 40.69485608499997,-80.9363592929999 40.69482577800005,-80.93639832299993 40.69482600000009,-80.93779095799988 40.694833912000206,-80.93999666199994 40.69484640500008,-80.94002425499991 40.69401579800018,-80.9400313029999 40.6934423030001,-80.94003871099989 40.692839499000115,-80.94003876799991 40.69283479000018,-80.94005684653133 40.69136296938674,-80.94072258005211 40.69104458882698,-80.94147380699985 40.69084031000017,-80.94161899999989 40.6908008270002,-80.94385607399988 40.6901824680001,-80.94392788699997 40.689732874000185,-80.94387054697607 40.689539104365004,-80.94533513799996 40.688838678000025),(-80.94017029099996 40.69344505000004,-80.94132916299998 40.693465046000085,-80.94606283300004 40.69354787200018,-80.9400313029999 40.6934423030001,-80.94017029099996 40.69344505000004),(-80.94065147099985 40.694853976000104,-80.94031648600003 40.69485191299998,-80.94124708599986 40.694867935000104,-80.94065147099985 40.694853976000104))'
8
  • ArcMap doesn't need shapes stripped to four places of precision in decimal degrees (which is pretty coarse for geodata). ob xkcd
    – Vince
    Commented Aug 27 at 16:49
  • Shapes throw shape integrity error with lower precision while reading fine on QGIS .Reference I used for the limits: gis.stackexchange.com/questions/250165/…
    – Sam
    Commented Aug 27 at 16:59
  • 2
    It looks like your geometries are WGS 84 (srid 4326). Reducing precision to 0.0001 is moving your vertices up to 11m. My guess is that you're trying to set a tolerance of 0.0001 m? If so, you need a gridsize of about 9 decimals or 0.000000001.
    – jbalk
    Commented Aug 27 at 17:11
  • @Sam the post you have linked didn't quote the doc properly. The distances are in "meters or its equivalent in map units"
    – JGH
    Commented Aug 27 at 17:59
  • 2
    If you layer projection unit is in meters, then 0.0001 meters if pretty accurate and sufficient. If the projection unit is in degrees - as in your sample -, 0.0001 degree is very coarse (about 11m as Jbalk and Vince wrote). Your 1st polygon is about 6m on one side, which will collapse to a single point when using an 11 meters resolution, making it invalid. --> if you want to stick to a resolution of 0.0001 map unit then use another projection. Else, use a resolution of 0.0001 meters, which is roughly 0.000000001 map units
    – JGH
    Commented Aug 27 at 19:23

1 Answer 1

4

As mentioned in the comments... a grid size/tolerance of 0.0001 in WGS84 coordinates isn't very precise anymore (~11 meter, depending on where on earth you are, overview of precisions: openstreetmap wiki), so possibly you want to reconsider this.

Nonetheless, it shouldn't give an error.

I'm not a PostGIS user, but as far as I know ST_ReducePrecision uses the GEOS function set_precision under the hood. In recent GEOS versions there have been updates that fix many instances of this type of error.

I also tested your two polygons, and they don't give an error when applying set_precision with e.g. GEOS 3.12.2.

So, I would check the version of GEOS in your installation and considering upgrading your installation if it isn't a recent version.

Test script (in python, shapely is a python wrapper of GEOS):

import shapely

wkt1 = 'POLYGON((-81.07617417999995 40.41644104000005,-81.07564138383023 40.41651771771441,-81.0761647459999 40.41641947000005,-81.07618946678375 40.4164759888721,-81.07617417999995 40.41644104000005))'
wkt2 = 'POLYGON((-80.94533513799996 40.688838678000025,-80.94608381135927 40.68981923891161,-80.94607828799991 40.690919819999976,-80.94606284029669 40.69354660600186,-80.94606512299987 40.6935466450002,-80.94605917499985 40.69473439700005,-80.9460588479999 40.69479968600001,-80.94605846900004 40.694868292000194,-80.94605805499992 40.69495063800008,-80.9459727269998 40.70219608699995,-80.94597236899983 40.70222642900018,-80.94349159199993 40.70219077000013,-80.93963737799987 40.70213525999998,-80.93970467099984 40.70069341300018,-80.93982688900002 40.698453888000245,-80.9398648729998 40.69754836600009,-80.93979271300003 40.69754821200007,-80.93633854399991 40.69754077100009,-80.93633969399991 40.69738355100003,-80.9363453819999 40.696642410000095,-80.93528609999993 40.695559449000086,-80.93526858999991 40.69554154800011,-80.936313112 40.69485608499997,-80.9363592929999 40.69482577800005,-80.93639832299993 40.69482600000009,-80.93779095799988 40.694833912000206,-80.93999666199994 40.69484640500008,-80.94002425499991 40.69401579800018,-80.9400313029999 40.6934423030001,-80.94003871099989 40.692839499000115,-80.94003876799991 40.69283479000018,-80.94005684653133 40.69136296938674,-80.94072258005211 40.69104458882698,-80.94147380699985 40.69084031000017,-80.94161899999989 40.6908008270002,-80.94385607399988 40.6901824680001,-80.94392788699997 40.689732874000185,-80.94387054697607 40.689539104365004,-80.94533513799996 40.688838678000025),(-80.94017029099996 40.69344505000004,-80.94132916299998 40.693465046000085,-80.94606283300004 40.69354787200018,-80.9400313029999 40.6934423030001,-80.94017029099996 40.69344505000004),(-80.94065147099985 40.694853976000104,-80.94031648600003 40.69485191299998,-80.94124708599986 40.694867935000104,-80.94065147099985 40.694853976000104))'

poly1 = shapely.from_wkt(wkt1)
poly2 = shapely.from_wkt(wkt2)

print(f"{poly1.is_valid=}")
print(f"{poly2.is_valid=}")

poly1_prec = shapely.set_precision(poly1, grid_size=0.0001)
poly2_prec = shapely.set_precision(poly2, grid_size=0.0001)

print(poly1_prec)
print(poly2_prec)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.