2

My example use-case is that I want to redistribute vertices along lines as in:

I've written some functions to do some of the work:

import math

def redistribute_vertices_num(line,num):
    return LineString([line.interpolate(i/float(num),normalized=True) for i in range(num+1)]) 

def redistribute_vertices_dist(line,dist):
    return LineString([line.interpolate(i*float(dist)) for i in range(int(math.ceil(line.length/dist)))])

I would like to apply these functions (or other, modified functions) to the selected objects in the current layer to modify the layer. I'm looking for a general function like this:

edit_layer_selection_geometry(redistribute_vertices_dist,500)
# or 
def my_function(line):
    redistribute_vertices_dist(line,500)
edit_layer_selection_geometry(my_function)

...that might do something like the processing in How can I create a line with three points with Python in QGIS? or How can I switch line direction in QGIS? on the active layer with the user-defined function.

def edit_layer_selection_geometry(myfun, extra_arguments...):
    layer = qgis.utils.iface.mapCanvas().currentLayer()
    # check for selected_layer, editability ?
    for feature in layer.selectedFeatures():
        newgeom=myfun(feature,extra_arguments)
        # update feature with geometry
        layer.changeGeometry(feature.id(),newgeom)
    ...
    # update layer stuff (extents?)

I'm looking for the edit_layer_selection_geometry() or an equivalent functionality, and I'm happy to modify the potential 'myfun' functions to fit requirements of the general function.

I've put this in my .qgis2/mycode.py directory:

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



def redistribute_geometry_vertices(geom,dist):
    mylen=geom.length()
    line=geom.asPolyline()
    return QgsGeometry.fromPolyline([geom.interpolate(i*float(dist)).asPoint() for i in range(int(math.ceil(mylen/dist)))])

def redistribute_selection(dist):
    """Redistribute the vertices along a polyline """
    layer = iface.mapCanvas().currentLayer()
    for feature in layer.selectedFeatures():
        geom = feature.geometry()
        newgeom=redistribute_geometry_vertices(geom,dist)
        layer.changeGeometry(feature.id(),newgeom)

Then I can solve the use-case by selecting the layer and feature, opening the python console and typing:

import mycode
mycode.redistribute_selection(0.1)
1
  • 1
    Since the 2.x version, PyQGIS has an interpolate function: point = line.interpolate(distance) so you no longer need the Shapely module.
    – gene
    Commented Jul 22, 2014 at 16:03

1 Answer 1

3

I modified the redistribute_selection() function above to make ~/.qgis2/python/mytools.py :

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

def redistribute_geometry_vertices(geom,dist):
    mylen=geom.length()
    line=geom.asPolyline()
    return QgsGeometry.fromPolyline([geom.interpolate(i).asPoint() for i in numpy.arange(0,mylen+dist,dist)])

def redistribute_geometry_vertices_num(geom,num):
    mylen=geom.length()
    line=geom.asPolyline()
    return QgsGeometry.fromPolyline([geom.interpolate(i).asPoint() for i in numpy.linspace(0,mylen,num)])



def reverseGeometryVertices(geom):
    nodes = geom.asPolyline()
    nodes.reverse() 
    return  QgsGeometry.fromPolyline(nodes)

def selection_update_geometry(userFunction, *args):
    """Redistribute the vertices along a polyline """
    layer = iface.mapCanvas().currentLayer()
    for feature in layer.selectedFeatures():
        geom = feature.geometry()
        if geom.isMultipart():
            newgeom = QgsGeometry.fromMultiPolyline([userFunction(part,*args).asPolyline() for part in geom.asGeometryCollection()])
        else:
            newgeom=userFunction(geom,*args)
        layer.changeGeometry(feature.id(),newgeom)
        iface.mapCanvas().refresh()

Then I can type:

import mytools
mytools.selection_update_geometry(mytools.redistribute_geometry_vertices,.05)
mytools.selection_update_geometry(mytools.redistribute_geometry_vertices_num,5)
mytools.selection_update_geometry(mytools.reverseGeometryNodes)

enter image description here

There isn't any error handling in these functions (like checking if a layer is selected, editable, that the feature is a line, or that the user-supplied function returns compatible geometry) but they make it fairly easy to modify the geometry.

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.