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())
Dave X
  • 1,639
  • 13
  • 25
  • 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 http://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

1 Answers1

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)
vinayan
  • 7,282
  • 3
  • 37
  • 75
  • 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 04: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 05:29
  • My motivation is the same specified distance redistributing-vertices use-case as in http://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 06:00
  • @DaveX updated my answer. It is not tested. I think it would work. – vinayan Jul 30 '14 at 07:55
  • combine looks like it would merge the parts, losing their individual identities. I don't want them merged into one, I want a new multipart geometry. – Dave X Aug 01 '14 at 19:49
  • @DaveX combining disjoint geometries would only produce multipart geometries as I have done in the code? Have you ever tested whether this would work for you? – vinayan Aug 04 '14 at 06:05