PyQGIS – How to Clip Geometry in PyQGIS Without Using a Layer as Input

pyqgisqgis-3

I have two vector geometries, geom1 and geom2. They do not exist as individual layers, but rather are derived out of additional scripting in PyQGIS.

I would like to clip geom1 with geom2.

From what I can tell, the only clipping functions available are the processing algorithms which – appear to only take individual layers as input. The geometries I have don't exist as individual layers, rather they have been derived via something similar to:

geom1 = feature.geometry()

The help for the clip algorithm (processing.algorithmHelp("qgis:clip")) suggests that the input and overlap need to be layers.

So the only solution I can see is to convert my geom1 and geom2, into temporary virtual layers, and then clip. This seems really really inefficient and I'm trying to work out if there is better way to do this.
Ideally something like:

clipped_result = clip(geom1, geom2)

Best Answer

I think that the intersection() method of QgsGeometry is what you are after.

From the docs:

Returns a geometry representing the points shared by this geometry and other.

So the analogue to your pseudocode is:

clipped_result = geom1.intersection(geom2)

i.e. the new geometry object stored in the return value clipped_result represents geom1 clipped with geom2.

A simple example of usage:

l = iface.activeLayer()
geom1 = l.getFeature(1).geometry()
geom2 = l.getFeature(2).geometry()
geom3 = geom1.intersection(geom2)
feat = QgsFeature()
feat.setGeometry(geom3)
with edit(l):
    l.addFeature(feat)
l.triggerRepaint()

Screencast:

enter image description here

If you want to edit a feature's geometry in-place (clip a feature), you can do it at the layer level like:

l = iface.activeLayer()
f1 = l.getFeature(1)
#print(f1.geometry())
f2 = l.getFeature(2)
geom3 = f1.geometry().intersection(f2.geometry())
with edit(l):
    l.changeGeometry(f1.id(), geom3)
l.triggerRepaint()

enter image description here

There is also difference() method which

Returns a geometry representing the points making up this geometry that do not make up other.

E.g.

l = iface.activeLayer()
geom1 = l.getFeature(1).geometry()
geom2 = l.getFeature(2).geometry()
geom3 = geom1.difference(geom2)
feat = QgsFeature()
feat.setGeometry(geom3)
with edit(l):
    l.addFeature(feat)
l.triggerRepaint()

enter image description here

Related Question