-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rings order in MultiPolygon WKT string may leave overlapping parts when deleting holes (native:deleteholes) #44424
Comments
I should also add that the order of rings in the WKT has an impact in the ability of The following MultiPolygon has a inner ring of 9 unit² with an island of 1 unit² resulting in a hole of 8 unit². So if I set the vlayer = QgsVectorLayer("multipolygon?crs=EPSG:3857", "test", "memory")
geom = QgsGeometry().fromWkt('MultiPolygon (((0 0, 0 5, 5 5, 5 0, 0 0),(1 1, 4 1, 4 4, 1 4, 1 1)),((2 2, 2 3, 3 3, 3 2, 2 2)),((6 2, 6 3, 7 3, 7 2, 6 2)))')
fet = QgsFeature()
fet.setGeometry(geom)
vlayer.dataProvider().addFeature(fet)
params = {'INPUT':vlayer, 'MIN_AREA':8.5, 'OUTPUT':'TEMPORARY_OUTPUT'}
vlayer_filled = processing.run("native:deleteholes", params)["OUTPUT"]
vlayer_filled.getGeometry(1).asWkt()
# 'MultiPolygon (((0 0, 0 5, 5 5, 5 0, 0 0),(1 1, 4 1, 4 4, 1 4, 1 1)),((2 2, 2 3, 3 3, 3 2, 2 2)),((6 2, 6 3, 7 3, 7 2, 6 2)))' Interestingly, if I put all the nested ring inside the same parenthesis as I suggest, the hole also stays but the island is removed. vlayer = QgsVectorLayer("multipolygon?crs=EPSG:3857", "test", "memory")
geom = QgsGeometry().fromWkt('MultiPolygon (((0 0, 0 5, 5 5, 5 0, 0 0),(1 1, 4 1, 4 4, 1 4, 1 1),(2 2, 2 3, 3 3, 3 2, 2 2)),((6 2, 6 3, 7 3, 7 2, 6 2)))')
fet = QgsFeature()
fet.setGeometry(geom)
vlayer.dataProvider().addFeature(fet)
params = {'INPUT':vlayer, 'MIN_AREA':8.5, 'OUTPUT':'TEMPORARY_OUTPUT'}
vlayer_filled = processing.run("native:deleteholes", params)["OUTPUT"]
vlayer_filled.getGeometry(1).asWkt()
# 'MultiPolygon (((0 0, 0 5, 5 5, 5 0, 0 0),(1 1, 4 1, 4 4, 1 4, 1 1)),((6 2, 6 3, 7 3, 7 2, 6 2)))' As a side note, I find misleading the parameter |
Thank you for this very clear and detailed report, it is much appreciated. I am not sure if this can be considered a bug. Indeed, the algorithm does remove the hole, that's what it is asked. However, you're right it produces an invalid geometry. There are some others algorithm which can produce invalid geometry (I think about snap to grid, subdivide, etc) This case is simple to solve, since we can extract and merge polygon. Or use the magic buffer(0) trick, example: geom = QgsGeometry().fromWkt('MultiPolygon (((0 0, 0 5, 5 5, 5 0, 0 0),(1 1, 4 1, 4 4, 1 4, 1 1)),((2 2, 2 3, 3 3, 3 2, 2 2)),((6 2, 6 3, 7 3, 7 2, 6 2)))')
# removeInteriorRings result:
geom.removeInteriorRings()
# <QgsGeometry: MultiPolygon (((0 0, 0 5, 5 5, 5 0, 0 0)),((2 2, 2 3, 3 3, 3 2, 2 2)),((6 2, 6 3, 7 3, 7 2, 6 2)))>
# valideGeometry result
geom.removeInteriorRings().validateGeometry()
[<QgsGeometry.Error: Le polygone 1 est à l'intérieur du polygone 0>]
# using unaryUnion:
QgsGeometry().unaryUnion([geom.removeInteriorRings()])
<QgsGeometry: MultiPolygon (((0 5, 5 5, 5 0, 0 0, 0 5)),((7 3, 7 2, 6 2, 6 3, 7 3)))>
# using buffer(0)
geom.removeInteriorRings().buffer(0, 0)
# <QgsGeometry: MultiPolygon (((6 2, 6 3, 7 3, 7 2, 6 2)),((0 0, 0 5, 5 5, 5 0, 0 0)))>
# I noticed that makeValid doesn't work for this case
geom.removeInteriorRings().makeValid()
#<QgsGeometry: MultiPolygon (((5 5, 5 0, 0 0, 0 5, 5 5),(3 3, 2 3, 2 2, 3 2, 3 3)),((7 3, 7 2, 6 2, 6 3, 7 3)))> |
What is the bug or the crash?
I'm not so sure that this is a bug or a feature request but the issue it that when manually digitalizing a MultiPolygon, multiple level of nested rings don't seem to be store correctly or at least not in a way that some processing tools are expecting.
The following MultiPolygon, when manually drawn is defined as:
MultiPolygon (((0 0, 0 5, 5 5, 5 0, 0 0),(1 1, 4 1, 4 4, 1 4, 1 1)),((2 2, 2 3, 3 3, 3 2, 2 2)),((6 2, 6 3, 7 3, 7 2, 6 2)))
When trying to fill the hole using
native:deleteholes
, the hole is filled, but the island is not dissolved, resulting in an invalid feature (overlapping parts of the same feature):MultiPolygon (((0 0, 0 5, 5 5, 5 0, 0 0)),((2 2, 2 3, 3 3, 3 2, 2 2)),((6 2, 6 3, 7 3, 7 2, 6 2)))
Instead of the expected:
MultiPolygon (((0 0, 0 5, 5 5, 5 0, 0 0)),((6 2, 6 3, 7 3, 7 2, 6 2)))
However, if the WKT string is defined as
'MultiPolygon (((0 0, 0 5, 5 5, 5 0, 0 0),(1 1, 4 1, 4 4, 1 4, 1 1),(2 2, 2 3, 3 3, 3 2, 2 2)),((6 2, 6 3, 7 3, 7 2, 6 2)))'
then the island is dissolved.Steps to reproduce the issue
MultiPolygon with overlapping island after
native:deleteholes
MultiPolygon with dissolved island after
native:deleteholes
Versions
QGIS version 3.20.0-Odense
QGIS code revision decaadb
Qt version 5.15.2
Python version 3.9.5
GDAL/OGR version 3.3.0
GEOS version 3.9.1-CAPI-1.14.2
Windows 10 Version 1809
Additional context
I'm not sure of the fix:
native:deleteholes
should automatically remove overlapping partsInteresting read on GIS StackExchange on the matter: Order of polygon vertices in general GIS.
The text was updated successfully, but these errors were encountered: