5

I'm writing a Plugin where you build networks with point and line geometries. One Tool should give the User the possibility to make changes to the network by dragging and dropping the points to another location. Since the points are sometimes connected to lines I want the vertex of the connected lines to the new location as well. I managed to write a tool that does exactly that, but if several line features are connected to the same point it fails and only drags one line. I tried looping through all the line features and thought it should work, but it still only moves one line and I don't know why.

Here a few pictures to illustrate my problem:

This is how the network could be made up This is how the network could be made up

changing one point with one line works as expected changing one point with one line works as expected changing the middle point fails changing the middle point fails

I wrote a maptool-class passing the QgsMapTool to it.

In the canvasPressEvent I call on two methods one looks for features and the other for vertices. if there are results i enable dragging and start editing. Here are the code parts where I think the problem might be in

def findVertexAt (self, pos):

    self.lineFeatures=[]
    self.vertices = []

    point = QgsPoint(self.canvas.getCoordinateTransform().toMapCoordinates(pos.x(), pos.y()))
    tolerance = self.calcTolerance(pos)
    searchRect = QgsRectangle(point.x() - tolerance,
                              point.y() - tolerance,
                              point.x() + tolerance,
                              point.y() + tolerance)
    request = QgsFeatureRequest()
    request.setFilterRect(searchRect)
    request.setFlags(QgsFeatureRequest.ExactIntersect)

    for feature in self.netLayer.getFeatures(request):
        self.lineFeatures.append(feature)
        i = 0 
        while i <= len(self.lineFeatures)-1:
            vertexCoord, vertex, prevVertex, nextVertex, distSquared = self.lineFeatures[i].geometry().closestVertex(QgsPointXY(point))  
            self.vertices.append(vertex)
            i = i + 1
        return self.vertices

def canvasMoveEvent(self, event):

    point = QgsPoint(self.canvas.getCoordinateTransform().toMapCoordinates(event.pos()))
    pointXY = QgsPointXY(point)

    if self.dragging:

        geometry = QgsGeometry.fromPointXY(pointXY)
        self.layer.changeGeometry(self.feature.id(),geometry)

        if self.lineDragging:
            i = 0
            while i <= len(self.lineFeatures)-1:
                lineGeometry = self.lineFeatures[i].geometry()
                lineGeometry.moveVertex(point, self.vertices[i])                     
                self.netLayer.changeGeometry(self.lineFeatures[i].id(), lineGeometry)
                i = i + 1

The canvasRelease event then just disables dragging and commits the changes

5

This can be done using QGIS tools that you can enable programmatically. That is, there is no need to reinvent the wheel.

Namely, you need to:

  1. Click on the Enable Topological Editing button in the Snapping toolbar.

    enter image description here

  2. Start the edit session on both your point and line layers.

  3. Click on Vertex Tool (All layers).

    enter image description here

This enables a tool that you can use to move a common vertex in both point and line layers, as you can see in this GIF:

enter image description here

The code to enable such tool would be:

QgsProject.instance().setTopologicalEditing(True)

points = QgsProject.instance().mapLayersByName('points')[0]
lines = QgsProject.instance().mapLayersByName('lines')[0]

points.startEditing()
lines.startEditing()

iface.layerTreeView().setCurrentLayer(points)
iface.actionVertexTool().trigger()

Hope this helps!

  • I didn't know about the vertexTool. I kind of liked my approach as it would still work if the plugin should be made in a standalone skript. Not sure if using the vertexTool would still work there. And the dragging and dropping seemed more intuitive as the click to pick up and click again to drop. So if anyone has another answer for my a little more complicaded uproach I'm still interested. – chrisd Sep 17 '18 at 8:56
0

Ok I fixed my original code so the Tool is working as I wanted. The problem I had with using the vertexTool is that it untoggles my custom maptool so I can not make use of certain key-Events or automatically commitChanges or Rollback etc. In the end it was just a simple indentation mistake that I somehow didn't see and today without working on that code for a week I suddently saw it.

Here is the Code to the FindVertexAt Method in case someone wants to use it for a similar Project.

def findVertexAt (self, pos):

    self.lineFeatures=[]
    self.vertices = []

    point = QgsPoint(self.canvas.getCoordinateTransform().toMapCoordinates(pos.x(), pos.y()))
    tolerance = self.calcTolerance(pos)
    searchRect = QgsRectangle(point.x() - tolerance,
                              point.y() - tolerance,
                              point.x() + tolerance,
                              point.y() + tolerance)
    request = QgsFeatureRequest()
    request.setFilterRect(searchRect)
    request.setFlags(QgsFeatureRequest.ExactIntersect)

    for feature in self.netLayer.getFeatures(request):
        self.lineFeatures.append(feature)
    for feature in self.lineFeatures:
        vertexCoord, vertex, prevVertex, nextVertex, distSquared = feature.geometry().closestVertex(QgsPointXY(point))  
        self.vertices.append(vertex)

    return self.vertices

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.