8

I am looking for a PyQGIS 3 method for reversing the direction of a MultiLineString feature. If there is more than one part, the order of the parts should be reversed.

I have found a similar question - Switching line direction in QGIS - for LineString/Polyline - which only works for QGIS 2 - and modified it slightly for use in QGIS 3.

However, I can't work out how to adapt the approach for MultiLineStrings.

from qgis.utils import iface
from qgis.core import QgsGeometry

layer = qgis.utils.iface.mapCanvas().currentLayer()
feature = layer.getFeature(1) # feature id
geom = feature.geometry()
nodes = geom.asPolyline()
nodes.reverse() 
newgeom = QgsGeometry.fromPolylineXY(nodes)
layer.startEditing()
layer.changeGeometry(feature.id(), newgeom)
layer.commitChanges()

In theory, the above approach could be used with

newgeom = QgsGeometry.fromMultiPolylineXY(<QgsMultiPolylineXY>)

but I can't see how to generate the necessary QgsMultiPolylineXY object.

I have also noted the reversed() function on the QGSMultiLineCurve class, but I couldn't attach the generated GSMultiLineCurve to the original feature.

I'm not interested in UI-based approaches, as the features to be reversed are determined programmatically.

2
  • Do you also want to re-order the parts of multiline so that line1-line2-line3 would become line3reversed-line2reversed-line1reversed?
    – user30184
    Commented Mar 1, 2019 at 7:10
  • @user30184 - yes, have added clarification to the question. Commented Mar 1, 2019 at 8:29

1 Answer 1

11

I will focus on the geometry creation part, because the feature editing part is fully explained in many places, including the example inside the question.

I will use some Python list comprehension, but the key here is the use of the QgsAbstractGeometry type QgsMultiLineString, which is iterable and converts easily from/to list type.

From the QGIS API, you will see that each QgsGeometry is a container for the "real" QgsAbstractGeometry:

A geometry is the spatial representation of a feature. Since QGIS 2.10, QgsGeometry acts as a generic container for geometry objects. QgsGeometry is implicitly shared, so making copies of geometries is inexpensive. The geometry container class can also be stored inside a QVariant object.

The actual geometry representation is stored as a QgsAbstractGeometry within the container, and can be accessed via the get() method or set using the set() method.

#First, will create an example multilinestring geometry
lines = [[[0,0],[1,1],[2,2]],[[0,1],[1,2],[2,3]],[[0,2],[1,3],[2,4]]]
mls = QgsMultiLineString()
for i in [QgsLineString([QgsPoint(x,y) for x,y in i]) for i in lines]:
    _ = mls.addGeometry(i)

old_geometry = QgsGeometry(mls)

# QgsGeometry can be converted to QgsAbstractGeometry with the
# .get() method, so the real example begins HERE:

mls1 = old_geometry.get()
mls2 = QgsMultiLineString()
# For each reversed linestring, visited in reverse order
for i in [QgsLineString([*i][::-1]) for i in [*mls1][::-1]]:
    _ = mls2.addGeometry(i) # add it to new geometry

new_geometry = QgsGeometry(mls2)
old_geometry
#[out]: <QgsGeometry: MultiLineString ((0 0, 1 1, 2 2),(0 1, 1 2, 2 3),(0 2, 1 3, 2 4))>
new_geometry
#[out]: <QgsGeometry: MultiLineString ((2 4, 1 3, 0 2),(2 3, 1 2, 0 1),(2 2, 1 1, 0 0))>

Note here, that QgsMultiLineString objects are iterable so, you can expand it to a list of LineStrings using [*list] Python syntax.

In the developer forum, they say it is recommended to use QgsMultiLineString, QgsLineString, QgsPoint,... etc when creating geometries, one advantage is the easy conversion from/to list conversion.

One thing to be aware of is that if you are using existing features, rather than a newly created one as per the example above, don't try to shortcut the "cloning" process. Given a feature f, use, for example:

geom = f.geometry()
mls1 = geom.get()

rather than

mls1 = f.geometry().get()

Otherwise, you will get a crash due to Python garbage collectin.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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