10

In ArcPy, you can pass a geometry object as parameter to geoprocessing tool:

import arcpy

coordinates = [[20, 30], [30, 30], [30, 20], [20, 20]] array = arcpy.Array([arcpy.Point(x, y) for x, y in coordinates])

Create a polygon geometry object using the array object

boundary = arcpy.Polygon(array, arcpy.SpatialReference(4326))

arcpy.Clip_analysis('c:/data/rivers.shp', boundary, # <- GEOMETRY OBJECT 'c:/data/rivers_clipped.shp')

I have a polygon geometry and a layer. I want to clip the layer by the polygon geometry using PyQGIS. Normally, I make a new layer, add the geometry to the layer and use it in processing.run as follows:

coordinates = [QgsPointXY(20, 30), QgsPointXY(30, 30),
               QgsPointXY(30, 20), QgsPointXY(20, 20)]
geometry = QgsGeometry.fromPolygonXY([coordinates ])

temp_layer = QgsVectorLayer(f"Polygon?crs=EPSG:4326", "TEST", "memory")

feature = QgsFeature() feature.setGeometry(geometry) temp_layer.dataProvider().addFeatures([feature]) temp_layer.updateExtents()

LayerA = iface.activeLayer()

result = processing.run("native:difference", {'INPUT': LayerA, # <- QgsVectorLayer 'OVERLAY': temp_layer, # <- QgsVectorLayer 'OUTPUT':'TEMPORARY_OUTPUT'})

But I would like to avoid making a new layer for one geometry. I tried passing a geometry to processing.run, but it obviously didn't work:

result = processing.run("native:difference",
                        {'INPUT': LayerA,       # <- QgsVectorLayer
                         'OVERLAY': geometry,   # <- QgsGeometry ?
                         'OUTPUT':'TEMPORARY_OUTPUT'})

How can I pass a geometry object to a processing tool without making a new layer for the geometry? Is that possible in PyQGIS?

Kadir Şahbaz
  • 76,800
  • 56
  • 247
  • 389
  • 1
    This something I have wondered too. Currently I have a function, geom2lyr to convert a geometry or list of geometries into a layer, in a library that I import into most of my scripts. Using the geometry directly would be very handy. – Matt Jan 25 '22 at 14:18

1 Answers1

4

When I check the help for the "native:difference"/"qgis:difference" algorithm with processing.algorithmHelp("native:difference") it declares that:

INPUT: Input layer
Parameter type: QgsProcessingParameterFeatureSource

Accepted data types:
    - str: layer ID
    - str: layer name
    - str: layer source
    - QgsProcessingFeatureSourceDefinition
    - QgsProperty
    - QgsVectorLayer

where:

  • QgsProcessingFeatureSourceDefinition : a constructor for QgsProcessingFeatureSourceDefinition, accepting a static string source.
  • QgsProperty : a constructor for a QgsAbstractProperty. The property will be set to an InvalidProperty type.
  • QgsVectorLayer : represents a vector layer which manages a vector based data sets.

So, it seems there is no possibility to pass directly the geometry object to processing algorithm.

However, I can suggest an alternative that uses a "Virtual Layer":

coordinates1 = [QgsPointXY(20, 30), QgsPointXY(30, 30), QgsPointXY(30, 20), QgsPointXY(20, 20)]
coordinates2 = [QgsPointXY(25, 35), QgsPointXY(35, 35), QgsPointXY(35, 25), QgsPointXY(25, 25)]

geometry1 = QgsGeometry.fromPolygonXY([coordinates1]) geometry2 = QgsGeometry.fromPolygonXY([coordinates2])

layer1 = QgsVectorLayer( f"?query=SELECT ST_GeomFromText('{geometry1.asWkt()}')", "vlayer1", "virtual" ) layer2 = QgsVectorLayer( f"?query=SELECT ST_GeomFromText('{geometry2.asWkt()}')", "vlayer2", "virtual" )

result = processing.runAndLoadResults("native:difference", {'INPUT': layer1, # <- QgsVectorLayer 'OVERLAY': layer2, # <- QgsVectorLayer 'OUTPUT':'memory:'})

If it is not mandatory to use the "Difference" tool one can also try this:

coordinates1 = [QgsPointXY(20, 30), QgsPointXY(30, 30), QgsPointXY(30, 20), QgsPointXY(20, 20)]
coordinates2 = [QgsPointXY(25, 35), QgsPointXY(35, 35), QgsPointXY(35, 25), QgsPointXY(25, 25)]

geometry1 = QgsGeometry.fromPolygonXY([coordinates1]) geometry2 = QgsGeometry.fromPolygonXY([coordinates2])

difference_geometry = geometry1.difference(geometry2)

result = QgsVectorLayer( f"?query=SELECT ST_GeomFromText('{difference_geometry.asWkt()}')", "result", "virtual" )

QgsProject.instance().addMapLayer(result)


References:

Taras
  • 32,823
  • 4
  • 66
  • 137