def build_markers(self, signature): markers = [] rb = QgsRubberBand(self._canvas) rb.setColor(Qt.red) rb.setWidth(1) max_col = 0 max_line = 0 for point in signature['points']: col = point['col'] if col > max_col: max_col = col line = point['line'] if line > max_line: max_line = line markers.append(self.build_marker(col, line)) rb.addPoint(QgsPointXY(col, -line)) rb.closePoints() markers.append(rb) return (markers, QgsPointXY(max_col, -max_line))
class PolygonMapTool(QgsMapToolEmitPoint): """This class holds a map tool to create a polygon from points got by clicking on the map window. Points are stored in a list of point geometries, which is returned to the main plugin for use.""" def __init__(self, canvas): self.canvas = canvas QgsMapToolEmitPoint.__init__(self, self.canvas) # rubberband class gives the user visual feedback of the drawing self.rubberBand = QgsRubberBand(self.canvas, True) # setting up outline and fill color: both red self.rubberBand.setColor(QColor(235, 36, 21)) # RGB color values, last value indicates transparency (0-255) self.rubberBand.setFillColor(QColor(255, 79, 66, 140)) self.rubberBand.setWidth(3) self.points = [] # a flag indicating when a single polygon is finished self.finished = False self.poly_bbox = False self.double_click_flag = False self.reset() def reset(self): """Empties the canvas and the points gathered thus far""" self.rubberBand.reset(True) self.poly_bbox = False self.points.clear() def keyPressEvent(self, e): """Pressing ESC resets the canvas. Pressing enter connects the polygon""" if (e.key() == 16777216): self.reset() if (e.key() == 16777220): self.finishPolygon() def canvasDoubleClickEvent(self, e): self.double_click_flag = True self.finishPolygon() def canvasReleaseEvent(self, e): """Activated when user clicks on the canvas. Gets coordinates, draws them on the map and adds to the list of points.""" if self.double_click_flag: self.double_click_flag = False return # if the finished flag is activated, the canvas will be must be reset # for a new polygon if self.finished: self.reset() self.finished = False self.click_point = self.toMapCoordinates(e.pos()) self.rubberBand.addPoint(self.click_point, True) self.points.append(self.click_point) self.rubberBand.show() def finishPolygon(self): """Activated when by user or when the map window is closed without connecting the polygon. Makes the polygon valid by making first and last point the same. This is reflected visually. Up until now the user has been drawing a line: a polygon is created and shown on the map.""" # nothing will happen if the code below has already been ran if self.finished: return # connecting the polygon is valid if there's already at least 3 points elif len(self.points) > 2: first_point = self.points[0] self.points.append(first_point) self.rubberBand.closePoints() self.rubberBand.addPoint(first_point, True) self.finished = True # a polygon is created and added to the map for visual purposes map_polygon = QgsGeometry.fromPolygonXY([self.points]) self.rubberBand.setToGeometry(map_polygon) # get the bounding box of this new polygon self.poly_bbox = self.rubberBand.asGeometry().boundingBox() else: self.finished = True def getPoints(self): """Returns list of PointXY geometries, i.e. the polygon in list form""" self.rubberBand.reset(True) return self.points def getPolyBbox(self): return self.poly_bbox
class QGISRedMultiLayerSelection(QgsMapTool): def __init__(self, iface, canvas, action): QgsMapTool.__init__(self, canvas) self.canvas = canvas self.iface = iface self.setAction(action) self.myRubberBand = QgsRubberBand(self.canvas, 3) # 3= Polygon mFillColor = QColor(255, 0, 0, 100) self.myRubberBand.setColor(mFillColor) self.myRubberBand.setWidth(2) self.myRubberBand.setLineStyle(2) self.rubberBand1 = None self.rubberBand2 = None self.reset() def deactivate(self): self.reset() self.myRubberBand.hide() QgsMapTool.deactivate(self) def activate(self): QgsMapTool.activate(self) """Methods""" def reset(self): self.initialPoint = None self.finalPoint = None self.isSelecting = False self.myRubberBand.reset(3) # 3= Polygon 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.mousePoints = [] 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]) myPoints1.append(myPoints1[0]) 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())) myPoints2.append(QgsPoint(points[0].x(), points[0].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) def showRectangle(self, initialPoint, finalPoint): self.myRubberBand.reset(3) if initialPoint.x() == finalPoint.x() or initialPoint.y( ) == finalPoint.y(): return point1 = QgsPointXY(initialPoint.x(), initialPoint.y()) point2 = QgsPointXY(initialPoint.x(), finalPoint.y()) point3 = QgsPointXY(finalPoint.x(), finalPoint.y()) point4 = QgsPointXY(finalPoint.x(), initialPoint.y()) self.myRubberBand.addPoint(point1, False) self.myRubberBand.addPoint(point2, False) self.myRubberBand.addPoint(point3, False) self.myRubberBand.addPoint(point4, False) self.myRubberBand.closePoints() self.myRubberBand.show() def getRectangle(self): if self.initialPoint is None or self.finalPoint is None: return None elif self.initialPoint.x() == self.finalPoint.x( ) or self.initialPoint.y() == self.finalPoint.y(): return None return QgsRectangle(self.initialPoint, self.finalPoint) """Events""" def canvasPressEvent(self, e): if e.button() == Qt.RightButton and len(self.mousePoints) > 0: poligon = QgsVectorLayer('Polygon', 'poly', "memory") pr = poligon.dataProvider() poly = QgsFeature() if len(self.mousePoints) > 3: self.mousePoints.remove(self.mousePoints[-1]) poly.setGeometry(QgsGeometry.fromPolygonXY([self.mousePoints])) pr.addFeatures([poly]) layers = self.canvas.layers() try: for layer in layers: if layer.type() == QgsMapLayer.RasterLayer: continue modifiers = QApplication.keyboardModifiers() if modifiers == Qt.ShiftModifier: processing.run( 'qgis:selectbylocation', { 'INPUT': layer, 'PREDICATE': [0], 'INTERSECT': poligon, 'METHOD': 3 }) # Remove elif modifiers == Qt.ControlModifier: processing.run( 'qgis:selectbylocation', { 'INPUT': layer, 'PREDICATE': [0], 'INTERSECT': poligon, 'METHOD': 1 }) # Add else: processing.run( 'qgis:selectbylocation', { 'INPUT': layer, 'PREDICATE': [0], 'INTERSECT': poligon, 'METHOD': 0 }) # Set except Exception: self.iface.messageBar().pushMessage( "Warning", "Polygon not valid for selecting elements", level=1, duration=5) self.reset() poligon = None return elif e.button() == Qt.RightButton: self.canvas.unsetMapTool(self) self.deactivate() return # Rectangle if len(self.mousePoints) == 0: self.initialPoint = self.toMapCoordinates(e.pos()) self.finalPoint = self.initialPoint self.isSelecting = True self.showRectangle(self.initialPoint, self.finalPoint) # Poliline point = self.toMapCoordinates(e.pos()) self.mousePoints.append(point) if len(self.mousePoints) == 1: self.mousePoints.append(point) def canvasReleaseEvent(self, e): self.isSelecting = False rect = self.getRectangle() if rect is None: if len(self.mousePoints) > 0: self.createRubberBand(self.mousePoints) else: self.mousePoints = [] layers = self.canvas.layers() for layer in layers: if layer.type() == QgsMapLayer.RasterLayer: continue lRect = self.canvas.mapSettings().mapToLayerCoordinates( layer, rect) modifiers = QApplication.keyboardModifiers() if modifiers == Qt.ShiftModifier: layer.selectByRect(lRect, 3) # Remove elif modifiers == Qt.ControlModifier: layer.selectByRect(lRect, 1) # Add else: layer.selectByRect(lRect, 0) # Set self.myRubberBand.hide() def canvasMoveEvent(self, e): point = self.toMapCoordinates(e.pos()) if self.isSelecting: self.finalPoint = point self.showRectangle(self.initialPoint, self.finalPoint) elif len(self.mousePoints) > 0: self.mousePoints[-1] = point self.createRubberBand(self.mousePoints)
class DeleteTool(QgsMapTool): def __init__(self, data_dock, params): QgsMapTool.__init__(self, data_dock.iface.mapCanvas()) self.iface = data_dock.iface """:type : QgisInterface""" self.data_dock = data_dock """:type : DataDock""" self.params = params self.elev = -1 self.vertex_marker = QgsVertexMarker(self.canvas()) # Stroke self.rubber_band = QgsRubberBand(self.data_dock.iface.mapCanvas()) self.rubber_band.setColor(QColor(255, 0, 0, 255)) self.rubber_band.setWidth(2) self.mouse_clicked = False self.snapper = None self.clicked_pt = None self.snap_results = None self.adj_links_fts = None self.selected_node_ft = None self.selected_node_ft_lay = None self.mouse_pt = None self.pump_valve_selected = False self.pump_or_valve = None self.pump_valve_ft = None self.adj_junctions = None self.delta_vec = None self.adj_pipes_fts_d = {} def canvasPressEvent(self, event): # if self.snap_results is None: # return if event.button() == Qt.RightButton: self.mouse_clicked = False self.clicked_pt = None if event.button() == Qt.LeftButton: self.mouse_clicked = True self.clicked_pt = self.toMapCoordinates(event.pos()) def canvasMoveEvent(self, event): self.mouse_pt = self.toMapCoordinates(event.pos()) elev = raster_utils.read_layer_val_from_coord(self.params.dem_rlay, self.mouse_pt, 1) if elev is not None: self.elev = elev self.data_dock.lbl_elev_val.setText("{0:.2f}".format(self.elev)) # Mouse not clicked if not self.mouse_clicked: match = self.snapper.snapToMap(self.mouse_pt) if match.isValid(): self.snap_results = match # snapped_pt = self.snap_results[0].snappedVertex self.snapped_pipe_id = match.featureId() snapped_vertex = match.point() self.snapped_vertex_nr = match.vertexIndex() self.vertex_marker.setCenter( QgsPointXY(snapped_vertex.x(), snapped_vertex.y())) self.vertex_marker.setColor(QColor(255, 0, 0)) self.vertex_marker.setIconSize(10) self.vertex_marker.setIconType( QgsVertexMarker.ICON_CIRCLE) # or ICON_CROSS, ICON_X self.vertex_marker.setPenWidth(3) self.vertex_marker.show() else: self.snap_results = None self.selected_node_ft = None self.vertex_marker.hide() # Mouse clicked: draw rectangle else: if self.snap_results is None: end_point = self.toMapCoordinates(event.pos()) self.show_rect(self.clicked_pt, end_point) def canvasReleaseEvent(self, event): if not self.mouse_clicked: return if event.button() == Qt.LeftButton: self.mouse_clicked = False # Snapped: one element selected if self.snap_results is not None: selected_node_ft_lay, selected_node_ft = vector_utils.findSnappedNode( self.snapper, self.snap_results, self.params) # A node ha been snapped if selected_node_ft_lay is not None: self.delete_element(selected_node_ft_lay, selected_node_ft) # A link has been snapped else: snapped_ft = vector_utils.get_feats_by_id( self.snap_results.layer(), self.snap_results.featureId()) snapped_layer = self.snap_results.layer() self.delete_element(snapped_layer, snapped_ft[0]) # Not snapped: rectangle else: rubber_band_rect = self.rubber_band.asGeometry().boundingBox() self.rubber_band.reset() self.delete_elements(self.params.valves_vlay, rubber_band_rect) self.delete_elements(self.params.pumps_vlay, rubber_band_rect) self.delete_elements(self.params.pipes_vlay, rubber_band_rect) self.delete_elements(self.params.tanks_vlay, rubber_band_rect) self.delete_elements(self.params.reservoirs_vlay, rubber_band_rect) self.delete_elements(self.params.junctions_vlay, rubber_band_rect) # Refresh symbology.refresh_layer(self.iface.mapCanvas(), self.params.junctions_vlay) symbology.refresh_layer(self.iface.mapCanvas(), self.params.reservoirs_vlay) symbology.refresh_layer(self.iface.mapCanvas(), self.params.tanks_vlay) symbology.refresh_layer(self.iface.mapCanvas(), self.params.pipes_vlay) symbology.refresh_layer(self.iface.mapCanvas(), self.params.pumps_vlay) symbology.refresh_layer(self.iface.mapCanvas(), self.params.valves_vlay) def activate(self): cursor = QCursor() cursor.setShape(Qt.ArrowCursor) self.iface.mapCanvas().setCursor(cursor) layers = { self.params.junctions_vlay: QgsSnappingConfig.Vertex, self.params.reservoirs_vlay: QgsSnappingConfig.Vertex, self.params.tanks_vlay: QgsSnappingConfig.Vertex, self.params.pipes_vlay: QgsSnappingConfig.VertexAndSegment } self.snapper = NetworkUtils.set_up_snapper(layers, self.iface.mapCanvas(), self.params.snap_tolerance) self.snapper.toggleEnabled() # Editing if not self.params.junctions_vlay.isEditable(): self.params.junctions_vlay.startEditing() if not self.params.reservoirs_vlay.isEditable(): self.params.reservoirs_vlay.startEditing() if not self.params.tanks_vlay.isEditable(): self.params.tanks_vlay.startEditing() if not self.params.pipes_vlay.isEditable(): self.params.pipes_vlay.startEditing() if not self.params.pumps_vlay.isEditable(): self.params.pumps_vlay.startEditing() if not self.params.valves_vlay.isEditable(): self.params.valves_vlay.startEditing() def deactivate(self): self.data_dock.btn_delete_element.setChecked(False) self.canvas().scene().removeItem(self.vertex_marker) def isZoomTool(self): return False def isTransient(self): return False def isEditTool(self): return True def show_rect(self, start_point, end_point): self.rubber_band.reset() if start_point.x() == end_point.x() or start_point.y() == end_point.y( ): return point1 = QgsPointXY(start_point.x(), start_point.y()) point2 = QgsPointXY(start_point.x(), end_point.y()) point3 = QgsPointXY(end_point.x(), end_point.y()) point4 = QgsPointXY(end_point.x(), start_point.y()) point5 = QgsPointXY(start_point.x(), start_point.y()) self.rubber_band.addPoint(point1, False) self.rubber_band.addPoint(point2, False) self.rubber_band.addPoint(point3, False) self.rubber_band.addPoint(point4, False) self.rubber_band.closePoints(True) # true to update canvas self.rubber_band.show() def delete_elements(self, layer, rectangle): try: QApplication.setOverrideCursor(Qt.WaitCursor) feats = layer.getFeatures() for feat in feats: if rectangle.contains(feat.geometry().boundingBox()): self.delete_element(layer, feat) finally: QApplication.restoreOverrideCursor() def delete_element(self, layer, feature): # If node if layer == self.params.junctions_vlay or \ layer == self.params.reservoirs_vlay or \ layer == self.params.tanks_vlay: # The node is a junction if layer == self.params.junctions_vlay: adj_links_fts = NetworkUtils.find_adjacent_links( self.params, feature.geometry()) # Only pipes adjacent to node: it's a simple junction if not adj_links_fts['pumps'] and not adj_links_fts['valves']: # Delete node NodeHandler.delete_node(self.params, layer, feature) # Delete adjacent pipes adj_pipes = NetworkUtils.find_adjacent_links( self.params, feature.geometry()) for adj_pipe in adj_pipes['pipes']: LinkHandler.delete_link(self.params.pipes_vlay, adj_pipe) # The node is part of a pump or valve else: if adj_links_fts['pumps']: LinkHandler.delete_link(self.params, self.params.pumps_vlay, feature) elif adj_links_fts['valves']: LinkHandler.delete_link(self.params, self.params.valves_vlay, feature) # The node is a reservoir or a tank elif layer == self.params.reservoirs_vlay or \ layer == self.params.tanks_vlay: adj_pipes = NetworkUtils.find_adjacent_links( self.params, feature.geometry())['pipes'] NodeHandler._delete_feature(self.params, layer, feature) for adj_pipe in adj_pipes: LinkHandler.delete_link(self.params, self.params.pipes_vlay, adj_pipe) # If pipe elif layer == self.params.pipes_vlay: if self.snap_results is not None: vertex = feature.geometry().closestVertexWithContext( self.snap_results.point()) vertex_dist = vertex[0] if vertex_dist < self.params.min_dist: # Delete vertex LinkHandler.delete_vertex(self.params, self.params.pipes_vlay, feature, vertex[1]) else: # Delete whole feature LinkHandler.delete_link(self.params, layer, feature) else: LinkHandler.delete_link(self.params, layer, feature)
class SignatureTool(QgsMapTool): """ On Double click it will callback with an array with a single pixel. On Single click without releasing it will draw a square and callback the starting and ending point in an array. On Single click with releasing it will start drawing a polygon and every subsequent single click will add a new vertex in the polygon. On Right click it will callback with an array with all the vertex in the polygon. On Escape it will clean up the array and start over. """ def __init__(self, canvas, layer, callback): QgsMapTool.__init__(self, canvas) self._canvas = canvas self._layer = layer self._callback = callback self._pixels = [] self._start_point = None self._mode = Mode.NONE self._rubber_band = QgsRubberBand(self._canvas) self._rubber_band.setColor(Qt.red) self._rubber_band.setWidth(1) self.parent().setCursor(Qt.CrossCursor) def getPoint(self, pos): x = pos.x() y = pos.y() return self._canvas.getCoordinateTransform().toMapCoordinates(x, y) def getRowCol(self, point): # clicked position on screen to map coordinates data_provider = self._layer.dataProvider() extent = data_provider.extent() width = data_provider.xSize() if data_provider.capabilities() \ & data_provider.Size else 1000 height = data_provider.ySize() if data_provider.capabilities() \ & data_provider.Size else 1000 xres = extent.width() / width yres = extent.height() / height if extent.xMinimum() <= point.x() <= extent.xMaximum() and \ extent.yMinimum() <= point.y() <= extent.yMaximum(): col = int(floor((point.x() - extent.xMinimum()) / xres)) row = int(floor((extent.yMaximum() - point.y()) / yres)) return (row, col) else: return None def keyReleaseEvent(self, event): if event.key() == Qt.Key_Escape: self._pixels = [] self.finish() def canvasMoveEvent(self, event): point = self.getPoint(event.pos()) if self._mode is Mode.SQUARE: if not point.compare(self._start_point): self._rubber_band.reset() self._rubber_band.addPoint(self._start_point, False) self._rubber_band.addPoint( QgsPointXY(self._start_point.x(), point.y()), False) self._rubber_band.addPoint(point, False) self._rubber_band.addPoint( QgsPointXY(point.x(), self._start_point.y()), False) self._rubber_band.closePoints() elif self._mode is Mode.POLYGON: self._rubber_band.movePoint( self._rubber_band.numberOfVertices() - 1, point) def canvasReleaseEvent(self, event): if event.button() == Qt.LeftButton: point = self.getPoint(event.pos()) if self._mode is Mode.SQUARE: if self._start_point.compare(point): self._mode = Mode.POLYGON self._rubber_band.addPoint(point) self._start_point = None else: self._pixels = [] # The last vertex is repeated for i in range(self._rubber_band.numberOfVertices() - 1): self._pixels.append( self.getRowCol(self._rubber_band.getPoint(0, i))) self.finish() elif self._mode is Mode.POLYGON: self._rubber_band.addPoint(point) def canvasPressEvent(self, event): if event.button() == Qt.LeftButton: point = self.getPoint(event.pos()) pixel = self.getRowCol(point) if self._mode is Mode.NONE: self._mode = Mode.SQUARE self._start_point = QgsPointXY(point.x(), point.y()) elif self._mode is Mode.POLYGON: self._rubber_band.removePoint( self._rubber_band.numberOfVertices() - 1) else: self._mode = Mode.POLYGON if pixel: self._rubber_band.addPoint(point) self._pixels.append(pixel) elif event.button() == Qt.RightButton: self.finish() def finish(self): self._canvas.unsetMapTool(self) self._rubber_band.reset() self._mode = Mode.NONE self._start_point = None if len(self._pixels) > 0: self._callback(self._layer.hiperqube_id(), self._pixels)
class MapTool(QgsMapTool): geometry_changed = pyqtSignal(QgsGeometry, bool) tool_deactivated = pyqtSignal() def __init__(self, canvas, cursorstyle=Qt.CrossCursor): self.canvas = canvas QgsMapTool.__init__(self, canvas) self.caller = self.sender() self.cursorStyle = cursorstyle self.active = False # get selection color selcolor = self.canvas.selectionColor() mycolor = QColor(selcolor.red(), selcolor.green(), selcolor.blue(), 40) self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.rb.setStrokeColor(QColor(255, 0, 0, 40)) self.rb.setFillColor(mycolor) self.rb.setLineStyle(Qt.PenStyle(Qt.SolidLine)) self.rb.setWidth(2) def setCursorStyle(self): cursor = QCursor() cursor.setShape(self.cursorStyle) self.setCursor(cursor) def activate(self): self.caller.setChecked(True) self.setCursorStyle() def deactivate(self): self.canvas.scene().removeItem(self.rb) self.tool_deactivated.emit() self.caller.setChecked(False) QgsMapTool.deactivate(self) def setGeometry(self, geo): self.rb.setToGeometry(geo) def canvasReleaseEvent(self, mouseEvent): if mouseEvent.button() == Qt.LeftButton: if not self.active: self.active = True self.geometry_changed.emit(QgsGeometry(), False) self.rb.reset(QgsWkbTypes.PolygonGeometry) self.rb.addPoint(mouseEvent.mapPoint()) if self.rb.numberOfVertices() > 2: self.geometry_changed.emit(self.rb.asGeometry(), False) elif mouseEvent.button() == Qt.RightButton: if self.rb.numberOfVertices() > 3: self.active = False self.rb.removeLastPoint() self.rb.closePoints( ) #Ensures that a polygon geometry is closed and that the last vertex equals the first vertex geo = self.rb.asGeometry() self.geometry_changed.emit(geo, True) else: self.rb.reset(QgsWkbTypes.PolygonGeometry) def canvasMoveEvent(self, mouseEvent): if self.rb.numberOfVertices() > 1 and self.active: self.rb.removeLastPoint() self.rb.addPoint(mouseEvent.mapPoint()) pass