2

What is the inverse operation of QgsGeometry.asGeometryCollection() as documented here: http://qgis.org/api/classQgsGeometry.html#a7cb1cbf8cfa441456067a66ad3a25a94

I'd like to do something like:

from qgis.core import (QgsFeature, QgsGeometry,
                   QgsVectorLayer, QgsMapLayerRegistry,
                   QgsField)
from PyQt4.QtCore import QVariant
from qgis.utils import iface
import math


def myFunction(arg):
    return arg

layer=iface.mapCanvas().currentLayer()
feature = layer.selectedFeatures()[0]
geom = feature.geometry()
if geom.isMultipart():
    newgeom=QgsGeometry.INVERSE([myFunction(part) for part in geom.asGeometryCollection ()])
else:
    newgeom=myFunction(geom)
changeGeometry(feature.id(),newgeom)

Things that do not work:

# doesn't work:
newgeom=QgsGeometry.combine([part for part in geom.asGeometryCollection ()])
# doesn't work:
newgeom=([part for part in geom.asGeometryCollection ()])
# doesn't work:
newgeom = [part for part in geom.asGeometryCollection()]
# doesn't work: argument 1 has unexpected type 'list'
newgeom = QgsGeometry.fromPolyline([part for part in geom.asGeometryCollection()])
# QgsGeometry has no attribute 'MultiPolyline': 
newgeom = QgsGeometry.MultiPolyline([part for part in geom.asGeometryCollection()])
# MuliPolyline is not defined: 
newgeom = MultiPolyline([part for part in geom.asGeometryCollection()])
newgeom = QgsGeometry.fromMultiPolyline([part for part in geom.asGeometryCollection()])
newgeom = QgsGeometry.fromMultiPolyline([part.asPolyline for part in geom.asGeometryCollection()])

newgeom = QgsGeometry.fromMultiPolyline([part.asPolyline for part in geom])
newgeom = QgsGeometry.fromMultiPolyline([part.asPolyline for part in geom.asMultiPolyline()])

Works with Polylines / LineStrings:

newgeom = QgsGeometry.fromMultiPolyline([part for part in geom.asMultiPolyline()])

newgeom = QgsGeometry.fromMultiPolyline([userFunction(part,*args).asPolyline() for part in geom.asGeometryCollection()])

http://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/geometry.html has some documentation on accessing and creating the various types. http://qgis.org/api/classQGis.html lists the enumerations of WKB* types and plain geometry types.

It appears that each multipart type must be treated separately, and the multi-* types can't be disassembled and reassembled generally. In other words, you need to spell out and process the individual geometries separately like:

parts = ([userFunction(part,*args) for part in geom.asGeometryCollection()])

if geom.wkbType() == Qgis.WKBMultiLineString: 
    newgeom= QgsGeometry.fromMultiPolyline([x.asPolyline() for x in parts])
elif geom.wkbType() == QGis.WKBMultiPolygon:
    newgeom= QgsGeometry.fromMultiPolygon([x.asPolygon() for x in parts])
elif geom.wkbType() == QGis.WKBLineString25D:
    newgeom= QgsGeometry.fromMultiPolyline25D([x.asPolyline25D() for x in parts])
elif geom.wkbType() == QGis.WKBMultiPolygon25D:
    newgeom= QgsGeometry.fromMultiPolygon25D([x.asPolygon25D() for x in parts])
...

layer.changeGeometry(feature.id(),newgeom)

Is there a function or combination of functions that would simplify the above? Something like:

newgeom = CAST_AS_GEOMETRY_TYPE([part for part in geom.asGeometryCollection()],geom.WKBType())
  • A GeometryCollection is an heterogeneous collections of geometric objects (line, points, polygons) so what is the purpose ? – gene Jul 24 '14 at 19:56
  • I'd like to process the lines within a selected multi-part polyline separately. My motivating example is in gis.stackexchange.com/a/108243/10229 – Dave X Jul 24 '14 at 20:03
  • a multi-part polyline is a MultiLineString (or list of LineStrings) and all you need to do is iterate over the MultiLineString – gene Jul 24 '14 at 20:08
  • in PyQGIS, it is MultiPolyline (list of Polylines) – gene Jul 24 '14 at 20:24
  • Can you point me toward MultiPolyline documentation? The list of objects returned by asGeometryCollection does not appear to be a list of Polylines. – Dave X Jul 24 '14 at 20:38
2

QgsVectorLayer.changeGeometry function can be used to update the geometry after combining the manipulated geometries to form a single geometry.

if geom.isMultipart():
    geomColl = geom.asGeometryCollection()
    tempGeom = QgsGeometry()
    for g in geomColl:  #g is QgsGeometry
        g2 = reverseDirection(g) # your function to manipulate the geometry
        tempGeom = tempGeom.combine(g2);
    layer.changeGeometry(feature.id(),tempGeom)
  • After I iterate, I then want to re-collect the list of paert into a type-conformant replacement for the original geometry. It appears that you can take apart all types of .isMultipart()==True geometries with .asGeometryCollection(), but you can't re-collect them with something like geom.replaceGeometry(geomColl). – Dave X Jul 25 '14 at 13:24
  • @DaveX so u want to make your multipart geometry to be replaced with a single part geometry? Suppose u have 3 parts for a geometry. You will need to create 3 new features(or 2 new and replace existing multigeom with one geom) to accomplish your task. I am not really clear what your correct requirement is. – vinayan Jul 29 '14 at 4:20
  • No, I do not want to replace the multipart with a set of component parts (like 'explode' ungroup, or multi-to-single). I want to unpack the multigeom into its component parts, apply a user-defined function (in the Q, myFunction() is an identity function as a , but a function like reverse_line(), densify(), simplify()) to the parts to make a set of new parts, then re-pack the new parts into a new, replacement multigeom to use as a replacement. In your answer, how do I append each g.exportToWkt() into a list, and convert the list back into a multipart geometry of the same type as geom? – Dave X Jul 30 '14 at 5:29
  • My motivation is the same specified distance redistributing-vertices use-case as in gis.stackexchange.com/q/107999/10229 but I'd like to know how to write things to deal with polygons, and potentially 2.5D polygons and polylines as well. (Ultimately, I need to redistribute the vertices unevenly, based on a raster or some function of a raster, but that's for later.) – Dave X Jul 30 '14 at 6:00
  • @DaveX updated my answer. It is not tested. I think it would work. – vinayan Jul 30 '14 at 7:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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