class QGISRedSelectPointTool(QgsMapTool): def __init__(self, button, parent, method, type=1): QgsMapTool.__init__(self, parent.iface.mapCanvas()) self.canvas = parent.iface.mapCanvas() self.iface = parent.iface self.parent = parent self.method = method self.setAction(button) self.type = type # type 1: points; 2: lines; 3: 2-points; 4: 2-line; 5: point-line self.startMarker = QgsVertexMarker(self.iface.mapCanvas()) self.startMarker.setColor(QColor(255, 87, 51)) if self.type == 3 or self.type == 4 or self.type == 5: self.startMarker.setColor(QColor(139, 0, 0)) self.startMarker.setIconSize(15) self.startMarker.setIconType( QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X if self.type == 2 or self.type == 4: self.startMarker.setIconType( QgsVertexMarker.ICON_X) # or ICON_CROSS, ICON_X self.startMarker.setPenWidth(3) self.startMarker.hide() self.endMarker = QgsVertexMarker(self.iface.mapCanvas()) self.endMarker.setColor(QColor(0, 128, 0)) self.endMarker.setIconSize(15) self.endMarker.setIconType( QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X if self.type == 4 or self.type == 5: self.endMarker.setIconType( QgsVertexMarker.ICON_X) # or ICON_CROSS, ICON_X self.endMarker.setPenWidth(3) self.endMarker.hide() self.firstPoint = None self.snapper = None self.resetProperties() def activate(self): QgsMapTool.activate(self) type = 1 if self.type == 2 or self.type == 4: type = 2 self.configSnapper(type) def deactivate(self): self.resetProperties() QgsMapTool.deactivate(self) def isZoomTool(self): return False def isTransient(self): return False def isEditTool(self): return True """Methods""" def configSnapper(self, type): # Snapping self.snapper = QgsMapCanvasSnappingUtils(self.iface.mapCanvas()) self.snapper.setMapSettings(self.iface.mapCanvas().mapSettings()) config = QgsSnappingConfig(QgsProject.instance()) config.setType(type) # 1: Vertex; 2:Segment config.setMode(2) # All layers config.setTolerance(10) config.setUnits(1) # Pixels config.setEnabled(True) self.snapper.setConfig(config) def resetProperties(self): self.firstPoint = None self.startMarker.hide() self.endMarker.hide() self.objectSnapped = None """Events""" def canvasReleaseEvent(self, event): if event.button() == Qt.LeftButton: if self.objectSnapped is None: self.iface.messageBar().pushMessage( "Warning", "A not valid point was selected", level=1, duration=5) return if self.type == 3 or self.type == 4 or self.type == 5: if self.firstPoint is None: self.firstPoint = self.objectSnapped.point() if self.type == 5: self.configSnapper(2) else: point1 = self.firstPoint point2 = self.objectSnapped.point() # Call to parent method self.method(point1, point2) self.resetProperties() if self.type == 5: self.configSnapper(1) else: point = self.objectSnapped.point() # Call to parent method self.method(point) self.resetProperties() if event.button() == Qt.RightButton: if self.type == 3 or self.type == 5: if self.objectSnapped is None: self.iface.messageBar().pushMessage( "Warning", "A not valid point was selected", level=1, duration=5) return else: point = self.objectSnapped.point() # Call to parent method # Tconnection & Split/merge Juncitons self.method(point, None) self.resetProperties() else: self.canvas.unsetMapTool(self) self.deactivate() return def canvasMoveEvent(self, event): match = self.snapper.snapToMap(self.toMapCoordinates(event.pos())) if match.isValid(): self.objectSnapped = match if self.firstPoint is None: self.startMarker.setCenter( QgsPointXY(match.point().x(), match.point().y())) self.startMarker.show() else: self.endMarker.setCenter( QgsPointXY(match.point().x(), match.point().y())) self.endMarker.show() else: self.startMarker.hide() self.endMarker.hide() self.objectSnapped = None
class QGISRedEditLinksGeometryTool(QgsMapTool): ownMainLayers = ["Pipes", "Valves", "Pumps", "ServiceConnections"] def __init__(self, button, iface, projectDirectory, netwName): QgsMapTool.__init__(self, iface.mapCanvas()) self.iface = iface self.ProjectDirectory = projectDirectory self.NetworkName = netwName self.toolbarButton = button self.snapper = None self.vertexMarker = QgsVertexMarker(self.iface.mapCanvas()) self.vertexMarker.setColor(QColor(255, 87, 51)) self.vertexMarker.setIconSize(15) self.vertexMarker.setIconType( QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X self.vertexMarker.setPenWidth(3) self.vertexMarker.hide() self.pipeSnapper = None self.pipeMarker = QgsVertexMarker(self.iface.mapCanvas()) self.pipeMarker.setColor(QColor(143, 0, 255)) self.pipeMarker.setIconSize(10) try: self.pipeMarker.setIconType( QgsVertexMarker.ICON_DOUBLE_TRIANGLE) # or ICON_CROSS, ICON_X except: self.pipeMarker.setIconType( QgsVertexMarker.ICON_X) # or ICON_CROSS, ICON_X self.pipeMarker.setPenWidth(3) self.pipeMarker.hide() self.mouseClicked = False self.clickedPoint = None self.objectSnapped = None self.pipeSnapped = None self.selectedFeature = None self.selectedLayer = None self.newPositionVector = QgsVector(0, 0) self.rubberBand = None self.newVertexMarker = QgsVertexMarker(self.iface.mapCanvas()) self.newVertexMarker.setColor(QColor(55, 198, 5)) self.newVertexMarker.setIconSize(15) self.newVertexMarker.setIconType( QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X self.newVertexMarker.setPenWidth(3) self.newVertexMarker.hide() def activate(self): cursor = QCursor() cursor.setShape(Qt.ArrowCursor) self.iface.mapCanvas().setCursor(cursor) myLayers = [] # Editing layers = self.getLayers() for layer in layers: openedLayerPath = self.getLayerPath(layer) for name in self.ownMainLayers: layerPath = self.generatePath( self.ProjectDirectory, self.NetworkName + "_" + name + ".shp") if openedLayerPath == layerPath: myLayers.append(layer) if not layer.isEditable(): layer.startEditing() # Snapping self.snapper = QgsMapCanvasSnappingUtils(self.iface.mapCanvas()) self.snapper.setMapSettings(self.iface.mapCanvas().mapSettings()) config = QgsSnappingConfig(QgsProject.instance()) config.setType(2) # Vertex config.setMode(2) # All layers config.setTolerance(10) config.setUnits(1) # Pixels config.setEnabled(True) self.snapper.setConfig(config) self.pipeSnapper = QgsMapCanvasSnappingUtils(self.iface.mapCanvas()) self.pipeSnapper.setMapSettings(self.iface.mapCanvas().mapSettings()) config = QgsSnappingConfig(QgsProject.instance()) config.setType(2) # Vertex config.setMode(2) # All layers config.setTolerance(10) config.setUnits(1) # Pixels config.setEnabled(True) self.pipeSnapper.setConfig(config) def deactivate(self): self.toolbarButton.setChecked(False) # End Editing layers = self.getLayers() for layer in layers: openedLayerPath = self.getLayerPath(layer) for name in self.ownMainLayers: layerPath = self.generatePath( self.ProjectDirectory, self.NetworkName + "_" + name + ".shp") if openedLayerPath == layerPath: if layer.isModified(): layer.commitChanges() else: layer.rollBack() def isZoomTool(self): return False def isTransient(self): return False def isEditTool(self): return True """Methods""" def getUniformedPath(self, path): return QGISRedUtils().getUniformedPath(path) def getLayerPath(self, layer): return QGISRedUtils().getLayerPath(layer) def generatePath(self, folder, fileName): return QGISRedUtils().generatePath(folder, fileName) def getLayers(self): return QGISRedUtils().getLayers() def areOverlapedPoints(self, point1, point2): tolerance = 0.1 if point1.distance(point2) < tolerance: return True else: return False def isInPath(self, point1, point2, myPoint): width = point2.x() - point1.x() height = point2.y() - point1.y() widthM = myPoint.x() - point1.x() heightM = myPoint.y() - point1.y() if abs(width) >= abs(height): yEst = widthM * height / width + point1.y() if abs(yEst - myPoint.y()) < 1E-9: return True else: xEst = heightM * width / height + point1.x() if abs(xEst - myPoint.x()) < 1E-9: return True return False def createRubberBand(self, points): myPoints = points if isinstance(points[0], QgsPointXY): myPoints = [] for p in points: myPoints.append(QgsPoint(p.x(), p.y())) self.rubberBand = QgsRubberBand(self.iface.mapCanvas(), False) self.rubberBand.setToGeometry(QgsGeometry.fromPolyline(myPoints), None) self.rubberBand.setColor(QColor(55, 198, 5)) self.rubberBand.setWidth(1) self.rubberBand.setLineStyle(Qt.DashLine) self.newVertexMarker.setCenter(QgsPointXY(points[0].x(), points[0].y())) self.newVertexMarker.show() def updateRubberBand(self): newX = self.clickedPoint.x() + self.newPositionVector.x() newY = self.clickedPoint.y() + self.newPositionVector.y() self.rubberBand.movePoint(1, QgsPointXY(newX, newY)) self.newVertexMarker.setCenter(QgsPointXY(newX, newY)) def moveVertexLink(self, layer, feature, newPosition, vertexIndex): if layer.isEditable(): layer.beginEditCommand("Update link geometry") try: edit_utils = QgsVectorLayerEditUtils(layer) edit_utils.moveVertex(newPosition.x(), newPosition.y(), feature.id(), vertexIndex) except Exception as e: layer.destroyEditCommand() raise e layer.endEditCommand() def deleteVertexLink(self, layer, feature, vertexIndex): if layer.isEditable(): layer.beginEditCommand("Update link geometry") try: edit_utils = QgsVectorLayerEditUtils(layer) edit_utils.deleteVertex(feature.id(), vertexIndex) except Exception as e: layer.destroyEditCommand() raise e layer.endEditCommand() def insertVertexLink(self, layer, feature, newPoint): if layer.isEditable(): layer.beginEditCommand("Update link geometry") vertex = -1 if layer.geometryType() == 1: # Line featureGeometry = self.selectedFeature.geometry() if featureGeometry.isMultipart(): parts = featureGeometry.get() for part in parts: # only one part for i in range(len(part) - 1): if self.isInPath( QgsPointXY(part[i].x(), part[i].y()), QgsPointXY(part[i + 1].x(), part[i + 1].y()), newPoint): vertex = i + 1 try: edit_utils = QgsVectorLayerEditUtils(layer) edit_utils.insertVertex(newPoint.x(), newPoint.y(), feature.id(), vertex) except Exception as e: layer.destroyEditCommand() raise e layer.endEditCommand() """Events""" def canvasPressEvent(self, event): if self.objectSnapped is None: self.clickedPoint = None return if event.button() == Qt.RightButton: self.mouseClicked = False self.clickedPoint = None if event.button() == Qt.LeftButton: self.clickedPoint = self.objectSnapped.point() if self.vertexIndex == -1: return self.mouseClicked = True self.createRubberBand( [self.objectSnapped.point(), self.objectSnapped.point()]) def canvasMoveEvent(self, event): mousePoint = self.toMapCoordinates(event.pos()) # Mouse not clicked if not self.mouseClicked: self.pipeSnappedOn = False matchSnapper = self.snapper.snapToMap(mousePoint) if matchSnapper.isValid(): valid = False layer = matchSnapper.layer() snapLayerPath = self.getLayerPath(layer) for name in self.ownMainLayers: layerPath = self.generatePath( self.ProjectDirectory, self.NetworkName + "_" + name + ".shp") if snapLayerPath == layerPath: valid = True if valid: self.objectSnapped = matchSnapper self.selectedLayer = layer vertex = matchSnapper.point() featureId = matchSnapper.featureId() request = QgsFeatureRequest().setFilterFid(featureId) nodes = list(layer.getFeatures(request)) self.selectedFeature = QgsFeature(nodes[0]) # #Ver aquí si es el nudo inicial y final middleNode = False self.vertexIndex = -1 if layer.geometryType() == 1: # Line featureGeometry = self.selectedFeature.geometry() if featureGeometry.isMultipart(): parts = featureGeometry.get() for part in parts: # only one part if middleNode: break i = -1 for v in part: i = i + 1 if ( i == 0 or i == len(part) - 1 ) and "ServiceConnections" not in snapLayerPath: continue matchedPoint = QgsPointXY( vertex.x(), vertex.y()) if self.areOverlapedPoints( QgsGeometry.fromPointXY( matchedPoint), QgsGeometry.fromPointXY( QgsPointXY(v.x(), v.y()))): middleNode = True self.vertexIndex = i if ( i == 0 or i == len(part) - 1 ) and "ServiceConnections" in snapLayerPath: self.pipeSnappedOn = True break if middleNode: self.vertexMarker.setCenter( QgsPointXY(vertex.x(), vertex.y())) self.vertexMarker.show() else: self.vertexMarker.hide() else: self.objectSnapped = None self.selectedFeature = None self.selectedLayer = None self.vertexMarker.hide() else: self.objectSnapped = None self.selectedFeature = None self.selectedLayer = None self.vertexMarker.hide() # Mouse clicked else: # Snap pipe layer if self.pipeSnappedOn: matchSnapper = self.pipeSnapper.snapToMap(mousePoint) if matchSnapper.isValid(): valid = False layer = matchSnapper.layer() snapLayerPath = self.getLayerPath(layer) for name in self.ownMainLayers: layerPath = self.generatePath( self.ProjectDirectory, self.NetworkName + "_Pipes.shp") if snapLayerPath == layerPath: valid = True if valid: self.pipeSnapped = matchSnapper self.pipeMarker.setCenter(matchSnapper.point()) self.pipeMarker.show() else: self.pipeMarker.hide() else: self.pipeMarker.hide() self.pipeSnapped = None # # Update rubber band if self.objectSnapped is not None and self.rubberBand is not None: snappedPoint = self.objectSnapped.point() self.newPositionVector = QgsVector( mousePoint.x() - snappedPoint.x(), mousePoint.y() - snappedPoint.y()) self.updateRubberBand() def canvasReleaseEvent(self, event): if self.mouseClicked: if event.button() == 1: mousePoint = self.toMapCoordinates(event.pos()) if (self.pipeSnapped is not None): mousePoint = self.pipeSnapped.point() self.mouseClicked = False if self.objectSnapped is not None: self.moveVertexLink(self.selectedLayer, self.selectedFeature, mousePoint, self.vertexIndex) elif event.button() == 2: if self.objectSnapped is not None: self.deleteVertexLink(self.selectedLayer, self.selectedFeature, self.vertexIndex) elif event.button() == 1: if self.objectSnapped is not None: self.insertVertexLink(self.selectedLayer, self.selectedFeature, self.objectSnapped.point()) self.objectSnapped = None self.pipeSnapped = None self.selectedFeature = None self.selectedLayer = None self.vertexIndex = -1 self.iface.mapCanvas().refresh() # Remove vertex marker and rubber band self.vertexMarker.hide() self.iface.mapCanvas().scene().removeItem(self.rubberBand) self.newVertexMarker.hide() self.pipeMarker.hide()
class QGISRedCreatePipeTool(QgsMapTool): def __init__(self, button, iface, projectDirectory, netwName, parent): QgsMapTool.__init__(self, iface.mapCanvas()) self.iface = iface self.ProjectDirectory = projectDirectory self.NetworkName = netwName self.parent = parent self.setAction(button) self.startMarker = QgsVertexMarker(self.iface.mapCanvas()) self.startMarker.setColor(QColor(255, 87, 51)) self.startMarker.setIconSize(15) self.startMarker.setIconType( QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X self.startMarker.setPenWidth(3) self.startMarker.hide() self.endMarker = QgsVertexMarker(self.iface.mapCanvas()) self.endMarker.setColor(QColor(255, 87, 51)) self.endMarker.setIconSize(15) self.endMarker.setIconType( QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X self.endMarker.setPenWidth(3) self.endMarker.hide() self.snapper = None self.rubberBand1 = None self.rubberBand2 = None self.resetProperties() def activate(self): QgsMapTool.activate(self) # Snapping self.snapper = QgsMapCanvasSnappingUtils(self.iface.mapCanvas()) self.snapper.setMapSettings(self.iface.mapCanvas().mapSettings()) config = QgsSnappingConfig(QgsProject.instance()) config.setType(1) # Vertex config.setMode(2) # All layers config.setTolerance(2) config.setUnits(2) # Pixels config.setEnabled(True) self.snapper.setConfig(config) def deactivate(self): self.resetProperties() QgsMapTool.deactivate(self) def isZoomTool(self): return False def isTransient(self): return False def isEditTool(self): return True """Methods""" def resetProperties(self): # self.toolbarButton.setChecked(False) if self.rubberBand1 is not None: self.iface.mapCanvas().scene().removeItem(self.rubberBand1) if self.rubberBand2 is not None: self.iface.mapCanvas().scene().removeItem(self.rubberBand2) self.startMarker.hide() self.endMarker.hide() self.mousePoints = [] self.firstClicked = False self.objectSnapped = None self.rubberBand1 = None self.rubberBand2 = None def createRubberBand(self, points): myPoints1 = [] for p in points: myPoints1.append(QgsPoint(p.x(), p.y())) myPoints1.remove(myPoints1[-1]) if self.rubberBand1 is not None: self.iface.mapCanvas().scene().removeItem(self.rubberBand1) self.rubberBand1 = QgsRubberBand(self.iface.mapCanvas(), False) self.rubberBand1.setToGeometry(QgsGeometry.fromPolyline(myPoints1), None) self.rubberBand1.setColor(QColor(240, 40, 40)) self.rubberBand1.setWidth(1) self.rubberBand1.setLineStyle(Qt.SolidLine) myPoints2 = [] myPoints2.append(QgsPoint(points[-2].x(), points[-2].y())) myPoints2.append(QgsPoint(points[-1].x(), points[-1].y())) if self.rubberBand2 is not None: self.iface.mapCanvas().scene().removeItem(self.rubberBand2) self.rubberBand2 = QgsRubberBand(self.iface.mapCanvas(), False) self.rubberBand2.setToGeometry(QgsGeometry.fromPolyline(myPoints2), None) self.rubberBand2.setColor(QColor(240, 40, 40)) self.rubberBand2.setWidth(1) self.rubberBand2.setLineStyle(Qt.DashLine) """Events""" def canvasPressEvent(self, event): if event.button() == Qt.LeftButton: if not self.firstClicked: self.firstClicked = True point = self.toMapCoordinates(event.pos()) if self.objectSnapped is not None: point = self.objectSnapped.point() self.mousePoints.append(point) self.mousePoints.append(point) else: self.mousePoints.append(self.mousePoints[-1]) self.createRubberBand(self.mousePoints) if event.button() == Qt.RightButton: self.mousePoints.remove(self.mousePoints[-1]) if self.firstClicked: if (len(self.mousePoints) == 2 and self.mousePoints[0] == self.mousePoints[1]): createdPipe = False elif len(self.mousePoints) < 2: createdPipe = False else: createdPipe = True if createdPipe: self.parent.runCreatePipe(self.mousePoints) self.resetProperties() def canvasMoveEvent(self, event): # Mouse not clicked if not self.firstClicked: match = self.snapper.snapToMap(self.toMapCoordinates(event.pos())) if match.isValid(): self.objectSnapped = match self.startMarker.setCenter( QgsPointXY(match.point().x(), match.point().y())) self.startMarker.show() else: self.objectSnapped = None self.startMarker.hide() # Mouse clicked else: point = self.toMapCoordinates(event.pos()) match = self.snapper.snapToMap(point) if match.isValid(): self.objectSnapped = match self.endMarker.setCenter( QgsPointXY(match.point().x(), match.point().y())) self.endMarker.show() self.mousePoints[-1] = match.point() else: self.objectSnapped = None self.endMarker.hide() self.mousePoints[-1] = point self.createRubberBand(self.mousePoints)
class QGISRedMoveNodesTool(QgsMapTool): ownMainLayers = [ "Pipes", "Valves", "Pumps", "Junctions", "Tanks", "Reservoirs", "Demands", "Sources" ] myNodeLayers = ["Junctions", "Tanks", "Reservoirs", "Demands", "Sources"] def __init__(self, button, iface, projectDirectory, netwName): QgsMapTool.__init__(self, iface.mapCanvas()) self.iface = iface self.ProjectDirectory = projectDirectory self.NetworkName = netwName self.toolbarButton = button self.snapper = None self.vertexMarker = QgsVertexMarker(self.iface.mapCanvas()) self.vertexMarker.setColor(QColor(255, 87, 51)) self.vertexMarker.setIconSize(15) self.vertexMarker.setIconType( QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X self.vertexMarker.setPenWidth(3) self.vertexMarker.hide() self.mousePoint = None self.mouseClicked = False self.clickedPoint = None self.objectSnapped = None self.selectedNodeFeature = None self.selectedNodeLayer = None self.adjacentFeatures = None self.newPositionVector = QgsVector(0, 0) self.rubberBand = None self.newVertexMarker = QgsVertexMarker(self.iface.mapCanvas()) self.newVertexMarker.setColor(QColor(55, 198, 5)) self.newVertexMarker.setIconSize(15) self.newVertexMarker.setIconType( QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X self.newVertexMarker.setPenWidth(3) self.newVertexMarker.hide() def activate(self): cursor = QCursor() cursor.setShape(Qt.ArrowCursor) self.iface.mapCanvas().setCursor(cursor) myLayers = [] # Editing layers = self.getLayers() for layer in layers: openedLayerPath = self.getLayerPath(layer) for name in self.ownMainLayers: layerPath = self.generatePath( self.ProjectDirectory, self.NetworkName + "_" + name + ".shp") if openedLayerPath == layerPath: myLayers.append(layer) if not layer.isEditable(): layer.startEditing() # Snapping self.snapper = QgsMapCanvasSnappingUtils(self.iface.mapCanvas()) self.snapper.setMapSettings(self.iface.mapCanvas().mapSettings()) config = QgsSnappingConfig(QgsProject.instance()) config.setType(1) # Vertex config.setMode(2) # All layers config.setTolerance(1) config.setUnits(2) # Pixels config.setEnabled(True) self.snapper.setConfig(config) def deactivate(self): self.toolbarButton.setChecked(False) # End Editing layers = self.getLayers() for layer in layers: openedLayerPath = self.getLayerPath(layer) for name in self.ownMainLayers: layerPath = self.generatePath( self.ProjectDirectory, self.NetworkName + "_" + name + ".shp") if openedLayerPath == layerPath: if layer.isModified(): layer.commitChanges() else: layer.rollBack() def isZoomTool(self): return False def isTransient(self): return False def isEditTool(self): return True """Methods""" def getUniformedPath(self, path): return QGISRedUtils().getUniformedPath(path) def getLayerPath(self, layer): return QGISRedUtils().getLayerPath(layer) def generatePath(self, folder, fileName): return QGISRedUtils().generatePath(folder, fileName) def getLayers(self): return QGISRedUtils().getLayers() def findAdjacentElements(self, nodeGeometry): adjacentElements = {} layers = self.getLayers() for layer in layers: openedLayerPath = self.getLayerPath(layer) for name in self.ownMainLayers: layePath = self.generatePath( self.ProjectDirectory, self.NetworkName + "_" + name + ".shp") if openedLayerPath == layePath: adjacentFeatures = [] for feature in layer.getFeatures(): featureGeometry = feature.geometry() if layer.geometryType() == 0: # Point if self.areOverlapedPoints(nodeGeometry, featureGeometry): adjacentFeatures.append(feature) elif layer.geometryType() == 1: if featureGeometry.isMultipart(): for part in featureGeometry.get( ): # only one part first_vertex = part[0] last_vertex = part[-1] else: first_vertex = featureGeometry.get()[0] last_vertex = featureGeometry.get()[-1] firsVertex = QgsGeometry.fromPointXY( QgsPointXY(first_vertex.x(), first_vertex.y())) lastVertex = QgsGeometry.fromPointXY( QgsPointXY(last_vertex.x(), last_vertex.y())) if self.areOverlapedPoints(nodeGeometry, firsVertex) or\ self.areOverlapedPoints(nodeGeometry, lastVertex): adjacentFeatures.append(feature) if len(adjacentFeatures) > 0: adjacentElements[layer] = adjacentFeatures return adjacentElements def areOverlapedPoints(self, point1, point2): tolerance = 0.1 if point1.distance(point2) < tolerance: return True else: return False def createRubberBand(self, points): myPoints = points if isinstance(points[0], QgsPointXY): myPoints = [] for p in points: myPoints.append(QgsPoint(p.x(), p.y())) self.rubberBand = QgsRubberBand(self.iface.mapCanvas(), False) self.rubberBand.setToGeometry(QgsGeometry.fromPolyline(myPoints), None) self.rubberBand.setColor(QColor(55, 198, 5)) self.rubberBand.setWidth(1) self.rubberBand.setLineStyle(Qt.DashLine) self.newVertexMarker.setCenter(QgsPointXY(points[0].x(), points[0].y())) self.newVertexMarker.show() def updateRubberBand(self): newX = self.clickedPoint.x() + self.newPositionVector.x() newY = self.clickedPoint.y() + self.newPositionVector.y() self.rubberBand.movePoint(1, QgsPointXY(newX, newY)) self.newVertexMarker.setCenter(QgsPointXY(newX, newY)) def moveNodePoint(self, layer, nodeFeature, newPosition): if layer.isEditable(): layer.beginEditCommand('Move node') try: edit_utils = QgsVectorLayerEditUtils(layer) edit_utils.moveVertex(newPosition.x(), newPosition.y(), nodeFeature.id(), 0) except Exception as e: layer.destroyEditCommand() raise e layer.endEditCommand() def moveVertexLink(self, layer, feature, newPosition, vertexIndex): if layer.isEditable(): layer.beginEditCommand("Update link geometry") try: edit_utils = QgsVectorLayerEditUtils(layer) edit_utils.moveVertex(newPosition.x(), newPosition.y(), feature.id(), vertexIndex) except Exception as e: layer.destroyEditCommand() raise e layer.endEditCommand() """Events""" def canvasPressEvent(self, event): if self.objectSnapped is None: self.clickedPoint = None return if event.button() == Qt.RightButton: self.mouseClicked = False self.clickedPoint = None if event.button() == Qt.LeftButton: self.mouseClicked = True self.clickedPoint = self.objectSnapped.point() self.selectedNodeFeature = None self.adjacentFeatures = None foundNode = False layers = self.getLayers() for layer in layers: openedLayerPath = self.getLayerPath(layer) for name in self.myNodeLayers: layerPath = self.generatePath( self.ProjectDirectory, self.NetworkName + "_" + name + ".shp") if openedLayerPath == layerPath: locatedPoint = self.snapper.locatorForLayer(layer) match = locatedPoint.nearestVertex( self.objectSnapped.point(), 1) if match.isValid(): featureId = match.featureId() request = QgsFeatureRequest().setFilterFid( featureId) node = list(layer.getFeatures(request)) self.selectedNodeLayer = layer foundNode = True if not foundNode: return self.selectedNodeFeature = QgsFeature(node[0]) self.adjacentFeatures = self.findAdjacentElements( self.selectedNodeFeature.geometry()) self.createRubberBand( [self.objectSnapped.point(), self.objectSnapped.point()]) def canvasMoveEvent(self, event): self.mousePoint = self.toMapCoordinates(event.pos()) # Mouse not clicked if not self.mouseClicked: match = self.snapper.snapToMap(self.mousePoint) if match.isValid(): self.objectSnapped = match vertex = match.point() self.vertexMarker.setCenter(QgsPointXY(vertex.x(), vertex.y())) self.vertexMarker.show() else: self.objectSnapped = None self.selectedNodeFeature = None self.vertexMarker.hide() # Mouse clicked else: # Update rubber band if self.objectSnapped is not None and self.rubberBand is not None: snappedPoint = self.objectSnapped.point() self.newPositionVector = QgsVector( self.mousePoint.x() - snappedPoint.x(), self.mousePoint.y() - snappedPoint.y()) self.updateRubberBand() def canvasReleaseEvent(self, event): mousePoint = self.toMapCoordinates(event.pos()) if not self.mouseClicked: return if event.button() == 1: self.mouseClicked = False if self.objectSnapped is not None: if self.selectedNodeFeature is not None: for adjLayer in self.adjacentFeatures: for feature in self.adjacentFeatures[adjLayer]: if adjLayer.geometryType() == 0: # Point self.moveNodePoint(adjLayer, feature, mousePoint) else: nodeGeometry = self.selectedNodeFeature.geometry( ) featureGeometry = feature.geometry() if featureGeometry.isMultipart(): for part in featureGeometry.get( ): # only one part firstVertex = part[0] vertices = len(part) else: firstVertex = featureGeometry.get()[0] vertices = 2 firstPoint = QgsGeometry.fromPointXY( QgsPointXY(firstVertex.x(), firstVertex.y())) if self.areOverlapedPoints( nodeGeometry, firstPoint): index = 0 else: index = vertices - 1 self.moveVertexLink(adjLayer, feature, mousePoint, index) self.objectSnapped = None self.selectedNodeFeature = None self.iface.mapCanvas().refresh() # Remove vertex marker and rubber band self.vertexMarker.hide() self.iface.mapCanvas().scene().removeItem(self.rubberBand) self.newVertexMarker.hide()