Is there any way to dissolve (merge) overlapping polygons, using any GDAL/OGR API or command line tool, while keeping the resulting non overlapping areas distinct? I have searched a lot and I cannot find anything resembling what need. However, I think it is very unlikely that this problem has not been solved yet.
Here's a more detailed description of what I need:
It is the last point which is causing troubles. I basically get what I need except for the last point. If I run the typical solution for dissolving a shape file
$ ogr2ogr -f "ESRI Shapefile" dissolved.shp input.shp -dialect sqlite -sql "select ST_union(Geometry) from input"
I end up with a single polygon which includes everything, even if the areas are not connected.
Update: I solved the problem by ditching GDAL entirely. As many sources point out it is generally a better approach to use fiona and shapely to work with shapefiles. I have posted my solution below.
I had a similar problem and solved it like this, taking all the previous answers from Taking Union of several geometries in GEOS Python? into account:
import os
from osgeo import ogr
def createDS(ds_name, ds_format, geom_type, srs, overwrite=False):
drv = ogr.GetDriverByName(ds_format)
if os.path.exists(ds_name) and overwrite is True:
deleteDS(ds_name)
ds = drv.CreateDataSource(ds_name)
lyr_name = os.path.splitext(os.path.basename(ds_name))[0]
lyr = ds.CreateLayer(lyr_name, srs, geom_type)
return ds, lyr
def dissolve(input, output, multipoly=False, overwrite=False):
ds = ogr.Open(input)
lyr = ds.GetLayer()
out_ds, out_lyr = createDS(output, ds.GetDriver().GetName(), lyr.GetGeomType(), lyr.GetSpatialRef(), overwrite)
defn = out_lyr.GetLayerDefn()
multi = ogr.Geometry(ogr.wkbMultiPolygon)
for feat in lyr:
if feat.geometry():
feat.geometry().CloseRings() # this copies the first point to the end
wkt = feat.geometry().ExportToWkt()
multi.AddGeometryDirectly(ogr.CreateGeometryFromWkt(wkt))
union = multi.UnionCascaded()
if multipoly is False:
for geom in union:
poly = ogr.CreateGeometryFromWkb(geom.ExportToWkb())
feat = ogr.Feature(defn)
feat.SetGeometry(poly)
out_lyr.CreateFeature(feat)
else:
out_feat = ogr.Feature(defn)
out_feat.SetGeometry(union)
out_lyr.CreateFeature(out_feat)
out_ds.Destroy()
ds.Destroy()
return True
UnionCascaded
requires MultiPolygon
as a geometry type, which is why I implemented the option to re-create single polyons. You could also use ogr2ogr
from the command line with option -explodecollections
:
ogr2ogr -f "ESRI Shapefile" -explodecollections dissolved.shp input.shp -dialect sqlite -sql "select ST_union(Geometry) from input"
So, after many unsuccessful attempts I have ditched gdal/ogr and went on with shapely and fiona. This does exactly what I need. The filtering was necessary becuase my dataset contains self-intersecting polygons which need to be filtered out before calling cascaded_union
.
import fiona
from shapely.ops import cascaded_union
from shapely.geometry import shape, mapping
with fiona.open(src, 'r') as ds_in:
crs = ds_in.crs
drv = ds_in.driver
filtered = filter(lambda x: shape(x["geometry"]).is_valid, list(ds_in))
geoms = [shape(x["geometry"]) for x in filtered]
dissolved = cascaded_union(geoms)
schema = {
"geometry": "Polygon",
"properties": {"id": "int"}
}
with fiona.open(dst, 'w', driver=drv, schema=schema, crs=crs) as ds_dst:
for i,g in enumerate(dissolved):
ds_dst.write({"geometry": mapping(g), "properties": {"id": i}})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With