class LineDrawer(QgsMapToolEmitPoint): def __init__(self, canvas): # call the parent constructor QgsMapToolEmitPoint.__init__(self, canvas) # store the passed canvas self.canvas = canvas # flag to know whether the tool is performing a drawing operation self.isDrawing = False # create and setup the rubber band to display the line self.rubberBand = QgsRubberBand( self.canvas, False ) # False = not a polygon = a line self.rubberBand.setColor( Qt.red ) self.rubberBand.setWidth( 1 ) def clear(self): self.rubberBand.reset( False ) # False = not a polygon = a line def delete(self): self.canvas.scene().removeItem( self.rubberBand ) def canvasPressEvent(self, e): # which the mouse button? if e.button() == Qt.LeftButton: # left click # if it's the first left click, clear the rubberband if not self.isDrawing: self.clear() # we are drawing now self.isDrawing = True # convert the clicked position to map coordinates point = self.toMapCoordinates( e.pos() ) # add a new point to the rubber band self.rubberBand.addPoint( point, True ) # True = display updates on the canvas # and finally show the rubber band self.rubberBand.show() elif e.button() == Qt.RightButton: # right click, stop drawing self.isDrawing = False # emit a signal self.emit( SIGNAL("editingFinished()") ) def canvasMoveEvent(self, e): # check if it's already drawing if not self.isDrawing: return # convert the mouse position to map coordinates point = self.toMapCoordinates( e.pos() ) # move the last point to the new coordinates self.rubberBand.movePoint( point ) def geometry(self): return self.rubberBand.asGeometry()
def _draw_rubberband(self, geometry, colour, width): """Draw a rubber band on the canvas. .. versionadded: 2.2.0 :param geometry: Extent that the rubber band should be drawn for. :type geometry: QgsGeometry :param colour: Colour for the rubber band. :type colour: QColor :param width: The width for the rubber band pen stroke. :type width: int :returns: Rubber band that should be set to the extent. :rtype: QgsRubberBand """ # noinspection PyArgumentList rubber_band = QgsRubberBand( self._map_canvas, geometryType=QGis.Polygon) rubber_band.setBrushStyle(Qt.NoBrush) rubber_band.setColor(colour) rubber_band.setWidth(width) rubber_band.setToGeometry(geometry, None) return rubber_band
def highlight(): rb = QgsRubberBand( self.canvas, QGis.Polygon) rb.setBorderColor( QColor( 255, 0, 0 ) ) rb.setWidth( 2 ) rb.setToGeometry( geomRB, None ) return rb
def _draw_rubberband(self, extent, colour, width=2): """ Draw a rubber band on the canvas. .. versionadded: 2.2.0 :param extent: Extent that the rubber band should be drawn for. :type extent: QgsRectangle :param colour: Colour for the rubber band. :type colour: QColor :param width: The width for the rubber band pen stroke. :type width: int :returns: Rubber band that should be set to the extent. :rtype: QgsRubberBand """ rubberband = QgsRubberBand( self.iface.mapCanvas(), geometryType=QGis.Line) rubberband.setColor(colour) rubberband.setWidth(width) update_display_flag = False point = QgsPoint(extent.xMinimum(), extent.yMinimum()) rubberband.addPoint(point, update_display_flag) point = QgsPoint(extent.xMaximum(), extent.yMinimum()) rubberband.addPoint(point, update_display_flag) point = QgsPoint(extent.xMaximum(), extent.yMaximum()) rubberband.addPoint(point, update_display_flag) point = QgsPoint(extent.xMinimum(), extent.yMaximum()) rubberband.addPoint(point, update_display_flag) point = QgsPoint(extent.xMinimum(), extent.yMinimum()) update_display_flag = True rubberband.addPoint(point, update_display_flag) return rubberband
def loadLines(self, lines, points, markers, suffix): no = self.project.readEntry("TUVIEW", "lines{0}no".format(suffix))[0] if no: no = int(no) for i in range(no): a = self.project.readEntry("TUVIEW", 'lines{0}x{1}'.format(suffix, i))[0] a = a.split('~~') b = self.project.readEntry("TUVIEW", 'lines{0}y{1}'.format(suffix, i))[0] b = b.split('~~') points.clear() for j in range(len(a)): x = float(a[j]) y = float(b[j]) point = QgsPoint(x, y) points.append(point) if i + 1 == no: marker = QgsVertexMarker(self.tuView.canvas) if suffix == 'cs': marker.setColor(Qt.red) marker.setIconSize(10) marker.setIconType(QgsVertexMarker.ICON_BOX) else: # 'q' marker.setColor(Qt.blue) marker.setIconSize(12) marker.setIconType(QgsVertexMarker.ICON_DOUBLE_TRIANGLE) marker.setCenter(QgsPointXY(point)) markers.append(marker) line = QgsRubberBand(self.tuView.canvas, False) line.setWidth(2) if suffix == 'cs': line.setColor(QColor(Qt.red)) else: # 'q' line.setColor(QColor(Qt.blue)) line.setToGeometry(QgsGeometry.fromPolyline(points), None) lines.append(line)
class QgepMapTool( QgsMapTool ): ''' Base class for all the map tools ''' highLightedPoints = [] logger = logging.getLogger( __name__ ) def __init__( self, iface, button ): QgsMapTool.__init__( self, iface.mapCanvas() ) self.canvas = iface.mapCanvas() self.cursor = QCursor( Qt.CrossCursor ) self.button = button self.msgBar = iface.messageBar() settings = QSettings() currentProfileColor = settings.value( "/QGEP/CurrentProfileColor", u'#FF9500' ) self.rubberBand = QgsRubberBand( self.canvas ) self.rubberBand.setColor( QColor( currentProfileColor ) ) self.rubberBand.setWidth( 3 ) # Gets called when the tool is activated def activate( self ): QgsMapTool.activate( self ) self.canvas.setCursor( self.cursor ) self.button.setChecked( True ) # Gets called whenever the tool is deactivated directly or indirectly def deactivate( self ): QgsMapTool.deactivate( self ) self.button.setChecked( False ) def isZoomTool( self ): return False def setCursor( self, cursor ): self.cursor = QCursor( cursor ) #=========================================================================== # Events #=========================================================================== def canvasMoveEvent( self, event ): try: self.mouseMoved( event ) except AttributeError: pass def canvasReleaseEvent( self, event ): if event.button() == Qt.RightButton: self.rightClicked ( event ) else: self.leftClicked( event ) def canvasDoubleClickEvent( self, event ): try: self.doubleClicked( event ) except AttributeError: pass
def getSnapRubberBand(self): rubberBand = QgsRubberBand(self.canvas, geometryType = QGis.Point) rubberBand.setFillColor(QColor(255, 0, 0, 40)) rubberBand.setBorderColor(QColor(255, 0, 0, 200)) rubberBand.setWidth(2) rubberBand.setIcon(QgsRubberBand.ICON_X) return rubberBand
def zoomAndShowWKT(self, wtk): geom = QgsGeometry.fromWkt(wtk) canvas = self.iface.mapCanvas() self.clear() r = QgsRubberBand(canvas, geom.type() == 3 ) r.setToGeometry(geom, None) r.setColor(QColor(0, 0, 255)) r.setFillColor(QColor(0, 0, 255, 50)) r.setWidth(3) pt = geom.pointOnSurface().asPoint() m = QgsVertexMarker(canvas) m.setCenter( pt ) m.setColor(QColor(0, 0, 255)) m.setIconSize(5) m.setIconType(QgsVertexMarker.ICON_BOX) m.setPenWidth(3) if geom.type() == 3 or geom.type() == 2: rec = geom.boundingBox() canvas.setExtent(rec) else: self.moveMapTo( pt[0], pt[1], 0) self.graphics.append(r) self.graphics.append(m) self._refresh_layers()
class PlaceMarkerMapTool(QgsMapToolEmitPoint): ''' classdocs ''' def __init__(self, canvas): ''' Constructor ''' self.canvas = canvas super(PlaceMarkerMapTool, self).__init__(self.canvas) self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon) self.rubberBand.setColor(Qt.red) self.rubberBand.setWidth(1) self.reset() def reset(self): self.rubberBand.reset(QGis.Polygon) def canvasReleaseEvent(self, e): p1 = self.canvas.getCoordinateTransform().toMapCoordinates(e.x() - 2, e.y() - 2) p2 = self.canvas.getCoordinateTransform().toMapCoordinates(e.x() + 2, e.y() - 2) p3 = self.canvas.getCoordinateTransform().toMapCoordinates(e.x() + 2, e.y() + 2) p4 = self.canvas.getCoordinateTransform().toMapCoordinates(e.x() - 2, e.y() + 2) self.reset() self.rubberBand.addPoint(p1, False) self.rubberBand.addPoint(p2, False) self.rubberBand.addPoint(p3, False) self.rubberBand.addPoint(p4, True) self.rubberBand.show() def deactivate(self): self.reset() super(PlaceMarkerMapTool, self).deactivate()
class GetPointMapTool(QgsMapToolEmitPoint): coordCaptured = "" def __init__(self, canvas, iface, dockwidget, currentMapTool): self.canvas = canvas self.iface = iface self.currentMapTool = currentMapTool self.dockwidget = dockwidget QgsMapToolEmitPoint.__init__(self, self.canvas) self.rubberBand = QgsRubberBand(self.canvas, QGis.Point) self.rubberBand.setColor(QColor(255,5,5)) self.rubberBand.setWidth(1) self.reset() def reset(self): self.startPoint = self.endPoint = None self.isEmittingPoint = False self.rubberBand.reset(QGis.Polygon) def canvasPressEvent(self, e): self.point = self.toMapCoordinates(e.pos()) self.isEmittingPoint = True self.showPoint(self.point) def canvasReleaseEvent(self, e): self.isEmittingPoint = False self.coordCaptured = self.pointdef() if self.coordCaptured is not None: print "Point:", self.coordCaptured self.coordCaptured = str(self.coordCaptured).strip("(") self.coordCaptured = str(self.coordCaptured).strip(")") self.dockwidget.munLineEdit.setText(self.coordCaptured) self.iface.mapCanvas().setMapTool(self.currentMapTool) def canvasMoveEvent(self, e): if not self.isEmittingPoint: return self.endPoint = self.toMapCoordinates(e.pos()) # self.showRect(self.startPoint, self.endPoint) def showPoint(self, point): self.rubberBand.reset(QGis.Polygon) point1 = QgsPoint(point.x(), point.y()) self.rubberBand.addPoint(point1, False) self.rubberBand.show() def pointdef(self): return QgsPoint(self.point)
def addGraphic(self, geom ): canvas = self.iface.mapCanvas() rBand = QgsRubberBand(canvas, True) self.graphics.append( rBand ) rBand.setToGeometry( geom, None ) rBand.setColor(QtGui.QColor(0,0,255, 70)) if QGis.QGIS_VERSION_INT >= 20600: rBand.setBorderColor( QtGui.QColor(0,0,250, 220) ) rBand.setWidth(3)
class QgepMapToolAddFeature( QgsMapTool ): def __init__(self, iface, layer): QgsMapTool.__init__(self, iface.mapCanvas() ) self.iface = iface self.canvas = iface.mapCanvas() self.layer = layer self.rubberband = QgsRubberBand( iface.mapCanvas(), layer.geometryType() ) self.rubberband.setColor( QColor( "#ee5555" ) ) self.rubberband.setWidth( 2 ) self.tempRubberband = QgsRubberBand( iface.mapCanvas(), layer.geometryType() ) self.tempRubberband.setColor( QColor( "#ee5555" ) ) self.tempRubberband.setWidth( 2 ) self.tempRubberband.setLineStyle(Qt.DotLine) def activate(self): QgsMapTool.activate( self ) self.canvas.setCursor( QCursor( Qt.CrossCursor ) ) pass def deactivate(self): QgsMapTool.deactivate( self ) self.canvas.unsetCursor() pass def isZoomTool( self ): return False #=========================================================================== # Events #=========================================================================== def canvasMoveEvent( self, event ): self.mouseMoved( event ) def canvasReleaseEvent( self, event ): if event.button() == Qt.RightButton: self.rightClicked ( event ) else: self.leftClicked( event ) def leftClicked(self, event): mousePos = self.canvas.getCoordinateTransform().toMapCoordinates( event.pos().x(), event.pos().y() ) self.rubberband.addPoint( mousePos ) self.tempRubberband.reset() def rightClicked(self, event): f = QgsFeature( self.layer.pendingFields() ) f.setGeometry( self.rubberband.asGeometry() ) dlg = self.iface.getFeatureForm( self.layer, f ) dlg.setIsAddDialog(True) dlg.exec_() self.rubberband.reset() self.tempRubberband.reset() def mouseMoved(self, event): mousePos = self.canvas.getCoordinateTransform().toMapCoordinates( event.pos().x(), event.pos().y() ) self.tempRubberband.movePoint( mousePos )
def onClickedHighlight(self): def removeRB(): rb.reset( True ) self.qgisCanvas.scene().removeItem( rb ) rb = QgsRubberBand( self.qgisCanvas, QGis.Polygon) rb.setBorderColor( QColor( 255, 0, 0 ) ) rb.setWidth( 2 ) rb.setToGeometry( QgsGeometry.fromRect( self.canvas.extent() ), None ) QTimer.singleShot( 2000, removeRB )
def _setRubberBandMarker(self, geom): m = QgsRubberBand(self.qgisIface.mapCanvas(), False) # not polygon if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry: linegeom = geom elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PolygonGeometry: linegeom = QgsGeometry.fromPolylineXY(geom.asPolygon()[0]) m.setToGeometry(linegeom, None) m.setColor(QColor(self.config['rubber_color'])) m.setWidth(self.config['rubber_width']) return m
def initRubberLayer(self): if self.rubberLayer: rb = self.rubberLayer rb.reset(True) else: rb = QgsRubberBand(self.iface.mapCanvas(), True) rb.setColor(QColor(255, 0, 255, 255)) rb.setWidth(3) rb.setFillColor(QColor(255, 0, 255, 50)) self.rubberLayer = rb
def getRubberBand(self): geomType = self.iface.activeLayer().geometryType() if geomType == QGis.Polygon: rubberBand = QgsRubberBand(self.canvas, True) rubberBand.setFillColor(QColor(255, 0, 0, 40)) elif geomType == QGis.Line: rubberBand = QgsRubberBand(self.canvas, False) rubberBand.setBorderColor(QColor(255, 0, 0, 200)) rubberBand.setWidth(2) return rubberBand
class CurrentSelection(QgsRubberBand): """ Position marker for the current location in the viewer. """ class AniObject(QObject): def __init__(self, band): super(CurrentSelection.AniObject, self).__init__() self.color = QColor() @pyqtProperty(int) def alpha(self): return self.color.alpha() @alpha.setter def alpha(self, value): self.color.setAlpha(value) def __init__(self, canvas): super(CurrentSelection, self).__init__(canvas) self.outline = QgsRubberBand(canvas) self.outline.setBrushStyle(Qt.NoBrush) self.outline.setWidth(5) self.outline.setIconSize(30) self.aniobject = CurrentSelection.AniObject(self) self.anim = QPropertyAnimation(self.aniobject, "alpha") self.anim.setDuration(500) self.anim.setStartValue(50) self.anim.setEndValue(100) self.anim.valueChanged.connect(self.value_changed) def setOutlineColour(self, color): self.outline.setColor(color) def setToGeometry(self, geom, layer): super(CurrentSelection, self).setToGeometry(geom, layer) self.outline.setToGeometry(geom, layer) self.anim.stop() self.anim.start() def reset(self, geomtype=QGis.Line): super(CurrentSelection, self).reset(geomtype) self.outline.reset(geomtype) self.anim.stop() def value_changed(self, value): self.setColor(self.aniobject.color) self.update() def setColor(self, color): self.aniobject.color = color super(CurrentSelection, self).setColor(color)
def drawManyPaths(self, rows, columns, con, args, geomType, canvasItemList, mapCanvas): ''' draws multi line string on the mapCanvas. ''' resultPathsRubberBands = canvasItemList['paths'] rubberBand = None cur_path_id = None for row in rows: cur2 = con.cursor() result_path_id = str(row[columns[0]]) args['result_node_id'] = sql.Literal(row[columns[1]]) args['result_edge_id'] = sql.Literal(row[columns[2]]) if result_path_id != cur_path_id: cur_path_id = result_path_id if rubberBand: resultPathsRubberBands.append(rubberBand) rubberBand = None rubberBand = QgsRubberBand(mapCanvas, Utils.getRubberBandType(False)) rubberBand.setColor(QColor(255, 0, 0, 128)) rubberBand.setWidth(4) if row[columns[2]] != -1: query2 = sql.SQL(""" SELECT ST_AsText({transform_s}{geometry}{transform_e}) FROM {edge_schema}.{edge_table} WHERE {source} = {result_node_id} AND {id} = {result_edge_id} UNION SELECT ST_AsText({transform_s}ST_Reverse({geometry}){transform_e}) FROM {edge_schema}.{edge_table} WHERE {target} = {result_node_id} AND {id} = {result_edge_id} """).format(**args).as_string(con) cur2.execute(query2) row2 = cur2.fetchone() geom = QgsGeometry().fromWkt(str(row2[0])) if geom.wkbType() == QgsWkbTypes.MultiLineString: for line in geom.asMultiPolyline(): for pt in line: rubberBand.addPoint(pt) elif geom.wkbType() == QgsWkbTypes.LineString: for pt in geom.asPolyline(): rubberBand.addPoint(pt) if rubberBand: resultPathsRubberBands.append(rubberBand) rubberBand = None
def _createRubberBand(self, geometryType, moveBand=False): settings = QSettings() rb = QgsRubberBand(self.canvas(), geometryType) rb.setWidth(int(settings.value('/qgis/digitizing/line_width', 1))) color = QColor(int(settings.value('/qgis/digitizing/line_color_red', 255)), int(settings.value('/qgis/digitizing/line_color_green', 0)), int(settings.value('/qgis/digitizing/line_color_blue', 0))) myAlpha = int(settings.value('/qgis/digitizing/line_color_alpha', 200)) / 255.0 if (moveBand): myAlpha = myAlpha * float(settings.value('/qgis/digitizing/line_color_alpha_scale', 0.75)) rb.setLineStyle(Qt.DotLine) if (geometryType == QGis.Polygon): color.setAlphaF(myAlpha) color.setAlphaF(myAlpha) rb.setColor(color) rb.show() return rb
class lineTool(QgsMapTool): def __init__(self, iface, callback): QgsMapTool.__init__(self,iface.mapCanvas()) self.iface = iface self.canvas = iface.mapCanvas() self.cursor = QCursor(Qt.CrossCursor) self.callback = callback self.rubberBand = QgsRubberBand(self.canvas, False) self.points = [] self.rubberBand.setColor(Qt.red) self.rubberBand.setWidth(1.6) def canvasReleaseEvent(self,event): if event.button() == Qt.RightButton: self.points.append(QgsPoint( self.toMapCoordinates( event.pos()) ) ) if len(self.points) <= 1 :return self.rubberBand.setToGeometry( QgsGeometry.fromPolyline(self.points), None ) self.callback( self.rubberBand ) QgsMapTool.deactivate(self) else: self.points.append(QgsPoint( self.toMapCoordinates(event.pos()) ) ) if len(self.points) <= 1 : return self.rubberBand.setToGeometry( QgsGeometry.fromPolyline(self.points), None ) def canvasDoubleClickEvent(self,event): self.points.append(QgsPoint( self.toMapCoordinates( event.pos()) )) if len(self.points) <= 1 : return self.rubberBand.setToGeometry( QgsGeometry.fromPolyline(self.points), None ) self.callback( self.rubberBand ) QgsMapTool.deactivate(self) def activate(self): QgsMapTool.activate(self) self.canvas.setCursor(self.cursor) def isZoomTool(self): return False def setCursor(self,cursor): self.cursor = QCursor(cursor)
def createMoveTrack(self, line=False, color=QColor(255, 71, 25, 170), width=0.2): '''Create move track. :param line: Flag indicating if geometry to draw is a line (True) or a polygon(False). :type line: bool :param color: Color of line. :type color: QColor :param width: Width of line. :type width: int :return: Created rubber band. :rtype: QgsRubberBand ''' moveTrack = QgsRubberBand(self.canvas, line) moveTrack.setColor(color) moveTrack.setWidth(width) return moveTrack
def highlight(self,geometry): def processEvents(): try: qApp.processEvents() except: QApplication.processEvents() highlight = QgsRubberBand(self.canvas, geometry.type()) highlight.setColor(QColor("#36AF6C")) highlight.setFillColor(QColor("#36AF6C")) highlight.setWidth(2) highlight.setToGeometry(geometry,self.canvas.currentLayer()) processEvents() sleep(.1) highlight.hide() processEvents() sleep(.1) highlight.show() processEvents() sleep(.1) highlight.reset() processEvents()
class DrawPoint(QgsMapTool): selectionDone = pyqtSignal() def __init__(self, iface, couleur): canvas = iface.mapCanvas() QgsMapTool.__init__(self, canvas) self.canvas = canvas self.iface = iface self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry) self.rb.setColor(couleur) self.rb.setWidth(3) def canvasReleaseEvent(self, e): if e.button() == Qt.LeftButton: self.rb.addPoint(self.toMapCoordinates(e.pos())) self.selectionDone.emit() def reset(self): self.rb.reset(QgsWkbTypes.PointGeometry) def deactivate(self): self.rb.reset(QgsWkbTypes.PointGeometry) QgsMapTool.deactivate(self)
class RotateRasterMapTool(QgsMapToolEmitPoint): def __init__(self, iface): self.iface = iface self.canvas = iface.mapCanvas() QgsMapToolEmitPoint.__init__(self, self.canvas) self.rasterShadow = RasterShadowMapCanvasItem(self.canvas) self.rubberBandExtent = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.rubberBandExtent.setColor(Qt.red) self.rubberBandExtent.setWidth(1) # In case of rotation around pressed point (ctrl) # Use rubberBand for displaying an horizontal line. self.rubberBandDisplacement = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.rubberBandDisplacement.setColor(Qt.red) self.rubberBandDisplacement.setWidth(1) self.reset() def setLayer(self, layer): self.layer = layer def reset(self): self.startPoint = self.endPoint = None self.isEmittingPoint = False self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) self.rasterShadow.reset() self.layer = None def canvasPressEvent(self, e): self.startY = e.pos().y() self.endY = self.startY self.isEmittingPoint = True self.height = self.canvas.height() modifiers = QApplication.keyboardModifiers() self.isRotationAroundPoint = bool(modifiers & Qt.ControlModifier) self.startPoint = self.toMapCoordinates(e.pos()) self.endPoint = self.startPoint self.isLayerVisible = isLayerVisible(self.iface, self.layer) setLayerVisible(self.iface, self.layer, False) rotation = self.computeRotation() self.showRotation(rotation) self.layer.history.append({ "action": "rotation", "rotation": self.layer.rotation, "center": self.layer.center }) # rotation set def canvasReleaseEvent(self, e): self.isEmittingPoint = False self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) self.rasterShadow.reset() rotation = self.computeRotation() if self.isRotationAroundPoint: self.layer.moveCenterFromPointRotate(self.startPoint, rotation, 1, 1) val = self.layer.rotation + rotation self.layer.setRotation(val) setLayerVisible(self.iface, self.layer, self.isLayerVisible) self.layer.repaint() self.layer.commitTransformParameters() def canvasMoveEvent(self, e): if not self.isEmittingPoint: return self.endY = e.pos().y() rotation = self.computeRotation() self.showRotation(rotation) self.endPoint = self.toMapCoordinates(e.pos()) def computeRotation(self): if self.isRotationAroundPoint: dX = self.endPoint.x() - self.startPoint.x() dY = self.endPoint.y() - self.startPoint.y() return math.degrees(math.atan2(-dY, dX)) else: dY = self.endY - self.startY return 90.0 * dY / self.height def showRotation(self, rotation): if self.isRotationAroundPoint: cornerPoints = self.layer.transformedCornerCoordinatesFromPoint( self.startPoint, rotation, 1, 1) self.rasterShadow.reset(self.layer) self.rasterShadow.setDeltaRotationFromPoint( rotation, self.startPoint, True) self.rasterShadow.show() self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) point0 = QgsPointXY(self.startPoint.x() + 10, self.startPoint.y()) point1 = QgsPointXY(self.startPoint.x(), self.startPoint.y()) point2 = QgsPointXY(self.endPoint.x(), self.endPoint.y()) self.rubberBandDisplacement.addPoint(point0, False) self.rubberBandDisplacement.addPoint(point1, False) self.rubberBandDisplacement.addPoint(point2, True) # true to update canvas self.rubberBandDisplacement.show() else: center, originalRotation, xScale, yScale = \ self.layer.transformParameters() newRotation = rotation + originalRotation cornerPoints = self.layer.transformedCornerCoordinates( center, newRotation, xScale, yScale) self.rasterShadow.reset(self.layer) self.rasterShadow.setDeltaRotation(rotation, True) self.rasterShadow.show() self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) for point in cornerPoints: self.rubberBandExtent.addPoint(point, False) # for closing self.rubberBandExtent.addPoint(cornerPoints[0], True) self.rubberBandExtent.show()
class ProfileTool(QgsMapTool): """ Narzędzie do tworzenia krzywej """ def __init__(self, parent): canvas = iface.mapCanvas() super(ProfileTool, self).__init__(canvas) set_cursor(self) self.editing = False self.parent = parent self.task = None self.tempGeom = QgsRubberBand(canvas, QgsWkbTypes.LineGeometry) self.tempGeom.setColor(QColor('red')) self.tempGeom.setWidth(2) self.tempLine = QgsRubberBand(canvas, QgsWkbTypes.LineGeometry) self.tempLine.setColor(QColor('red')) self.tempLine.setWidth(2) self.tempLine.setLineStyle(Qt.DotLine) def keyPressEvent(self, e): if e.key() == Qt.Key_Delete: pointsCount = self.tempLine.numberOfVertices() if pointsCount > 2 and self.editing: self.tempGeom.removePoint(pointsCount-2) self.tempLine.removePoint(pointsCount-2) len_m = self.calculateDistance(self.tempGeom.asGeometry()) self.parent.dsbLineLength.setValue(len_m) if self.tempGeom.numberOfVertices() == 1: self.tempGeom.reset(QgsWkbTypes.LineGeometry) self.tempLine.reset(QgsWkbTypes.LineGeometry) self.parent.dsbLineLength.setValue(0) else: self.reset() elif e.key() == Qt.Key_Escape: self.reset() def canvasMoveEvent(self, e): #Poruszanie" wierzchołkiem linii tymczasowej zgodnie z ruchem myszki if self.tempGeom.numberOfVertices()>1: point = e.snapPoint() self.tempLine.movePoint(point) def canvasReleaseEvent(self, e): point = e.snapPoint() if self.task: self.parent.on_message.emit('Trwa genrowanie profilu. Aby wygenerować następny poczekaj na pobranie danych', Qgis.Warning, 4) return if e.button() == int(Qt.LeftButton): #Dodawanie kolejnych wierzchołków if not self.editing: #Nowy obiekt, pierwszy wierzchołek self.tempLine.reset(QgsWkbTypes.LineGeometry) self.tempGeom.reset(QgsWkbTypes.LineGeometry) self.editing = True self.tempGeom.addPoint(point) self.tempLine.addPoint(point) len_m = self.calculateDistance(self.tempGeom.asGeometry()) self.parent.dsbLineLength.setValue(len_m) elif e.button() == int(Qt.RightButton): if self.tempGeom.numberOfVertices() < 2: return #Zakończenie rysowania obiektu self.tempLine.reset() self.editing = False geometry = self.tempGeom.asGeometry() errors = geometry.validateGeometry() if errors: #Niepoprawna geometria for error in errors: if self.tempGeom.numberOfVertices() > 2: self.parent.on_message.emit('Niepoprawna geometria', Qgis.Critical, 4) self.tempGeom.reset() return self.get_interval() def get_interval(self): interval, ok = QInputDialog.getDouble(self.parent, 'Podaj interwał', 'Interwał [m]:') if not ok: self.reset() return geom = self.tempGeom.asGeometry() activeCrs = QgsProject.instance().crs().authid() fromCrs = QgsCoordinateReferenceSystem(activeCrs) toCrs = QgsCoordinateReferenceSystem(2180) transformation = QgsCoordinateTransform(fromCrs, toCrs, QgsProject.instance()) geom.transform(transformation) meters_len = geom.length() if meters_len <= interval: self.parent.on_message.emit('Długość linii krótsza lub równa podanemu interwałowi', Qgis.Critical, 5) self.reset() return try: num_points = meters_len/interval except ZeroDivisionError: self.parent.on_message.emit('Interwał musi być większy od 0', Qgis.Critical, 4) self.reset() return points_on_line = [] max_interval = 0 intervals = [] for i in range(int(num_points)+1): pt = geom.interpolate(float(max_interval)) points_on_line.append(pt) intervals.append(max_interval) max_interval += interval data = {'points':points_on_line, 'intervals':intervals} self.task = QgsTask.fromFunction('Pobieranie wysokości dla przekroju...', self.generateProfileFromPoints, data=data) QgsApplication.taskManager().addTask(self.task) def generateProfileFromPoints(self, task: QgsTask, data): points_on_line = data.get('points') intervals = data.get('intervals') heights = [] total = 100/len(points_on_line) for idx, pt in enumerate(points_on_line): height = self.parent.getHeight(pt, special=True) heights.append(height) try: self.task.setProgress( idx*total ) except AttributeError as e: pass if heights and intervals: self.fillTable(heights, intervals) self.parent.on_message.emit('Pomyślnie wygenerowano profil', Qgis.Success, 4) self.task = None def fillTable(self, heights, intervals): for idx, interval in enumerate(intervals): self.parent.twData.setRowCount(idx+1) self.parent.twData.setItem(idx, 0, QTableWidgetItem(f'{interval}')) self.parent.twData.setItem(idx, 1, QTableWidgetItem(heights[idx])) def calculateDistance(self, geometry): distanceArea = QgsDistanceArea() distanceArea.setEllipsoid('GRS80') distanceArea.setSourceCrs(QgsProject.instance().crs(), QgsCoordinateTransformContext()) length = distanceArea.measureLength(geometry) result = distanceArea.convertLengthMeasurement(length, QgsUnitTypes.DistanceMeters) return result def reset(self): self.tempLine.reset(QgsWkbTypes.LineGeometry) self.tempGeom.reset(QgsWkbTypes.LineGeometry) self.parent.dsbLineLength.setValue(0) self.parent.twData.setRowCount(0) def deactivate(self): self.reset() self.parent.dsbLineLength.setEnabled(False) self.button().setChecked(False)
class QGISRedMoveVertexsTool(QgsMapTool): ownMainLayers = ["Pipes", "Valves", "Pumps"] 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.mouseClicked = False self.clickedPoint = None self.objectSnapped = 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(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 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: 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: 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 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: # # 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): mousePoint = self.toMapCoordinates(event.pos()) if self.mouseClicked: if event.button() == 1: 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.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()
class InfoTool(QgsMapTool): def __init__(self, canvas, snapradius=2): super(InfoTool, self).__init__(canvas) self.canvas = canvas self.radius = snapradius self.selectband = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.selectrect = QRect() self.dragging = False self.selectionlayers = {} def getFeatures(self, rect): # The MS SQL driver seems to crash with a empty rectangle. # Need to check QGIS to patch issue if rect.isEmpty(): return for layer in self.selectionlayers.values(): if (not layer.type() == QgsMapLayer.VectorLayer or layer.geometryType() == QgsWkbTypes.NoGeometry): continue layerrect = self.toLayerCoordinates(layer, rect) rq = QgsFeatureRequest().setFilterRect(layerrect)\ .setFlags(QgsFeatureRequest.ExactIntersect) features = [] for feature in layer.getFeatures(rq): if feature.isValid(): features.append(feature) yield layer, features def toSearchRect(self, point): size = 20 rect = QRectF() rect.setLeft(point.x() - size) rect.setRight(point.x() + size) rect.setTop(point.y() - size) rect.setBottom(point.y() + size) transform = self.canvas.getCoordinateTransform() ll = transform.toMapCoordinates(rect.left(), rect.bottom()) ur = transform.toMapCoordinates(rect.right(), rect.top()) rect = QgsRectangle(ur, ll) return rect def canvasPressEvent(self, event): self.dragging = False self.selectrect.setRect(0, 0, 0, 0) self.selectband = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.selectband.setColor(QColor.fromRgb(0, 0, 255, 65)) self.selectband.setWidth(5) def canvasMoveEvent(self, event): if not event.buttons() == Qt.LeftButton: return if not self.dragging: self.selectrect.setTopLeft(event.pos()) self.dragging = True self.selectrect.setBottomRight(event.pos()) maptoolutils.setRubberBand(self.canvas, self.selectrect, self.selectband) def canvasReleaseEvent(self, event): if self.dragging: geometry = self.selectband.asGeometry() if not geometry: return rect = geometry.boundingBox() else: rect = self.toSearchRect(event.pos()) self.dragging = False self.selectband.reset() results = OrderedDict((l, f) for l, f in self.getFeatures(rect)) RoamEvents.selectioncleared.emit() RoamEvents.selectionchanged.emit(results)
class SelectFeaturesTool(QgsMapTool): selection_clicked = pyqtSignal(list) def __init__(self, mission_track, canvas): QgsMapTool.__init__(self, canvas) self.setCursor(Qt.ArrowCursor) self.mission_track = mission_track self.layer = self.mission_track.get_mission_layer() self.rubber_band = None self.rubber_band_points = None self.selection_polygon = [] self.indexes_within_list = [] self.band_finished = True self.mCtrl = False self.p0, self.p1, self.p2, self.p3 = None, None, None, None self.mission_track.mission_changed.connect(self.update_rubber_band) self.mission_track.step_removed.connect(self.remove_rubber_band) self.wp = self.mission_track.find_waypoints_in_mission() self.layer.startEditing() self.rubber_band_vs_track_indexes = {} self.rubber_band_points = QgsRubberBand(self.canvas(), QgsWkbTypes.PointGeometry) self.rubber_band_points.setIcon(QgsRubberBand.ICON_CIRCLE) self.rubber_band_points.setIconSize(10) self.rubber_band_points.setColor(QColor("green")) self.rubber_band_vertex_counter = 0 def keyPressEvent(self, event): if event.key() == Qt.Key_Control: self.mCtrl = True def keyReleaseEvent(self, event): if event.key() == Qt.Key_Control: self.mCtrl = False if event.key() == Qt.Key_Escape: self.p0, self.p1, self.p2, self.p3 = None, None, None, None if self.rubber_band: self.rubber_band.reset(True) self.close_polygon_band() self.band_finished = True self.canvas().refresh() return def canvasPressEvent(self, event): if event.button() == Qt.LeftButton: point = self.toMapCoordinates(event.pos()) # check if we have clicked on a vertex tolerance = self.calc_tolerance() vertex = self.find_vertex_at(event.pos(), tolerance) if self.mCtrl and vertex is not None: # if we have clicked on a vertex, identify which one # check if was already in the selection list if vertex not in self.indexes_within_list: # add it self.indexes_within_list.append(vertex) self.update_rubber_band() else: # remove it self.indexes_within_list.remove(vertex) self.update_rubber_band() self.band_finished = True elif vertex is None: # if we have not clicked on a vertex and there's no polygon band, start it if not len(self.selection_polygon ) and self.band_finished and not self.mCtrl: self.selection_clicked.emit(list()) self.band_finished = False self.rubber_band = QgsRubberBand( self.canvas(), QgsWkbTypes.PolygonGeometry) self.rubber_band.setWidth(2) select_green = QColor("green") select_green.setAlpha(128) self.rubber_band.setColor(select_green) if event.button() == Qt.LeftButton: # Left click -> add vertex self.p0 = QgsPointXY(point.x(), point.y()) self.selection_polygon.append(self.p0) elif len(self.selection_polygon) == 1 and not self.mCtrl: if event.button() == Qt.LeftButton: # Left click -> add vertex self.p2 = QgsPointXY(point.x(), point.y()) self.p1 = QgsPointXY(self.p2.x(), self.p0.y()) self.p3 = QgsPointXY(self.p0.x(), self.p2.y()) self.selection_polygon.append(self.p1) self.selection_polygon.append(self.p2) self.selection_polygon.append(self.p3) self.band_finished = True self.set_selection() self.close_polygon_band() self.selection_clicked.emit(self.indexes_within_list) def find_vertex_at(self, pos, tolerance): """ get the vertex that is closer to the clicked point :param pos: The point that we've clicked :param tolerance: The tolerance of pos :return: vertex or None """ if len(self.wp) > 0: dist_to_vertex = [] for v in range(0, len(self.wp)): a1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v])) dist_to_vertex.append( math.sqrt((pos.x() - a1.x())**2 + (pos.y() - a1.y())**2)) vertex = dist_to_vertex.index(min(dist_to_vertex)) if min(dist_to_vertex) > tolerance: return None else: return vertex else: return None def calc_tolerance(self): """ Compute the tolerance on canvas :return: tolerance """ # 2% of tolerance width_tolerance = 0.02 * self.canvas().width() height_tolerance = 0.02 * self.canvas().height() if width_tolerance < height_tolerance: tolerance = width_tolerance else: tolerance = height_tolerance return tolerance def canvasMoveEvent(self, event): if not self.band_finished and not self.mCtrl: self.p2 = self.toMapCoordinates(event.pos()) self.p1 = QgsPointXY(self.p2.x(), self.p0.y()) self.p3 = QgsPointXY(self.p0.x(), self.p2.y()) self.selection_polygon.append(self.p1) self.selection_polygon.append(self.p2) self.selection_polygon.append(self.p3) self.rubber_band.setToGeometry( QgsGeometry.fromPolygonXY([self.selection_polygon]), None) self.selection_polygon.pop() self.selection_polygon.pop() self.selection_polygon.pop() def set_selection(self): """ Set vertices highlight according to polygon """ # Check which features are within the polygon mission_track = self.layer.getFeatures() # get mission track feature for f in mission_track: # loop although mission layer only has one feature vertices_it = f.geometry().vertices() polygon_geom = QgsGeometry.fromPolygonXY([self.selection_polygon]) vertices_within_list = [] # self.indexes_within_list = [] vertex_index = 0 # Highlight them using a point rubber band self.rubber_band_vertex_counter = 0 for v in vertices_it: point_geom = QgsGeometry.fromPointXY(QgsPointXY(v.x(), v.y())) if point_geom.within(polygon_geom): vertices_within_list.append(v) if not (vertex_index in self.indexes_within_list ): # only add if not already present self.indexes_within_list.append(vertex_index) self.rubber_band_points.addPoint(QgsPointXY(v.x(), v.y())) self.rubber_band_vertex_counter = self.rubber_band_vertex_counter + 1 self.rubber_band_vs_track_indexes[ vertex_index] = self.rubber_band_vertex_counter - 1 vertex_index = vertex_index + 1 def update_rubber_band(self): if self.rubber_band_points: self.rubber_band_points.reset(QgsWkbTypes.PointGeometry) self.rubber_band_vs_track_indexes = {} self.rubber_band_vertex_counter = 0 self.wp = self.mission_track.find_waypoints_in_mission() if len(self.indexes_within_list) > 0: selected_vertices = self.mission_track.find_waypoints_in_mission( self.indexes_within_list) for v in selected_vertices: vertex_index = 0 for point in self.wp: if v == point: pc = self.toLayerCoordinates(self.layer, QgsPointXY(v)) self.rubber_band_points.addPoint(pc) self.rubber_band_vertex_counter = self.rubber_band_vertex_counter + 1 self.rubber_band_vs_track_indexes[ vertex_index] = self.rubber_band_vertex_counter - 1 vertex_index = vertex_index + 1 self.set_geometry() def remove_rubber_band(self, wp): # if self.rubber_band_points: # self.rubber_band_points.reset(QgsWkbTypes.PointGeometry) self.indexes_within_list.remove(wp) self.update_rubber_band() def set_geometry(self): """ Save rubber band to geometry of the layer """ if self.layer.featureCount() == 0: # no feature yet created f = QgsFeature() if len(self.wp) == 1: f.setGeometry( QgsGeometry.fromPointXY( QgsPointXY(self.wp[0].x(), self.wp[0].y()))) else: f.setGeometry(QgsGeometry.fromPolyline(self.wp)) # self.layer.dataProvider().addFeatures([f]) self.layer.addFeatures([f]) else: # mission feature present, edit geometry feats = self.layer.getFeatures() for f in feats: if len(self.wp) == 1: self.layer.changeGeometry( f.id(), QgsGeometry.fromPointXY( QgsPointXY(self.wp[0].x(), self.wp[0].y()))) else: self.layer.changeGeometry( f.id(), QgsGeometry.fromPolyline(self.wp)) self.layer.commitChanges() self.layer.startEditing() def close_polygon_band(self): self.selection_polygon = [] if self.rubber_band is not None: self.rubber_band.reset() self.canvas().scene().removeItem(self.rubber_band) self.rubber_band = None def close_highlight_band(self): self.rubber_band_points.reset() self.canvas().scene().removeItem(self.rubber_band_points) self.rubber_band_points = None def deactivate(self): if self.rubber_band: self.close_polygon_band() if self.rubber_band_points: self.close_highlight_band() try: self.mission_track.mission_changed.disconnect( self.update_rubber_band) self.mission_track.step_removed.disconnect(self.remove_rubber_band) except: logger.info("no connected to signal") self.layer.commitChanges()
class AdvancedIntersectionMapTool(QgsMapTool): def __init__(self, iface): self.iface = iface self.mapCanvas = iface.mapCanvas() QgsMapTool.__init__(self, self.mapCanvas) self.settings = MySettings() self.rubber = QgsRubberBand(self.mapCanvas) self.tolerance = self.settings.value("selectTolerance") units = self.settings.value("selectUnits") if units == "pixels": self.tolerance *= self.mapCanvas.mapUnitsPerPixel() def activate(self): QgsMapTool.activate(self) self.rubber.setWidth(self.settings.value("rubberWidth")) self.rubber.setColor(self.settings.value("rubberColor")) line_layer = MemoryLayers(self.iface).line_layer() # unset this tool if the layer is removed line_layer.layerDeleted.connect(self.unsetMapTool) self.layerId = line_layer.id() # create snapper for this layer self.snapLayer = QgsSnapper.SnapLayer() self.snapLayer.mLayer = line_layer self.snapLayer.mSnapTo = QgsSnapper.SnapToVertexAndSegment self.snapLayer.mTolerance = self.settings.value("selectTolerance") if self.settings.value("selectUnits") == "map": self.snapLayer.mUnitType = QgsTolerance.MapUnits else: self.snapLayer.mUnitType = QgsTolerance.Pixels def unsetMapTool(self): self.mapCanvas.unsetMapTool(self) def deactivate(self): self.rubber.reset() line_layer = QgsMapLayerRegistry.instance().mapLayer(self.layerId) if line_layer is not None: line_layer.layerDeleted.disconnect(self.unsetMapTool) QgsMapTool.deactivate(self) def canvasMoveEvent(self, mouseEvent): # put the observations within tolerance in the rubber band self.rubber.reset() for f in self.getFeatures(mouseEvent.pos()): self.rubber.addGeometry(f.geometry(), None) def canvasPressEvent(self, mouseEvent): pos = mouseEvent.pos() observations = self.getFeatures(pos) point = self.toMapCoordinates(pos) self.doIntersection(point, observations) def getFeatures(self, pixPoint): snapper = QgsSnapper(self.mapCanvas.mapRenderer()) snapper.setSnapLayers([self.snapLayer]) snapper.setSnapMode(QgsSnapper.SnapWithResultsWithinTolerances) ok, snappingResults = snapper.snapPoint(pixPoint, []) # output snapped features features = [] alreadyGot = [] for result in snappingResults: featureId = result.snappedAtGeometry f = QgsFeature() if featureId not in alreadyGot: if result.layer.getFeatures(QgsFeatureRequest().setFilterFid( featureId)).nextFeature(f) is not False: features.append(QgsFeature(f)) alreadyGot.append(featureId) return features def doIntersection(self, initPoint, observations): nObs = len(observations) if nObs < 2: return self.rubber.reset() self.dlg = IntersectionDialog(self.iface, observations, initPoint) if not self.dlg.exec_() or self.dlg.solution is None: return intersectedPoint = self.dlg.solution self.saveIntersectionResult(self.dlg.report, intersectedPoint) self.saveDimension(intersectedPoint, self.dlg.observations) def saveIntersectionResult(self, report, intersectedPoint): # save the intersection result (point) and its report # check first while True: if not self.settings.value("advancedIntersectionWritePoint"): break # if we do not place any point, skip layerid = self.settings.value("advancedIntersectionLayer") message = QCoreApplication.translate( "IntersectIt", "To place the intersection solution," " you must select a layer in the settings.") status, intLayer = self.checkLayerExists(layerid, message) if status == 2: continue if status == 3: return if self.settings.value("advancedIntersectionWriteReport"): reportField = self.settings.value("reportField") message = QCoreApplication.translate( "IntersectIt", "To save the intersection report, please select a field for it." ) status = self.checkFieldExists(intLayer, reportField, message) if status == 2: continue if status == 3: return break # save the intersection results if self.settings.value("advancedIntersectionWritePoint"): f = QgsFeature() f.setGeometry(QgsGeometry().fromPoint(intersectedPoint)) if self.settings.value("advancedIntersectionWriteReport"): irep = intLayer.dataProvider().fieldNameIndex(reportField) f.addAttribute(irep, report) intLayer.dataProvider().addFeatures([f]) intLayer.updateExtents() self.mapCanvas.refresh() def saveDimension(self, intersectedPoint, observations): # check that dimension layer and fields have been set correctly if not self.settings.value( "dimensionDistanceWrite") and not self.settings.value( "dimensionOrientationWrite"): return # if we do not place any dimension, skip obsTypes = ("Distance", "Orientation") recheck = True while recheck: # settings might change during checking, # so recheck both observation types whenever the settings dialog is shown recheck = False for obsType in obsTypes: while True: if not self.settings.value("dimension" + obsType + "Write"): break # check layer layerId = self.settings.value("dimension" + obsType + "Layer") message = QCoreApplication.translate( "IntersectIt", "To place dimensions, " "you must define a layer in the settings.") status, dimLayer = self.checkLayerExists(layerId, message) if status == 2: recheck = True continue if status == 3: return # check fields if self.settings.value("dimension" + obsType + "ObservationWrite"): obsField = self.settings.value("dimension" + obsType + "ObservationField") message = QCoreApplication.translate( "IntersectIt", "To save the observation in the layer," " please select a field for it.") status = self.checkFieldExists(dimLayer, obsField, message) if status == 2: recheck = True continue if status == 3: return if self.settings.value("dimension" + obsType + "PrecisionWrite"): precisionField = self.settings.value("dimension" + obsType + "PrecisionField") message = QCoreApplication.translate( "IntersectIt", "To save the precision of observation," " please select a field for it.") status = self.checkFieldExists(dimLayer, precisionField, message) if status == 2: recheck = True continue if status == 3: return break # save the intersection results for obsType in obsTypes: if self.settings.value("dimension" + obsType + "Write"): layerid = self.settings.value("dimension" + obsType + "Layer") layer = QgsMapLayerRegistry.instance().mapLayer(layerid) if layer is None: continue initFields = layer.dataProvider().fields() features = [] for obs in observations: if obs["type"] != obsType.lower(): continue f = QgsFeature() f.setFields(initFields) f.initAttributes(initFields.size()) if self.settings.value("dimension" + obsType + "ObservationWrite"): f[self.settings.value( "dimension" + obsType + "ObservationField")] = obs["observation"] if self.settings.value("dimension" + obsType + "PrecisionWrite"): f[self.settings.value( "dimension" + obsType + "PrecisionField")] = obs["precision"] p0 = QgsPoint(obs["x"], obs["y"]) p1 = intersectedPoint if obs["type"] == "distance": geom = Arc(p0, p1).geometry() elif obs["type"] == "orientation": geom = QgsGeometry().fromPolyline([p0, p1]) else: raise NameError("Invalid observation %s" % obs["type"]) f.setGeometry(geom) features.append(QgsFeature(f)) if not layer.dataProvider().addFeatures(features): self.iface.messageBar().pushMessage( "Could not commit %s observations" % obsType, QgsMessageBar.CRITICAL) layer.updateExtents() self.mapCanvas.refresh() def checkLayerExists(self, layerid, message): # returns: # 1: layer exists # 2: does not exist, settings has been open, so loop once more (i.e. continue) # 3: does not exist, settings not edited, so cancel layer = QgsMapLayerRegistry.instance().mapLayer(layerid) if layer is not None: return 1, layer reply = QMessageBox.question( self.iface.mainWindow(), "Intersect It", message + " Would you like to open settings?", QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: if MySettingsDialog().exec_(): return 2 return 3 def checkFieldExists(self, layer, field, message): # returns: # 1: field exists # 2: does not exist, settings has been open, so loop once more (i.e. continue) # 3: does not exist, settings not edited, so cancel if layer.dataProvider().fieldNameIndex(field) != -1: return 1 reply = QMessageBox.question( self.iface.mainWindow(), "Intersect It", message + " Would you like to open settings?", QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: if MySettingsDialog().exec_(): return 2 return 3
class DailyImagesSearchResultsWidget(RESULTS_BASE, RESULTS_WIDGET): setAOIRequested = pyqtSignal(dict) checkedCountChanged = pyqtSignal(int) searchSaved = pyqtSignal(dict) def __init__(self): super().__init__() self.setupUi(self) self._p_client = PlanetClient.getInstance() self._has_more = True self._metadata_to_show = [ PlanetNodeMetadata.CLOUD_PERCENTAGE, PlanetNodeMetadata.GROUND_SAMPLE_DISTANCE ] self._image_count = 0 self._total_count = 0 self._request = None self._local_filters = None self._response_iterator = None self.btnSaveSearch.setIcon(SAVE_ICON) self.btnSort.setIcon(SORT_ICON) self.btnAddPreview.setIcon(ADD_PREVIEW_ICON) self.btnAddPreview.setEnabled(False) self.btnSaveSearch.clicked.connect(self._save_search) self.btnAddPreview.clicked.connect(self._add_preview_clicked) self.btnSort.clicked.connect(self._sort_order_changed) self.btnSettings.clicked.connect(self._open_settings) self.lblImageCount.setOpenExternalLinks(False) self.lblImageCount.linkActivated.connect(self.load_more_link_clicked) self._aoi_box = None self._setup_request_aoi_box() self._set_widgets_visibility(False) def _set_widgets_visibility(self, search_ok): self.tree.setVisible(search_ok) self.widgetActions.setVisible(search_ok) self.widgetNoResults.setVisible(not search_ok) def search_has_been_performed(self): return self._request is not None def _open_settings(self): dlg = ResultsConfigurationDialog(self._metadata_to_show) if dlg.exec_(): self._metadata_to_show = dlg.selection self.update_image_items() def _add_preview_clicked(self): self.add_preview() @waitcursor def add_preview(self): imgs = self.selected_images() if is_segments_write_key_valid(): item_ids = [ f"{img['properties'][ITEM_TYPE]}:{img[ID]}" for img in imgs ] analytics.track(PlanetClient.getInstance().user()["email"], "Scene preview added to map", {"images": item_ids}) create_preview_group("Selected images", imgs) def update_image_items(self): it = QTreeWidgetItemIterator(self.tree) while it.value(): item = it.value() if isinstance(item, SceneItem): w = self.tree.itemWidget(item, 0) w.set_metadata_to_show(self._metadata_to_show) it += 1 def _save_search(self): dlg = SaveSearchDialog(self._request) if dlg.exec_(): self._p_client.create_search(dlg.request_to_save) self.searchSaved.emit(dlg.request_to_save) def sort_order(self): order = ["acquired"] if self.btnSort.isChecked(): order.append("asc") else: order.append("desc") return order def _sort_order_changed(self): self.update_request(self._request, {}) def load_more_link_clicked(self): self.load_more() @waitcursor def update_request(self, request, local_filters): self._image_count = 0 self._request = request self._local_filters = local_filters self.tree.clear() stats_request = {"interval": "year"} stats_request.update(self._request) resp = self._p_client.stats(stats_request).get() self._total_count = sum([b["count"] for b in resp["buckets"]]) if self._total_count: response = self._p_client.quick_search(self._request, page_size=TOP_ITEMS_BATCH, sort=' '.join( self.sort_order())) self._response_iterator = response.iter() self.load_more() self._set_widgets_visibility(True) else: self._set_widgets_visibility(False) @waitcursor def load_more(self): page = next(self._response_iterator, None) if page is not None: for i in range(self.tree.topLevelItemCount()): date_item = self.tree.topLevelItem(i) date_widget = self.tree.itemWidget(date_item, 0) date_widget.has_new = False for j in range(date_item.childCount()): satellite_item = date_item.child(j) satellite_widget = self.tree.itemWidget(satellite_item, 0) satellite_widget.has_new = False links = page.get()[page.LINKS_KEY] next_ = links.get(page.NEXT_KEY, None) self._has_more = next_ is not None images = page.get().get(page.ITEM_KEY) for i, image in enumerate(images): if self._passes_area_coverage_filter(image): sort_criteria = "acquired" date_item, satellite_item = self._find_items_for_satellite( image) date_widget = self.tree.itemWidget(date_item, 0) satellite_widget = self.tree.itemWidget(satellite_item, 0) item = SceneItem(image, sort_criteria) widget = SceneItemWidget(image, sort_criteria, self._metadata_to_show, item) widget.checkedStateChanged.connect( self.checked_count_changed) widget.checkedStateChanged.connect( satellite_widget.update_checkbox) widget.thumbnailChanged.connect( satellite_widget.update_thumbnail) item.setSizeHint(0, widget.sizeHint()) satellite_item.addChild(item) self.tree.setItemWidget(item, 0, widget) date_widget.update_for_children() self._image_count += 1 for i in range(self.tree.topLevelItemCount()): date_item = self.tree.topLevelItem(i) date_widget = self.tree.itemWidget(date_item, 0) for j in range(date_item.childCount()): satellite_item = date_item.child(j) satellite_widget = self.tree.itemWidget(satellite_item, 0) satellite_widget.update_for_children() satellite_widget.update_thumbnail() satellite_item.sortChildren(0, Qt.AscendingOrder) date_widget.update_for_children() date_widget.update_thumbnail() self.item_count_changed() else: self._has_more = False self.item_count_changed() def _local_filter(self, name): for f in self._local_filters: if f.get("field_name") == name: return f def _passes_area_coverage_filter(self, image): aoi_geom = geometry_from_request(self._request) if aoi_geom is None: return True # an ID filter is begin used, so it makes no sense to # check for are acoverage aoi_qgsgeom = qgsgeometry_from_geojson(aoi_geom) image_qgsgeom = qgsgeometry_from_geojson(image[GEOMETRY]) filt = self._local_filter('area_coverage') if filt: minvalue = filt['config'].get('gte', 0) maxvalue = filt['config'].get('lte', 100) intersection = aoi_qgsgeom.intersection(image_qgsgeom) area_coverage = intersection.area() / aoi_qgsgeom.area() * 100 return area_coverage > minvalue and area_coverage < maxvalue return True def _find_item_for_date(self, image): sort_criteria = "acquired" date = iso8601.parse_date(image[PROPERTIES][sort_criteria]).date() itemtype = image[PROPERTIES][ITEM_TYPE] count = self.tree.topLevelItemCount() for i in range(count): child = self.tree.topLevelItem(i) if child.date == date and child.itemtype == itemtype: return child date_item = DateItem(image, sort_criteria) widget = DateItemWidget(image, sort_criteria, date_item) date_item.setSizeHint(0, widget.sizeHint()) self.tree.addTopLevelItem(date_item) self.tree.setItemWidget(date_item, 0, widget) return date_item def _find_items_for_satellite(self, image): date_item = self._find_item_for_date(image) date_widget = self.tree.itemWidget(date_item, 0) satellite = image[PROPERTIES][SATELLITE_ID] count = date_item.childCount() for i in range(count): child = date_item.child(i) if child.satellite == satellite: return date_item, child satellite_item = SatelliteItem(satellite) widget = SatelliteItemWidget(satellite, satellite_item) widget.checkedStateChanged.connect(date_widget.update_checkbox) widget.thumbnailChanged.connect(date_widget.update_thumbnail) satellite_item.setSizeHint(0, widget.sizeHint()) date_item.addChild(satellite_item) self.tree.setItemWidget(satellite_item, 0, widget) return date_item, satellite_item def selected_images(self): selected = [] it = QTreeWidgetItemIterator(self.tree) while it.value(): item = it.value() if isinstance(item, SceneItem): w = self.tree.itemWidget(item, 0) w.set_metadata_to_show(self._metadata_to_show) if w.is_selected(): selected.append(w.image) it += 1 return selected def checked_count_changed(self): hasSelection = bool(len(self.selected_images())) self.btnAddPreview.setEnabled(hasSelection) self.checkedCountChanged.emit(hasSelection) def item_count_changed(self): if self._image_count < self._total_count: self.lblImageCount.setText( f"{self._image_count} images. <a href='#'>Load more</a>") else: self.lblImageCount.setText(f"{self._image_count} images") def _setup_request_aoi_box(self): self._aoi_box = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self._aoi_box.setFillColor(QColor(0, 0, 0, 0)) self._aoi_box.setStrokeColor(SEARCH_AOI_COLOR) self._aoi_box.setWidth(2) self._aoi_box.setLineStyle(Qt.DashLine) @pyqtSlot() def clear_aoi_box(self): if self._aoi_box: self._aoi_box.reset(QgsWkbTypes.PolygonGeometry) def clean_up(self): self.clear_aoi_box() self.tree.clear() self.lblImageCount.setText("") self._set_widgets_visibility(False) def closeEvent(self, event): self.clean_up() super().closeEvent(self, event) def request_query(self): return self._request
class RectangleMapTool(QgsMapToolEmitPoint): rectangleCreated = pyqtSignal() deactivated = pyqtSignal() def __init__(self, canvas): self.canvas = canvas QgsMapToolEmitPoint.__init__(self, self.canvas) self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.rubberBand.setColor(QColor(255, 0, 0, 100)) self.rubberBand.setWidth(2) self.reset() def reset(self): self.startPoint = self.endPoint = None self.isEmittingPoint = False self.rubberBand.reset(QgsWkbTypes.PolygonGeometry) def canvasPressEvent(self, e): self.startPoint = self.toMapCoordinates(e.pos()) self.endPoint = self.startPoint self.isEmittingPoint = True self.showRect(self.startPoint, self.endPoint) def canvasReleaseEvent(self, e): self.isEmittingPoint = False if self.rectangle() is not None: self.rectangleCreated.emit() def canvasMoveEvent(self, e): if not self.isEmittingPoint: return self.endPoint = self.toMapCoordinates(e.pos()) self.showRect(self.startPoint, self.endPoint) def showRect(self, startPoint, endPoint): self.rubberBand.reset(QgsWkbTypes.PolygonGeometry) if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y(): return point1 = QgsPointXY(startPoint.x(), startPoint.y()) point2 = QgsPointXY(startPoint.x(), endPoint.y()) point3 = QgsPointXY(endPoint.x(), endPoint.y()) point4 = QgsPointXY(endPoint.x(), startPoint.y()) self.rubberBand.addPoint(point1, False) self.rubberBand.addPoint(point2, False) self.rubberBand.addPoint(point3, False) # True to update canvas self.rubberBand.addPoint(point4, True) self.rubberBand.show() def rectangle(self): if self.startPoint is None or self.endPoint is None: return None elif self.startPoint.x() == self.endPoint.x() or \ self.startPoint.y() == self.endPoint.y(): return None return QgsRectangle(self.startPoint, self.endPoint) def setRectangle(self, rect): if rect == self.rectangle(): return False if rect is None: self.reset() else: self.startPoint = QgsPointXY(rect.xMaximum(), rect.yMaximum()) self.endPoint = QgsPointXY(rect.xMinimum(), rect.yMinimum()) self.showRect(self.startPoint, self.endPoint) return True def deactivate(self): QgsMapTool.deactivate(self) self.deactivated.emit()
class MapWidget(Ui_CanvasWidget, QMainWindow): def __init__(self, parent=None): super(MapWidget, self).__init__(parent) self.setupUi(self) self.firstshow = True self.layerbuttons = [] self.editfeaturestack = [] self.lastgpsposition = None self.project = None self.gps = None self.gpslogging = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) if hasattr(self.canvas, 'setParallelRenderingEnabled'): self.canvas.setParallelRenderingEnabled(True) pal = QgsPalLabeling() self.canvas.mapRenderer().setLabelingEngine(pal) self.canvas.setFrameStyle(QFrame.NoFrame) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) self.actionGPS = GPSAction(":/icons/gps", self.canvas, self) self.projecttoolbar.addAction(self.actionGPS) gpsspacewidget= QWidget() gpsspacewidget.setMinimumWidth(30) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget(self.actionGPS, gpsspacewidget) self.dataentryselection = QAction(self.projecttoolbar) self.dataentryaction = self.projecttoolbar.insertAction(self.topspaceraction, self.dataentryselection) self.dataentryselection.triggered.connect(self.select_data_entry) self.marker = GPSMarker(self.canvas) self.marker.hide() self.currentfeatureband = QgsRubberBand(self.canvas) self.currentfeatureband.setIconSize(20) self.currentfeatureband.setWidth(10) self.currentfeatureband.setColor(QColor(186, 93, 212, 76)) self.gpsband = QgsRubberBand(self.canvas) self.gpsband.setColor(QColor(0, 0, 212, 76)) self.gpsband.setWidth(5) RoamEvents.editgeometry.connect(self.queue_feature_for_edit) RoamEvents.selectioncleared.connect(self.clear_selection) RoamEvents.selectionchanged.connect(self.highlight_selection) RoamEvents.featureformloaded.connect(self.feature_form_loaded) self.connectButtons() def init_qgisproject(self, doc): parser = ProjectParser(doc) canvasnode = parser.canvasnode self.canvas.freeze() self.canvas.mapRenderer().readXML(canvasnode) self.canvaslayers = parser.canvaslayers() self.canvas.setLayerSet(self.canvaslayers) #red = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorRedPart", 255 )[0]; #green = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorGreenPart", 255 )[0]; #blue = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorBluePart", 255 )[0]; #color = QColor(red, green, blue); #self.canvas.setCanvasColor(color) self.canvas.updateScale() return self.canvas.mapRenderer().destinationCrs() def showEvent(self, *args, **kwargs): if self.firstshow: self.canvas.refresh() self.canvas.repaint() self.firstshow = False def feature_form_loaded(self, form, feature, project, editmode): self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer) def highlight_selection(self, results): self.clear_selection() for layer, features in results.iteritems(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0, 200)) band.setIconSize(20) band.setWidth(2) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) for feature in features: band.addGeometry(feature.geometry(), layer) def highlight_active_selection(self, layer, feature, features): self.clear_selection() self.highlight_selection({layer: features}) self.currentfeatureband.setToGeometry(feature.geometry(), layer) def clear_selection(self): # Clear the main selection rubber band self.currentfeatureband.reset() # Clear the rest for band in self.selectionbands.itervalues(): band.reset() self.editfeaturestack = [] def queue_feature_for_edit(self, form, feature): def trigger_default_action(): for action in self.projecttoolbar.actions(): if action.property('dataentry') and action.isdefault: action.trigger() break self.editfeaturestack.append((form, feature)) self.load_form(form) trigger_default_action() def clear_temp_objects(self): def clear_tool_band(): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass self.currentfeatureband.reset() clear_tool_band() def settings_updated(self, settings): self.actionGPS.updateGPSPort() gpslogging = settings.get('gpslogging', True) if self.gpslogging: self.gpslogging.logging = gpslogging def set_gps(self, gps, logging): self.gps = gps self.gpslogging = logging self.gps.gpsposition.connect(self.gps_update_canvas) self.gps.firstfix.connect(self.gps_first_fix) self.gps.gpsdisconnected.connect(self.gps_disconnected) def gps_update_canvas(self, position, gpsinfo): # Recenter map if we go outside of the 95% of the area if self.gpslogging.logging: self.gpsband.addPoint(position) self.gpsband.show() if roam.config.settings.get('gpscenter', True): if not self.lastgpsposition == position: self.lastposition = position rect = QgsRectangle(position, position) extentlimt = QgsRectangle(self.canvas.extent()) extentlimt.scale(0.95) if not extentlimt.contains(position): self.zoom_to_location(position) self.marker.show() self.marker.setCenter(position) def gps_first_fix(self, postion, gpsinfo): zoomtolocation = roam.config.settings.get('gpszoomonfix', True) if zoomtolocation: self.canvas.zoomScale(1000) self.zoom_to_location(postion) def zoom_to_location(self, position): rect = QgsRectangle(position, position) self.canvas.setExtent(rect) self.canvas.refresh() def gps_disconnected(self): self.marker.hide() def select_data_entry(self): def showformerror(form): pass def actions(): for form in self.project.forms: action = form.createuiaction() valid, failreasons = form.valid if not valid: roam.utils.warning("Form {} failed to load".format(form.label)) roam.utils.warning("Reasons {}".format(failreasons)) action.triggered.connect(partial(showformerror, form)) else: action.triggered.connect(partial(self.load_form, form)) yield action formpicker = PickActionDialog(msg="Select data entry form") formpicker.addactions(actions()) formpicker.exec_() def project_loaded(self, project): self.project = project self.actionPan.trigger() try: firstform = project.forms[0] self.load_form(firstform) self.dataentryselection.setVisible(True) except IndexError: self.dataentryselection.setVisible(False) # Enable the raster layers button only if the project contains a raster layer. layers = QgsMapLayerRegistry.instance().mapLayers().values() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) self.infoTool.selectionlayers = project.selectlayersmapping() self.canvas.freeze(False) self.canvas.refresh() def setMapTool(self, tool, *args): self.canvas.setMapTool(tool) def connectButtons(self): def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24,24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = PanTool(self.canvas) self.infoTool = InfoTool(self.canvas) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/info')) self.actionRaster.triggered.connect(self.toggleRasterLayers) self.infoTool.infoResults.connect(RoamEvents.selectionchanged.emit) self.actionHome.triggered.connect(self.homeview) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def load_form(self, form): self.clearCapatureTools() self.dataentryselection.setIcon(QIcon(form.icon)) self.dataentryselection.setText(form.icontext) self.create_capture_buttons(form) def create_capture_buttons(self, form): tool = form.getMaptool()(self.canvas) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) action.setChecked(action.isdefault) if hasattr(tool, 'geometryComplete'): add = partial(self.add_new_feature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(partial(self.showUIMessage, form.label)) def add_new_feature(self, form, geometry): """ Add a new new feature to the given layer """ # TODO Extract into function. # NOTE This function is doing too much, acts as add and also edit. layer = form.QGISLayer if layer.geometryType() in [QGis.WKBMultiLineString, QGis.WKBMultiPoint, QGis.WKBMultiPolygon]: geometry.convertToMultiType() try: form, feature = self.editfeaturestack.pop() self.editfeaturegeometry(form, feature, newgeometry=geometry) return except IndexError: pass layer = form.QGISLayer fields = layer.pendingFields() feature = QgsFeature(fields) feature.setGeometry(geometry) for index in xrange(fields.count()): pkindexes = layer.dataProvider().pkAttributeIndexes() if index in pkindexes and layer.dataProvider().name() == 'spatialite': continue value = layer.dataProvider().defaultValue(index) feature[index] = value RoamEvents.open_feature_form(form, feature, editmode=False) def editfeaturegeometry(self, form, feature, newgeometry): # TODO Extract into function. layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() if not saved: map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() self.currentfeatureband.setToGeometry(feature.geometry(), layer) RoamEvents.editgeometry_complete.emit(form, feature) def clearCapatureTools(self): captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ if not self.canvaslayers: return #Freeze the canvas to save on UI refresh self.canvas.freeze() for layer in self.canvaslayers: if layer.layer().type() == QgsMapLayer.RasterLayer: layer.setVisible(not layer.isVisible()) # Really!? We have to reload the whole layer set every time? # WAT? self.canvas.setLayerSet(self.canvaslayers) self.canvas.freeze(False) self.canvas.refresh() def cleanup(self): self.gpsband.reset() self.gpsband.hide() self.clear_selection() self.clear_temp_objects() self.clearCapatureTools() self.canvas.freeze() self.canvas.clear() self.canvas.freeze(False) for action in self.layerbuttons: self.editgroup.removeAction(action)
class VoGISProfilToolMainDialog(QDialog): def __init__(self, interface, settings): self.settings = settings self.iface = interface self.selectingVisibleRasters = False self.thread = None QDialog.__init__(self, interface.mainWindow()) # Set up the user interface from Designer. self.ui = Ui_VoGISProfilToolMain() self.ui.setupUi(self) if self.settings.onlyHektoMode is True: self.ui.IDC_widRaster.hide() self.adjustSize() validator = QIntValidator(-32768, 32768, self) self.ui.IDC_tbNoDataExport.setValidator(validator) self.ui.IDC_tbFromX.setText('-30000') self.ui.IDC_tbFromY.setText('240000') self.ui.IDC_tbToX.setText('-20000') self.ui.IDC_tbToY.setText('230000') self.__addRastersToGui() self.__addPolygonsToGui() for line_lyr in self.settings.mapData.lines.lines(): self.ui.IDC_cbLineLayers.addItem(line_lyr.name, line_lyr) if self.settings.mapData.lines.count() < 1: self.ui.IDC_rbDigi.setChecked(True) self.ui.IDC_rbShapeLine.setEnabled(False) #Einstellungen fuer Linie zeichen self.action = QAction(QIcon(":/plugins/vogisprofiltoolmain/icons/icon.png"), "VoGIS-Profiltool", self.iface.mainWindow()) self.action.setWhatsThis("VoGIS-Profiltool") self.canvas = self.iface.mapCanvas() self.tool = ProfiletoolMapTool(self.canvas, self.action) self.savedTool = self.canvas.mapTool() self.polygon = False self.rubberband = QgsRubberBand(self.canvas, self.polygon) if QGis.QGIS_VERSION_INT >= 10900: #self.rubberband.setBrushStyle() self.rubberband.setLineStyle(Qt.SolidLine) self.rubberband.setWidth(4.0) self.rubberband.setColor(QColor(0, 255, 0)) #http://www.qgis.org/api/classQgsRubberBand.html#a6f7cdabfcf69b65dfc6c164ce2d01fab self.pointsToDraw = [] self.dblclktemp = None self.drawnLine = None def accept(self): try: #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", "ACCEPTED") #QgsMessageLog.logMessage('nodata: {0}'.format(self.settings.nodata_value), 'VoGis') self.settings.nodata_value = int(self.ui.IDC_tbNoDataExport.text()) QgsMessageLog.logMessage('maindlg: nodata: {0}'.format(self.settings.nodata_value), 'VoGis') if self.settings.onlyHektoMode is True and self.settings.mapData.rasters.count() > 0: self.settings.onlyHektoMode = False if self.settings.onlyHektoMode is False: if self.settings.mapData.rasters.count() < 1: #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", u"Keine Raster vorhanden. Zum Hektometrieren Dialog neu öffnen.") #return retVal = QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', 'Keine Rasterebene vorhanden oder sichtbar! Nur hektometrieren?', None, QApplication.UnicodeUTF8), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if retVal == QMessageBox.No: return else: self.settings.onlyHektoMode = True self.settings.createHekto = True if self.__getSettingsFromGui() is False: return if self.settings.onlyHektoMode is False: if len(self.settings.mapData.rasters.selectedRasters()) < 1: #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", "Kein Raster selektiert!") #msg = #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", msg) QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', 'Kein Raster selektiert!', None, QApplication.UnicodeUTF8)) return QgsMessageLog.logMessage('modeLine!=line: {0}'.format(self.settings.modeLine != enumModeLine.line), 'VoGis') QgsMessageLog.logMessage('customLine is None: {0}'.format(self.settings.mapData.customLine is None), 'VoGis') if self.settings.modeLine != enumModeLine.line and self.settings.mapData.customLine is None: QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', 'Keine Profillinie vorhanden!', None, QApplication.UnicodeUTF8)) return if len(self.settings.mapData.polygons.selected_polygons()) > 0 and len(self.settings.mapData.rasters.selectedRasters()) > 1: raster_names = list(raster.name for raster in self.settings.mapData.rasters.selectedRasters()) sel_raster, ok_clicked = QInputDialog.getItem( self.iface.mainWindow(), u'DHM?', u'Welches DHM soll zur Flächenverschneidung verwendet werden?', raster_names, 0, False ) if ok_clicked is False: return self.settings.intersection_dhm_idx = raster_names.index(sel_raster) #self.rubberband.reset(self.polygon) #QDialog.accept(self) QApplication.setOverrideCursor(Qt.WaitCursor) create_profile = CreateProfile(self.iface, self.settings) thread = QThread(self) create_profile.moveToThread(thread) create_profile.finished.connect(self.profiles_finished) create_profile.error.connect(self.profiles_error) create_profile.progress.connect(self.profiles_progress) thread.started.connect(create_profile.create) thread.start(QThread.LowestPriority) self.thread = thread self.create_profile = create_profile self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) except: QApplication.restoreOverrideCursor() ex = u'{0}'.format(traceback.format_exc()) msg = 'Unexpected ERROR:\n\n{0}'.format(ex[:2000]) QMessageBox.critical(self.iface.mainWindow(), "VoGIS-Profiltool", msg) def profiles_finished(self, profiles, intersections): QApplication.restoreOverrideCursor() self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True) #self.create_profile.deleteLater() self.thread.quit() self.thread.wait() #self.thread.deleteLater() #QGIS 2.0 http://gis.stackexchange.com/a/58754 http://gis.stackexchange.com/a/57090 self.iface.mainWindow().statusBar().showMessage('VoGIS-Profiltool, {0} Profile'.format(len(profiles))) QgsMessageLog.logMessage(u'Profile Count: {0}'.format(len(profiles)), 'VoGis') if len(profiles) < 1: QApplication.restoreOverrideCursor() QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', 'Es konnten keine Profile erstellt werden.', None, QApplication.UnicodeUTF8)) return dlg = VoGISProfilToolPlotDialog(self.iface, self.settings, profiles, intersections) dlg.show() #result = self.dlg.exec_() dlg.exec_() def profiles_error(self, exception_string): QApplication.restoreOverrideCursor() QgsMessageLog.logMessage(u'Error during profile creation: {0}'.format(exception_string), 'VoGis') QMessageBox.critical(self.iface.mainWindow(), "VoGIS-Profiltool", exception_string) def profiles_progress(self, msg): self.iface.mainWindow().statusBar().showMessage(msg) self.ui.IDC_lblCreateStatus.setText(msg) #QgsMessageLog.logMessage(msg, 'VoGis') QApplication.processEvents() def reject(self): if not self.thread is None: if self.thread.isRunning(): self.create_profile.abort() return self.rubberband.reset(self.polygon) QDialog.reject(self) def selectVisibleRasters(self): self.refreshRasterList() self.selectingVisibleRasters = True extCanvas = self.iface.mapCanvas().extent() #alle raster in den einstellunge deselektieren for r in self.settings.mapData.rasters.rasters(): r.selected = False #alle raster in der ListView deselektieren for idx in xrange(self.ui.IDC_listRasters.count()): item = self.ui.IDC_listRasters.item(idx) item.setCheckState(Qt.Unchecked) #Raster im Extent selektieren for idx in xrange(self.ui.IDC_listRasters.count()): item = self.ui.IDC_listRasters.item(idx) if QGis.QGIS_VERSION_INT < 10900: raster = item.data(Qt.UserRole).toPyObject() else: raster = item.data(Qt.UserRole) for r in self.settings.mapData.rasters.rasters(): if extCanvas.intersects(r.grid.extent()): if r.id == raster.id: r.selected = True item.setCheckState(Qt.Checked) self.selectingVisibleRasters = False def lineLayerChanged(self, idx): if self.ui.IDC_rbShapeLine.isChecked() is False: self.ui.IDC_rbShapeLine.setChecked(True) if QGis.QGIS_VERSION_INT < 10900: lineLyr = (self.ui.IDC_cbLineLayers.itemData(self.ui.IDC_cbLineLayers.currentIndex()).toPyObject()) else: lineLyr = (self.ui.IDC_cbLineLayers.itemData(self.ui.IDC_cbLineLayers.currentIndex())) lyr = lineLyr.line #QgsMessageLog.logMessage('{0}'.format(lyr.selectedFeatureCount()), 'VoGis') #QgsMessageLog.logMessage('{0}'.format(dir(lyr)), 'VoGis') if hasattr(lyr, 'selectedFeatureCount'): if(lyr.selectedFeatureCount() < 1): self.ui.IDC_chkOnlySelectedFeatures.setChecked(False) else: self.ui.IDC_chkOnlySelectedFeatures.setChecked(True) def valueChangedEquiDistance(self, val): if self.ui.IDC_rbEquiDistance.isChecked() is False: self.ui.IDC_rbEquiDistance.setChecked(True) def valueChangedVertexCount(self, val): if self.ui.IDC_rbVertexCount.isChecked() is False: self.ui.IDC_rbVertexCount.setChecked(True) def lvRasterItemChanged(self, item): if self.selectingVisibleRasters is True: return if item.checkState() == Qt.Checked: selected = True if item.checkState() == Qt.Unchecked: selected = False item_data = item.data(Qt.UserRole) if QGis.QGIS_VERSION_INT < 10900: raster_lyr = item_data.toPyObject() else: raster_lyr = item_data self.settings.mapData.rasters.getById(raster_lyr.id).selected = selected def lvPolygonItemChanged(self, item): if item.checkState() == Qt.Checked: selected = True if item.checkState() == Qt.Unchecked: selected = False item_data = item.data(Qt.UserRole) if QGis.QGIS_VERSION_INT < 10900: poly_lyr = item_data.toPyObject() else: poly_lyr = item_data self.settings.mapData.polygons.getById(poly_lyr.id).selected = selected def refreshRasterList(self): legend = self.iface.legendInterface() avail_lyrs = legend.layers() raster_coll = RasterCollection() for lyr in avail_lyrs: if legend.isLayerVisible(lyr): lyr_type = lyr.type() lyr_name = unicodedata.normalize('NFKD', unicode(lyr.name())).encode('ascii', 'ignore') if lyr_type == 1: if lyr.bandCount() < 2: new_raster = Raster(lyr.id(), lyr_name, lyr) raster_coll.addRaster(new_raster) self.settings.mapData.rasters = raster_coll self.__addRastersToGui() def __addRastersToGui(self): self.ui.IDC_listRasters.clear() check = Qt.Unchecked if self.settings.mapData.rasters.count() == 1: check = Qt.Checked self.settings.mapData.rasters.rasters()[0].selected = True for raster_lyr in self.settings.mapData.rasters.rasters(): item = QListWidgetItem(raster_lyr.name) item.setData(Qt.UserRole, raster_lyr) item.setFlags(item.flags() | Qt.ItemIsUserCheckable) item.setCheckState(check) self.ui.IDC_listRasters.addItem(item) def __addPolygonsToGui(self): self.ui.IDC_listPolygons.clear() check = Qt.Unchecked for poly_lyr in self.settings.mapData.polygons.polygons(): item = QListWidgetItem(poly_lyr.name) item.setData(Qt.UserRole, poly_lyr) item.setFlags(item.flags() | Qt.ItemIsUserCheckable) item.setCheckState(check) self.ui.IDC_listPolygons.addItem(item) def drawLine(self): if self.ui.IDC_rbDigi.isChecked() is False: self.ui.IDC_rbDigi.setChecked(True) self.dblckltemp = None self.rubberband.reset(self.polygon) self.__cleanDigi() self.__activateDigiTool() self.canvas.setMapTool(self.tool) def __createDigiFeature(self, pnts): u = Util(self.iface) f = u.createQgLineFeature(pnts) self.settings.mapData.customLine = f def __lineFinished(self, position): mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"]) newPoint = QgsPoint(mapPos.x(), mapPos.y()) self.pointsToDraw.append(newPoint) #launch analyses self.iface.mainWindow().statusBar().showMessage(str(self.pointsToDraw)) if len(self.pointsToDraw) < 2: self.__cleanDigi() self.pointsToDraw = [] self.dblclktemp = newPoint self.drawnLine = None QMessageBox.warning(self, "VoGIS-Profiltool", QApplication.translate('code', 'Profillinie digitalisieren abgebrochen!', None, QApplication.UnicodeUTF8)) self.drawnLine = self.__createDigiFeature(self.pointsToDraw) self.__cleanDigi() self.pointsToDraw = [] self.dblclktemp = newPoint def __cleanDigi(self): self.pointsToDraw = [] self.canvas.unsetMapTool(self.tool) self.canvas.setMapTool(self.savedTool) def __activateDigiTool(self): QObject.connect(self.tool, SIGNAL("moved"), self.__moved) QObject.connect(self.tool, SIGNAL("rightClicked"), self.__rightClicked) QObject.connect(self.tool, SIGNAL("leftClicked"), self.__leftClicked) QObject.connect(self.tool, SIGNAL("doubleClicked"), self.__doubleClicked) QObject.connect(self.tool, SIGNAL("deactivate"), self.__deactivateDigiTool) def __deactivateDigiTool(self): QObject.disconnect(self.tool, SIGNAL("moved"), self.__moved) QObject.disconnect(self.tool, SIGNAL("leftClicked"), self.__leftClicked) QObject.disconnect(self.tool, SIGNAL("rightClicked"), self.__rightClicked) QObject.disconnect(self.tool, SIGNAL("doubleClicked"), self.__doubleClicked) if QGis.QGIS_VERSION_INT < 10900: self.iface.mainWindow().statusBar().showMessage(QString("")) else: self.iface.mainWindow().statusBar().showMessage('') def __moved(self, position): if len(self.pointsToDraw) > 0: mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"]) self.rubberband.reset(self.polygon) newPnt = QgsPoint(mapPos.x(), mapPos.y()) if QGis.QGIS_VERSION_INT < 10900: for i in range(0, len(self.pointsToDraw)): self.rubberband.addPoint(self.pointsToDraw[i]) self.rubberband.addPoint(newPnt) else: pnts = self.pointsToDraw + [newPnt] self.rubberband.setToGeometry(QgsGeometry.fromPolyline(pnts),None) def __rightClicked(self, position): self.__lineFinished(position) def __leftClicked(self, position): mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"]) newPoint = QgsPoint(mapPos.x(), mapPos.y()) #if self.selectionmethod == 0: if newPoint == self.dblclktemp: self.dblclktemp = None return else: if len(self.pointsToDraw) == 0: self.rubberband.reset(self.polygon) self.pointsToDraw.append(newPoint) def __doubleClicked(self, position): pass #not in use right now def __lineCancel(self): pass def __getSettingsFromGui(self): self.settings.linesExplode = (self.ui.IDC_chkLinesExplode.checkState() == Qt.Checked) self.settings.linesMerge = (self.ui.IDC_chkLinesMerge.checkState() == Qt.Checked) self.settings.onlySelectedFeatures = (self.ui.IDC_chkOnlySelectedFeatures.checkState() == Qt.Checked) self.settings.equiDistance = self.ui.IDC_dblspinDistance.value() self.settings.vertexCnt = self.ui.IDC_dblspinVertexCnt.value() #self.settings.createHekto = (self.ui.IDC_chkCreateHekto.checkState() == Qt.Checked) self.settings.nodesAndVertices = (self.ui.IDC_chkNodesAndVertices.checkState() == Qt.Checked) if QGis.QGIS_VERSION_INT < 10900: self.settings.mapData.selectedLineLyr = (self.ui.IDC_cbLineLayers.itemData( self.ui.IDC_cbLineLayers.currentIndex() ).toPyObject() ) else: self.settings.mapData.selectedLineLyr = (self.ui.IDC_cbLineLayers.itemData(self.ui.IDC_cbLineLayers.currentIndex())) if self.settings.onlySelectedFeatures is True and self.settings.mapData.selectedLineLyr.line.selectedFeatureCount() < 1: QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', u'Der gewählte Layer hat keine selektierten Elemente.', None, QApplication.UnicodeUTF8)) return False if self.ui.IDC_rbDigi.isChecked(): self.settings.modeLine = enumModeLine.customLine elif self.ui.IDC_rbShapeLine.isChecked(): self.settings.modeLine = enumModeLine.line else: #self.ui.IDC_rbStraigthLine self.settings.modeLine = enumModeLine.straightLine if self.ui.IDC_rbEquiDistance.isChecked(): self.settings.modeVertices = enumModeVertices.equiDistant else: self.settings.modeVertices = enumModeVertices.vertexCnt if self.ui.IDC_rbStraigthLine.isChecked(): ut = Util(self.iface) if ut.isFloat(self.ui.IDC_tbFromX.text(), QApplication.translate('code', 'Rechtswert von', None, QApplication.UnicodeUTF8)) is False: return False else: fromX = float(self.ui.IDC_tbFromX.text()) if ut.isFloat(self.ui.IDC_tbFromY.text(), QApplication.translate('code', 'Hochwert von', None, QApplication.UnicodeUTF8)) is False: return False else: fromY = float(self.ui.IDC_tbFromY.text()) if ut.isFloat(self.ui.IDC_tbToX.text(), QApplication.translate('code', 'Rechtswert nach', None, QApplication.UnicodeUTF8)) is False: return False else: toX = float(self.ui.IDC_tbToX.text()) if ut.isFloat(self.ui.IDC_tbToY.text(), QApplication.translate('code', 'Hochwert nach', None, QApplication.UnicodeUTF8)) is False: return False else: toY = float(self.ui.IDC_tbToY.text()) fromPnt = QgsPoint(fromX, fromY) toPnt = QgsPoint(toX, toY) self.settings.mapData.customLine = ut.createQgLineFeature([fromPnt, toPnt]) return True
class AdjustRasterMapTool(QgsMapToolEmitPoint): def __init__(self, iface): self.iface = iface self.canvas = iface.mapCanvas() QgsMapToolEmitPoint.__init__(self, self.canvas) self.rasterShadow = RasterShadowMapCanvasItem(self.canvas) self.rubberBandExtent = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.rubberBandExtent.setColor(Qt.red) self.rubberBandExtent.setWidth(1) self.rubberBandAdjustSide = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.rubberBandAdjustSide.setColor(Qt.red) self.rubberBandAdjustSide.setWidth(3) self.reset() def setLayer(self, layer): self.layer = layer def reset(self): self.startPoint = self.endPoint = None self.isEmittingPoint = False self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rubberBandAdjustSide.reset(QgsWkbTypes.LineGeometry) self.rasterShadow.reset() self.layer = None def canvasPressEvent(self, e): # find the side of the rectangle closest to the click and some data # necessary to compute the new cneter and scale topLeft, topRight, bottomRight, bottomLeft = \ self.layer.cornerCoordinates() top = [topLeft, topRight] right = [bottomRight, topRight] bottom = [bottomRight, bottomLeft] left = [bottomLeft, topLeft] click = QgsGeometry.fromPointXY(self.toMapCoordinates(e.pos())) # order is important (for referenceSide) sides = [top, right, bottom, left] distances = [ click.distance(QgsGeometry.fromPolylineXY(side)) for side in sides ] self.indexSide = self.minDistance(distances) self.side = sides[self.indexSide] self.sidePoint = self.center(self.side) self.vector = self.directionVector(self.side) # side that does not move (opposite of indexSide) self.referenceSide = sides[(self.indexSide + 2) % 4] self.referencePoint = self.center(self.referenceSide) self.referenceDistance = self.distance(self.sidePoint, self.referencePoint) self.isXScale = self.indexSide % 2 == 1 self.startPoint = click.asPoint() self.endPoint = self.startPoint self.isEmittingPoint = True self.isLayerVisible = isLayerVisible(self.iface, self.layer) setLayerVisible(self.iface, self.layer, False) adjustment = self.computeAdjustment() self.showAdjustment(*adjustment) self.layer.history.append({ "action": "adjust", "center": self.layer.center, "xScale": self.layer.xScale, "yScale": self.layer.yScale }) def minDistance(self, distances): sortedDistances = [ i[0] for i in sorted(enumerate(distances), key=itemgetter(1)) ] # first is min return sortedDistances[0] def directionVector(self, side): sideCenter = self.center(side) layerCenter = self.layer.center vector = [ sideCenter.x() - layerCenter.x(), sideCenter.y() - layerCenter.y() ] norm = math.sqrt(vector[0]**2 + vector[1]**2) normedVector = [vector[0] / norm, vector[1] / norm] return normedVector def center(self, side): return QgsPointXY((side[0].x() + side[1].x()) / 2, (side[0].y() + side[1].y()) / 2) def distance(self, pt1, pt2): return math.sqrt((pt1.x() - pt2.x())**2 + (pt1.y() - pt2.y())**2) def canvasReleaseEvent(self, e): self.isEmittingPoint = False self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rubberBandAdjustSide.reset(QgsWkbTypes.LineGeometry) self.rasterShadow.reset() center, xScale, yScale = self.computeAdjustment() self.layer.setCenter(center) self.layer.setScale(xScale * self.layer.xScale, yScale * self.layer.yScale) setLayerVisible(self.iface, self.layer, self.isLayerVisible) self.layer.repaint() self.layer.commitTransformParameters() def canvasMoveEvent(self, e): if not self.isEmittingPoint: return self.endPoint = self.toMapCoordinates(e.pos()) adjustment = self.computeAdjustment() self.showAdjustment(*adjustment) def computeAdjustment(self): dX = self.endPoint.x() - self.startPoint.x() dY = self.endPoint.y() - self.startPoint.y() # project on vector dp = dX * self.vector[0] + dY * self.vector[1] # do not go beyond 5% of the current size of side if dp < -0.95 * self.referenceDistance: dp = -0.95 * self.referenceDistance updatedSidePoint = QgsPointXY(self.sidePoint.x() + dp * self.vector[0], self.sidePoint.y() + dp * self.vector[1]) center = self.center([self.referencePoint, updatedSidePoint]) scaleFactor = self.distance(self.referencePoint, updatedSidePoint) if self.isXScale: xScale = scaleFactor / self.referenceDistance yScale = 1.0 else: xScale = 1.0 yScale = scaleFactor / self.referenceDistance return (center, xScale, yScale) def showAdjustment(self, center, xScale, yScale): _, rotation, originalXScale, originalYScale = \ self.layer.transformParameters() newXScale = xScale * originalXScale newYScale = yScale * originalYScale cornerPoints = self.layer.transformedCornerCoordinates( center, rotation, newXScale, newYScale) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) for point in cornerPoints: self.rubberBandExtent.addPoint(point, False) # for closing self.rubberBandExtent.addPoint(cornerPoints[0], True) self.rubberBandExtent.show() # show rubberband for side # see def of indexSide in init: # cornerpoints are (topLeft, topRight, bottomRight, bottomLeft) self.rubberBandAdjustSide.reset(QgsWkbTypes.LineGeometry) self.rubberBandAdjustSide.addPoint(cornerPoints[self.indexSide % 4], False) self.rubberBandAdjustSide.addPoint( cornerPoints[(self.indexSide + 1) % 4], True) self.rubberBandAdjustSide.show() self.rasterShadow.reset(self.layer) dx = center.x() - self.layer.center.x() dy = center.y() - self.layer.center.y() self.rasterShadow.setDeltaDisplacement(dx, dy, False) self.rasterShadow.setDeltaScale(xScale, yScale, True) self.rasterShadow.show()
class MoveRasterMapTool(QgsMapToolEmitPoint): def __init__(self, iface): self.iface = iface self.canvas = iface.mapCanvas() QgsMapToolEmitPoint.__init__(self, self.canvas) self.rasterShadow = RasterShadowMapCanvasItem(self.canvas) self.rubberBandDisplacement = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.rubberBandDisplacement.setColor(Qt.red) self.rubberBandDisplacement.setWidth(1) self.rubberBandExtent = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.rubberBandExtent.setColor(Qt.red) self.rubberBandExtent.setWidth(1) self.isLayerVisible = True self.reset() def setLayer(self, layer): self.layer = layer def reset(self): self.startPoint = self.endPoint = None self.isEmittingPoint = False self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rasterShadow.reset() self.layer = None def canvasPressEvent(self, e): self.startPoint = self.toMapCoordinates(e.pos()) self.endPoint = self.startPoint self.isEmittingPoint = True self.originalCenter = self.layer.center # this tool do the displacement itself TODO update so it is done by # transformed coordinates + new center) self.originalCornerPoints = self.layer.transformedCornerCoordinates( *self.layer.transformParameters()) self.isLayerVisible = isLayerVisible(self.iface, self.layer) setLayerVisible(self.iface, self.layer, False) self.showDisplacement(self.startPoint, self.endPoint) self.layer.history.append({ "action": "move", "center": self.layer.center }) def canvasReleaseEvent(self, e): self.isEmittingPoint = False self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rasterShadow.reset() x = self.originalCenter.x() + self.endPoint.x() - self.startPoint.x() y = self.originalCenter.y() + self.endPoint.y() - self.startPoint.y() self.layer.setCenter(QgsPointXY(x, y)) setLayerVisible(self.iface, self.layer, self.isLayerVisible) self.layer.repaint() self.layer.commitTransformParameters() def canvasMoveEvent(self, e): if not self.isEmittingPoint: return self.endPoint = self.toMapCoordinates(e.pos()) self.showDisplacement(self.startPoint, self.endPoint) def showDisplacement(self, startPoint, endPoint): self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) point1 = QgsPointXY(startPoint.x(), startPoint.y()) point2 = QgsPointXY(endPoint.x(), endPoint.y()) self.rubberBandDisplacement.addPoint(point1, False) self.rubberBandDisplacement.addPoint(point2, True) # true to update canvas self.rubberBandDisplacement.show() self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) for point in self.originalCornerPoints: self._addDisplacementToPoint(self.rubberBandExtent, point, False) # for closing self._addDisplacementToPoint(self.rubberBandExtent, self.originalCornerPoints[0], True) self.rubberBandExtent.show() self.rasterShadow.reset(self.layer) self.rasterShadow.setDeltaDisplacement( self.endPoint.x() - self.startPoint.x(), self.endPoint.y() - self.startPoint.y(), True) self.rasterShadow.show() def _addDisplacementToPoint(self, rubberBand, point, doUpdate): x = point.x() + self.endPoint.x() - self.startPoint.x() y = point.y() + self.endPoint.y() - self.startPoint.y() self.rubberBandExtent.addPoint(QgsPointXY(x, y), doUpdate)
class ScaleRasterMapTool(QgsMapToolEmitPoint): def __init__(self, iface): self.iface = iface self.canvas = iface.mapCanvas() QgsMapToolEmitPoint.__init__(self, self.canvas) self.rasterShadow = RasterShadowMapCanvasItem(self.canvas) self.rubberBandExtent = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.rubberBandExtent.setColor(Qt.red) self.rubberBandExtent.setWidth(1) self.reset() def setLayer(self, layer): self.layer = layer def reset(self): self.startPoint = self.endPoint = None self.isEmittingPoint = False self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rasterShadow.reset() self.layer = None def canvasPressEvent(self, e): pressed_button = e.button() if pressed_button == 1: self.startPoint = e.pos() self.endPoint = self.startPoint self.isEmittingPoint = True self.height = float(self.canvas.height()) self.width = float(self.canvas.width()) modifiers = QApplication.keyboardModifiers() self.isKeepRelativeScale = bool(modifiers & Qt.ControlModifier) self.isLayerVisible = isLayerVisible(self.iface, self.layer) setLayerVisible(self.iface, self.layer, False) scaling = self.computeScaling() self.showScaling(*scaling) self.layer.history.append({ "action": "scale", "xScale": self.layer.xScale, "yScale": self.layer.yScale }) def canvasReleaseEvent(self, e): pressed_button = e.button() if pressed_button == 1: self.isEmittingPoint = False self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rasterShadow.reset() xScale, yScale = self.computeScaling() self.layer.setScale(xScale * self.layer.xScale, yScale * self.layer.yScale) setLayerVisible(self.iface, self.layer, self.isLayerVisible) elif pressed_button == 2: number, ok = QInputDialog.getText( None, "Scale & DPI", "Enter scale,dpi (e.g. 3000,96)") if not ok: self.layer.history.pop() return scales = number.split(',') if len(scales) != 2: self.layer.history.pop() QMessageBox.information(self.iface.mainWindow(), "Error", "Must be 2 numbers") return scale = tryfloat(scales[0]) dpi = tryfloat(scales[1]) if scale and dpi: xScale = scale / (dpi / 0.0254) yScale = xScale else: self.layer.history.pop() QMessageBox.information( self.iface.mainWindow(), "Error", "Bad format: Must be scale,dpi (e.g. 3000,96)") return self.layer.setScale(xScale, yScale) self.layer.repaint() self.layer.commitTransformParameters() def canvasMoveEvent(self, e): if not self.isEmittingPoint: return self.endPoint = e.pos() scaling = self.computeScaling() self.showScaling(*scaling) def computeScaling(self): dX = -(self.endPoint.x() - self.startPoint.x()) dY = self.endPoint.y() - self.startPoint.y() xScale = 1.0 - (dX / (self.width * 1.1)) yScale = 1.0 - (dY / (self.height * 1.1)) if self.isKeepRelativeScale: # keep same scale in both dimensions return (xScale, xScale) else: return (xScale, yScale) def showScaling(self, xScale, yScale): if xScale == 0 and yScale == 0: return center, rotation, originalXScale, originalYScale = \ self.layer.transformParameters() newXScale = xScale * originalXScale newYScale = yScale * originalYScale cornerPoints = self.layer.transformedCornerCoordinates( center, rotation, newXScale, newYScale) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) for point in cornerPoints: self.rubberBandExtent.addPoint(point, False) # for closing self.rubberBandExtent.addPoint(cornerPoints[0], True) self.rubberBandExtent.show() self.rasterShadow.reset(self.layer) self.rasterShadow.setDeltaScale(xScale, yScale, True) self.rasterShadow.show()
class MultipleSelection(QgsMapTool): def __init__(self, iface, controller, layers, mincut=None, parent_manage=None, manage_new_psector=None, table_object=None, dialog=None): """ Class constructor """ self.layers = layers self.iface = iface self.canvas = self.iface.mapCanvas() self.mincut = mincut self.parent_manage = parent_manage self.manage_new_psector = manage_new_psector self.table_object = table_object self.dialog = dialog # Call superclass constructor and set current action QgsMapTool.__init__(self, self.canvas) self.controller = controller self.rubber_band = QgsRubberBand(self.canvas, 2) self.rubber_band.setColor(QColor(255, 100, 255)) self.rubber_band.setFillColor(QColor(254, 178, 76, 63)) self.rubber_band.setWidth(1) self.reset() self.selected_features = [] # Snapper self.snapper_manager = SnappingConfigManager(self.iface) self.snapper = self.snapper_manager.get_snapper() def reset(self): self.start_point = self.end_point = None self.is_emitting_point = False self.reset_rubber_band() def canvasPressEvent(self, event): if event.button() == Qt.LeftButton: self.start_point = self.toMapCoordinates(event.pos()) self.end_point = self.start_point self.is_emitting_point = True self.show_rect(self.start_point, self.end_point) def canvasReleaseEvent(self, event): self.is_emitting_point = False rectangle = self.get_rectangle() selected_rectangle = None key = QApplication.keyboardModifiers() if event.button() != Qt.LeftButton: self.rubber_band.hide() return # Disconnect signal to enhance process # We will reconnect it when processing last layer of the group if self.mincut: self.mincut.disconnect_signal_selection_changed() if self.parent_manage: self.parent_manage.disconnect_signal_selection_changed() if self.manage_new_psector: self.manage_new_psector.disconnect_signal_selection_changed() for i in range(len(self.layers)): layer = self.layers[i] if i == len(self.layers) - 1: if self.mincut: self.mincut.connect_signal_selection_changed( "mincut_connec") if self.parent_manage: self.parent_manage.connect_signal_selection_changed( self.dialog, self.table_object) if self.manage_new_psector: self.manage_new_psector.connect_signal_selection_changed( self.manage_new_psector.dlg_plan_psector, self.table_object) # Selection by rectangle if rectangle: if selected_rectangle is None: selected_rectangle = self.canvas.mapSettings( ).mapToLayerCoordinates(layer, rectangle) # If Ctrl+Shift clicked: remove features from selection if key == (Qt.ControlModifier | Qt.ShiftModifier): layer.selectByRect(selected_rectangle, layer.RemoveFromSelection) # If Ctrl clicked: add features to selection elif key == Qt.ControlModifier: layer.selectByRect(selected_rectangle, layer.AddToSelection) # If Ctrl not clicked: add features to selection else: layer.selectByRect(selected_rectangle, layer.AddToSelection) # Selection one by one else: event_point = self.snapper_manager.get_event_point(event) result = self.snapper_manager.snap_to_background_layers( event_point) if self.snapper_manager.result_is_valid(): # Get the point. Leave selection self.snapper_manager.get_snapped_feature(result, True) self.rubber_band.hide() def canvasMoveEvent(self, event): if not self.is_emitting_point: return self.end_point = self.toMapCoordinates(event.pos()) self.show_rect(self.start_point, self.end_point) def show_rect(self, start_point, end_point): self.reset_rubber_band() 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()) self.rubber_band.addPoint(point1, False) self.rubber_band.addPoint(point2, False) self.rubber_band.addPoint(point3, False) self.rubber_band.addPoint(point4, True) self.rubber_band.show() def get_rectangle(self): if self.start_point is None or self.end_point is None: return None elif self.start_point.x() == self.end_point.x() or self.start_point.y( ) == self.end_point.y(): return None return QgsRectangle(self.start_point, self.end_point) def deactivate(self): self.rubber_band.hide() QgsMapTool.deactivate(self) def activate(self): pass def reset_rubber_band(self): try: self.rubber_band.reset(2) except: pass
class ParentMapTool(QgsMapTool): def __init__(self, iface, settings, action, index_action): """ Class constructor """ self.iface = iface self.canvas = self.iface.mapCanvas() self.settings = settings self.show_help = bool(int(self.settings.value('status/show_help', 1))) self.index_action = index_action self.layer_arc = None self.layer_connec = None self.layer_node = None self.layer_arc_man = None self.layer_connec_man = None self.layer_node_man = None self.layer_gully_man = None self.schema_name = None self.controller = None self.dao = None # Call superclass constructor and set current action QgsMapTool.__init__(self, self.canvas) self.setAction(action) # Snapper self.snapper_manager = SnappingConfigManager(self.iface) self.snapper = QgsMapCanvasSnapper(self.canvas) # Change map tool cursor self.cursor = QCursor() self.cursor.setShape(Qt.CrossCursor) # Get default cursor self.std_cursor = self.parent().cursor() # Set default vertex marker color = QColor(255, 100, 255) self.vertex_marker = QgsVertexMarker(self.canvas) self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE) self.vertex_marker.setColor(color) self.vertex_marker.setIconSize(15) self.vertex_marker.setPenWidth(3) # Set default rubber band color_selection = QColor(254, 178, 76, 63) self.rubber_band = QgsRubberBand(self.canvas, QGis.Polygon) self.rubber_band.setColor(color) self.rubber_band.setFillColor(color_selection) self.rubber_band.setWidth(1) self.reset() self.force_active_layer = True # Set default encoding reload(sys) sys.setdefaultencoding('utf-8') #@UndefinedVariable def get_cursor_multiple_selection(self): """ Set cursor for multiple selection """ path_folder = os.path.join(os.path.dirname(__file__), os.pardir) path_cursor = os.path.join(path_folder, 'icons', '201.png') if os.path.exists(path_cursor): cursor = QCursor(QPixmap(path_cursor)) else: cursor = QCursor(Qt.ArrowCursor) return cursor def set_layers(self, layer_arc_man, layer_connec_man, layer_node_man, layer_gully_man=None): """ Sets layers involved in Map Tools functions Sets Snapper Manager """ self.layer_arc_man = layer_arc_man self.layer_connec_man = layer_connec_man self.layer_node_man = layer_node_man self.layer_gully_man = layer_gully_man self.snapper_manager.set_layers(layer_arc_man, layer_connec_man, layer_node_man, layer_gully_man) def set_controller(self, controller): self.controller = controller self.schema_name = controller.schema_name self.plugin_dir = self.controller.plugin_dir self.snapper_manager.controller = controller def deactivate(self): # Uncheck button self.action().setChecked(False) # Restore previous snapping self.snapper_manager.recover_snapping_options() # Recover cursor self.canvas.setCursor(self.std_cursor) # Remove highlight self.vertex_marker.hide() def set_icon(self, widget, icon): """ Set @icon to selected @widget """ # Get icons folder icons_folder = os.path.join(self.plugin_dir, 'icons') icon_path = os.path.join(icons_folder, str(icon) + ".png") if os.path.exists(icon_path): widget.setIcon(QIcon(icon_path)) else: self.controller.log_info("File not found", parameter=icon_path) def set_action_pan(self): """ Set action 'Pan' """ try: self.iface.actionPan().trigger() except Exception: pass def reset(self): # Graphic elements self.rubber_band.reset(QGis.Polygon) # Selection self.snapped_feat = None def cancel_map_tool(self): """ Executed if user press right button or escape key """ # Reset rubber band self.reset() # Deactivate map tool self.deactivate() self.set_action_pan() def remove_markers(self): """ Remove previous markers """ vertex_items = [i for i in self.canvas.scene().items() if issubclass(type(i), QgsVertexMarker)] for ver in vertex_items: if ver in self.canvas.scene().items(): self.canvas.scene().removeItem(ver) def refresh_map_canvas(self): """ Refresh all layers present in map canvas """ self.canvas.refreshAllLayers() for layer_refresh in self.canvas.layers(): layer_refresh.triggerRepaint() def open_dialog(self, dlg=None, dlg_name=None, maximize_button=True, stay_on_top=True): """ Open dialog """ if dlg is None or type(dlg) is bool: dlg = self.dlg # Manage i18n of the dialog if dlg_name: self.controller.manage_translation(dlg_name, dlg) # Manage stay on top and maximize button if maximize_button and stay_on_top: dlg.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowStaysOnTopHint) elif not maximize_button and stay_on_top: dlg.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowStaysOnTopHint) elif maximize_button and not stay_on_top: dlg.setWindowFlags(Qt.WindowMaximizeButtonHint) # Open dialog dlg.open() def close_dialog(self, dlg=None, set_action_pan=True): """ Close dialog """ if dlg is None or type(dlg) is bool: dlg = self.dlg try: self.save_settings(dlg) dlg.close() if set_action_pan: map_tool = self.canvas.mapTool() # If selected map tool is from the plugin, set 'Pan' as current one if map_tool.toolName() == '': self.set_action_pan() except AttributeError: pass def load_settings(self, dialog=None): """ Load QGIS settings related with dialog position and size """ if dialog is None: dialog = self.dlg try: x = self.controller.plugin_settings_value(dialog.objectName() + "_x") y = self.controller.plugin_settings_value(dialog.objectName() + "_y") width = self.controller.plugin_settings_value(dialog.objectName() + "_width", dialog.property('width')) height = self.controller.plugin_settings_value(dialog.objectName() + "_height", dialog.property('height')) if int(x) < 0 or int(y) < 0: dialog.resize(int(width), int(height)) else: screens = ctypes.windll.user32 screen_x = screens.GetSystemMetrics(78) screen_y = screens.GetSystemMetrics(79) if int(x) > screen_x: x = int(screen_x) - int(width) if int(y) > screen_y: y = int(screen_y) dialog.setGeometry(int(x), int(y), int(width), int(height)) except: pass def save_settings(self, dialog=None): """ Save QGIS settings related with dialog position and size """ if dialog is None: dialog = self.dlg try: self.controller.plugin_settings_set_value(dialog.objectName() + "_width", dialog.property('width')) self.controller.plugin_settings_set_value(dialog.objectName() + "_height", dialog.property('height')) self.controller.plugin_settings_set_value(dialog.objectName() + "_x", dialog.pos().x()) self.controller.plugin_settings_set_value(dialog.objectName() + "_y", dialog.pos().y()) except: pass def check_expression(self, expr_filter, log_info=False): """ Check if expression filter @expr is valid """ if log_info: self.controller.log_info(expr_filter) expr = QgsExpression(expr_filter) if expr.hasParserError(): message = "Expression Error" self.controller.log_warning(message, parameter=expr_filter) return (False, expr) return (True, expr) def canvasMoveEvent(self, event): # Make sure active layer is always 'v_edit_node' cur_layer = self.iface.activeLayer() if cur_layer != self.layer_node and self.force_active_layer: self.iface.setActiveLayer(self.layer_node) # Hide highlight self.vertex_marker.hide() try: # Get current mouse coordinates x = event.pos().x() y = event.pos().y() event_point = QPoint(x, y) except(TypeError, KeyError): self.iface.actionPan().trigger() return # Snapping (retval, result) = self.snapper.snapToCurrentLayer(event_point, 2) # @UnusedVariable # That's the snapped features if result: # Get the point and add marker on it point = QgsPoint(result[0].snappedVertex) self.vertex_marker.setCenter(point) self.vertex_marker.show()
class OrientationMapTool(QgsMapTool): def __init__(self, iface): self.iface = iface self.settings = MySettings() self.canvas = iface.mapCanvas() self.rubber = QgsRubberBand(self.canvas) QgsMapTool.__init__(self, self.canvas) def activate(self): QgsMapTool.activate(self) self.rubber.setWidth(self.settings.value("rubberWidth")) self.rubber.setColor(self.settings.value("rubberColor")) def deactivate(self): self.rubber.reset() QgsMapTool.deactivate(self) def canvasMoveEvent(self, mouseEvent): ori = self.get_orientation(mouseEvent.pos()) if ori is None: self.rubber.reset() else: self.rubber.setToGeometry(ori.geometry(), None) def canvasPressEvent(self, mouseEvent): if mouseEvent.button() != Qt.LeftButton: self.rubber.reset() return ori = self.get_orientation(mouseEvent.pos()) if ori is None: self.rubber.reset() return dlg = OrientationDialog(ori, self.rubber) if dlg.exec_(): if ori.length != 0: ori.save() self.rubber.reset() def get_orientation(self, pos): match = self.snap_to_segment(pos) if not match.hasEdge(): return None vertices = match.edgePoints() po = match.point() dist = (po.sqrDist(vertices[0]), po.sqrDist(vertices[1])) mindist = min(dist) if mindist == 0: return None i = dist.index(mindist) ve = vertices[i] az = po.azimuth(ve) return Orientation(self.iface, ve, az) def snap_to_segment(self, pos): """ Temporarily override snapping config and snap to vertices and edges of any editable vector layer, to allow selection of node for editing (if snapped to edge, it would offer creation of a new vertex there). """ map_point = self.toMapCoordinates(pos) tol = QgsTolerance.vertexSearchRadius(self.canvas.mapSettings()) snap_type = QgsPointLocator.Type(QgsPointLocator.Edge) snap_layers = [] for layer in self.canvas.layers(): if not isinstance(layer, QgsVectorLayer): continue snap_layers.append( QgsSnappingUtils.LayerConfig(layer, snap_type, tol, QgsTolerance.ProjectUnits)) snap_util = self.canvas.snappingUtils() old_layers = snap_util.layers() old_mode = snap_util.snapToMapMode() old_inter = snap_util.snapOnIntersections() snap_util.setLayers(snap_layers) snap_util.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced) snap_util.setSnapOnIntersections(False) m = snap_util.snapToMap(map_point) snap_util.setLayers(old_layers) snap_util.setSnapToMapMode(old_mode) snap_util.setSnapOnIntersections(old_inter) return m
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) self.rb.setStrokeColor(QColor(255, 0, 0, 40)) self.rb.setFillColor(mycolor) self.rb.setLineStyle(Qt.PenStyle(Qt.SolidLine)) self.rb.setWidth(2) self.center = None self.segments = 120 #circle of 30 segments def setCursorStyle(self): cursor = QCursor() cursor.setShape(self.cursorStyle) self.setCursor(cursor) def activate(self): self.caller.setChecked(True) self.setCursorStyle() self.geometry_changed.emit(QgsGeometry(), False) 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 canvasPressEvent(self, e): if e.button() == Qt.LeftButton: self.active = True self.center = self.toMapCoordinates(e.pos()) self.geometry_changed.emit(QgsGeometry(), False) self.rb.reset() pass def canvasMoveEvent(self, QgsMapMouseEvent): if self.active: cp = self.toMapCoordinates(QgsMapMouseEvent.pos()) self.rbcircle(self.rb, self.center, cp, self.segments) self.geometry_changed.emit(self.rb.asGeometry(), True) pass def canvasReleaseEvent(self, mouseevent): if mouseevent.button() == Qt.LeftButton: self.active = False self.geometry_changed.emit(self.rb.asGeometry(), True) pass def rbcircle(self, rb, center, edgePoint, N): r = math.sqrt(center.sqrDist(edgePoint)) rb.reset(QgsWkbTypes.PolygonGeometry) for itheta in range(N + 1): theta = itheta * (2.0 * math.pi / N) rb.addPoint( QgsPointXY(center.x() + r * math.cos(theta), center.y() + r * math.sin(theta))) return
class LineMapTool(MapTool, QgsMapToolEmitPoint): ''' draw a line on the map (connected, multiple sections) Attributes ---------- drawn : pyqtSignal emitted after double click or right click on the map canvas, emits the drawn line ''' drawn = pyqtSignal(QgsGeometry) wkbtype = QgsWkbTypes.LineGeometry def __init__(self, ui_element: QWidget, canvas: QgsMapCanvas = None, color: Union[str, int] = None, draw_markers=False, line_width: int = 2, line_style: int = Qt.SolidLine, snap_geometry: QgsGeometry = None, target_epsg: int = 25832): ''' Parameters ---------- ui_element : QWidget clickable UI element, clicking it will activate/deactivate this tool canvas : QgsMapCanvas, optional the map canvas the tool will work on, defaults to the map canvas of the QGIS UI color : int or str, optional color description, sets color of line and markers while drawing, defaults to blue draw_markers : bool, optional draw markers between segments of the line, defaults to no markers line_width : int, optional width of drawn lines in pixels, defaults to 2 pixels line_style : int, optional style of drawn lines (e.g. Qt.DashDotLine), defaults to solid line snap_geometry : QgsGeometry, optional snap drawn lines to outline of given geometry, defaults to no snapping target_epsg : int, optional projection of emitted geometry after drawing as epsg code, defaults to 25832 ''' self.canvas = canvas MapTool.__init__(self, ui_element, self.canvas) QgsMapToolEmitPoint.__init__(self, canvas=self.canvas) self.rubberband = QgsRubberBand(self.canvas, self.wkbtype) self.color = QColor(color) if color else QColor(0, 0, 255) self.rubberband.setColor(self.color) self.color.setAlpha(100) self.rubberband.setFillColor(self.color) self.rubberband.setLineStyle(line_style) self.rubberband.setWidth(line_width) self.snap_geometry = self.set_snap_geometry(snap_geometry) self.draw_markers = draw_markers if self.draw_markers: # auto points on outline should but doesn't work: #self.drawing_lines.setIcon(QgsRubberBand.ICON_CIRCLE) #self.drawing_lines.setIconSize(8) # drawing markers manually instead self.markers = [] self._drawing = False self._moving = False # marker for showing snapped point on move self._move_marker = QgsVertexMarker(self.canvas) self._move_marker.setColor(self.color) self._move_marker.setIconType(QgsVertexMarker.ICON_CIRCLE) self._move_marker.setIconSize(10) self._move_marker.setPenWidth(3) self.reset() def set_snap_geometry(self, geom: QgsGeometry): ''' snap lines to outline of given geometry Parameters ---------- snap_geometry : QgsGeometry geometry to snap lines to ''' if not geom: return if SHAPELY_LOADED: self.snap_geometry = wkt.loads(geom.asWkt()).boundary # alternative for MacOS else: self.snap_geometry = QgsCurvePolygon() self.snap_geometry.fromWkt(geom.asWkt()) def reset(self): ''' reset drawing ''' scene = self.canvas.scene() if self.draw_markers: for m in self.markers: scene.removeItem(m) self.markers = [] self._moving = False self._drawing = False self.rubberband.reset(self.wkbtype) def canvasDoubleClickEvent(self, e): ''' override, emit line on double click ''' if self._moving: self.rubberband.removeLastPoint() geom = self.rubberband.asGeometry() self.drawn.emit(self.transform_from_map(geom)) self.reset() def _snap(self, point: QgsPoint) -> QgsPointXY: ''' snap point to snap-geometry ''' point = self.transform_from_map(point) if SHAPELY_LOADED: p = geometry.Point(point.x(), point.y()) np = nearest_points(self.snap_geometry, p)[0] p = QgsPointXY(np.x, np.y) # alternative for MacOS else: closest = QgsGeometryUtils.closestPoint( self.snap_geometry, QgsPoint(point.x(), point.y())) p = QgsPointXY(closest.x(), closest.y()) p = self.transform_to_map(p) return p def canvasPressEvent(self, e): ''' override, finish line segment when map is clicked ''' if (e.button() == Qt.RightButton): if self._moving: self.rubberband.removeLastPoint() geom = self.rubberband.asGeometry() self.drawn.emit(self.transform_from_map(geom)) self.reset() return self._moving = False self._drawing = True point = self.toMapCoordinates(e.pos()) if self.snap_geometry: point = self._snap(point) self.rubberband.addPoint(point, True) if self.draw_markers: marker = QgsVertexMarker(self.canvas) marker.setCenter(point) marker.setColor(self.color) marker.setIconSize(8) marker.setIconType(QgsVertexMarker.ICON_CIRCLE) marker.setPenWidth(4) self.markers.append(marker) def canvasMoveEvent(self, e): ''' override, draw connecting line to last segment when moving mouse ''' if not self.snap_geometry and not self._drawing: return point = self.toMapCoordinates(e.pos()) if self.snap_geometry: point = self._snap(point) if self.snap_geometry: self._move_marker.setCenter(point) if self._drawing: #self.rubberBand.removeLastPoint() if self._moving: self.rubberband.removeLastPoint() self.rubberband.addPoint(point, True) self._moving = True def disconnect(self, **kwargs): ''' override, 'remove' marker ''' if self._move_marker: #scene = self.canvas.scene() #scene.removeItem(self._move_marker) # workaround: if removed from scene marker won't appear any more # set it somewhere it can't be seen self._move_marker.setCenter(QgsPointXY(0, 0)) super().disconnect(**kwargs)
class InfoTool(TouchMapTool): infoResults = pyqtSignal(dict) def __init__(self, canvas, snapradius = 2): super(InfoTool, self).__init__(canvas) self.radius = snapradius self.band = QgsRubberBand(self.canvas) self.band.setColor(QColor.fromRgb(224,162,16)) self.band.setWidth(3) self.selectband = None self.selectrect = QRect() self.dragging = False self.selectionlayers = [] def getFeatures(self, rect, firstonly=False): self.band.reset() for layer in self.selectionlayers.itervalues(): if (not layer.type() == QgsMapLayer.VectorLayer or layer.geometryType() == QGis.NoGeometry): continue rect = self.toLayerCoordinates(layer, rect) rq = QgsFeatureRequest().setFilterRect(rect)\ .setFlags(QgsFeatureRequest.ExactIntersect)\ .setSubsetOfAttributes([]) features = [] if firstonly: try: feature = layer.getFeatures(rq).next() if feature.isValid(): features.append(feature) except StopIteration: continue else: for feature in layer.getFeatures(rq): if feature.isValid(): features.append(feature) yield layer, features def toSearchRect(self, point): point = self.toMapCoordinates(point) rect = QgsRectangle(point.x(), point.y(), point.x() + 10, point.y() + 10) return rect def canvasPressEvent(self, event): if self.pinching: return self.dragging = False self.selectrect.setRect(0, 0, 0, 0) self.selectband = QgsRubberBand(self.canvas, QGis.Polygon ) self.selectband.setColor(QColor.fromRgb(0,0,255, 65)) self.selectband.setWidth(5) def canvasMoveEvent(self, event): if self.pinching: return if not event.buttons() == Qt.LeftButton: return if not self.dragging: self.selectrect.setTopLeft(event.pos()) self.dragging = True self.selectrect.setBottomRight(event.pos()) maptoolutils.setRubberBand(self.canvas, self.selectrect, self.selectband) def canvasReleaseEvent(self, event): if self.pinching: return if self.dragging: geometry = self.selectband.asGeometry() if not geometry: return rect = geometry.boundingBox() firstonly = False else: firstonly = True rect = self.toSearchRect(event.pos()) self.dragging = False self.selectband.reset() results = OrderedDict((l,f) for l, f in self.getFeatures(rect)) self.infoResults.emit(results)
class QgepMapToolAddFeature(QgsMapToolAdvancedDigitizing): """ Base class for adding features """ def __init__(self, iface: QgisInterface, layer): QgsMapToolAdvancedDigitizing.__init__(self, iface.mapCanvas(), iface.cadDockWidget()) self.iface = iface self.canvas = iface.mapCanvas() self.layer = layer self.rubberband = QgepRubberBand3D(iface.mapCanvas(), layer.geometryType()) self.rubberband.setColor(QColor("#ee5555")) self.rubberband.setWidth(1) self.temp_rubberband = QgsRubberBand(iface.mapCanvas(), layer.geometryType()) self.temp_rubberband.setColor(QColor("#ee5555")) self.temp_rubberband.setWidth(1) self.temp_rubberband.setLineStyle(Qt.DotLine) def activate(self): """ When activating the map tool """ QgsMapToolAdvancedDigitizing.activate(self) self.canvas.setCursor(QCursor(Qt.CrossCursor)) def deactivate(self): """ On deactivating the map tool """ QgsMapToolAdvancedDigitizing.deactivate(self) self.canvas.unsetCursor() # pylint: disable=no-self-use def isZoomTool(self): """ This is no zoom tool """ return False # =========================================================================== # Events # =========================================================================== def cadCanvasReleaseEvent(self, event): """ Called when a mouse button is :param event: :return: """ if event.button() == Qt.RightButton: self.right_clicked(event) else: self.left_clicked(event) def left_clicked(self, event): """ When the canvas is left clicked we add a new point to the rubberband. :type event: QMouseEvent """ mousepos = self.canvas.getCoordinateTransform()\ .toMapCoordinates(event.pos().x(), event.pos().y()) self.rubberband.addPoint(mousepos) self.temp_rubberband.reset() def right_clicked(self, _): """ On a right click we create a new feature from the existing rubberband and show the add dialog """ f = QgsFeature(self.layer.fields()) f.setGeometry(self.rubberband.asGeometry()) dlg = self.iface.getFeatureForm(self.layer, f) dlg.setMode(QgsAttributeForm.AddFeatureMode) dlg.exec_() self.rubberband.reset3D() self.temp_rubberband.reset() def cadCanvasMoveEvent(self, event): """ When the mouse is moved the rubberband needs to be updated :param event: The coordinates etc. """ # When a generated event arrives it's a QMoveEvent... No idea why, but this prevents from an exception try: QgsMapToolAdvancedDigitizing.cadCanvasMoveEvent(self, event) mousepos = event.mapPoint() self.temp_rubberband.movePoint(mousepos) self.mouse_move(event) except TypeError: pass def mouse_move(self, event): pass
class EditTool(MapTool): """ Inspection tool which copies the feature to a new layer and copies selected data from the underlying feature. """ finished = pyqtSignal(object, QgsFeature) featuresfound = pyqtSignal(dict) def __init__(self, canvas, forms, snapradius = 2): MapTool.__init__(self, canvas, []) self.canvas = canvas self.radius = snapradius self.forms = forms self.band = QgsRubberBand(self.canvas) self.band.setColor(QColor.fromRgb(224,162,16)) self.band.setWidth(3) self.selectband = None self.selectrect = QRect() self.dragging = False self.cursor = QCursor(QPixmap(["16 16 3 1", " c None", ". c #FF0000", "+ c #FFFFFF", " ", " +.+ ", " ++.++ ", " +.....+ ", " +. .+ ", " +. . .+ ", " +. . .+ ", " ++. . .++", " ... ...+... ...", " ++. . .++", " +. . .+ ", " +. . .+ ", " ++. .+ ", " ++.....+ ", " ++.++ ", " +.+ "])) def addForm(self, form): self.forms.append(form) self.layersupdated.emit(True) def layers(self): """ Return a set of layers that this edit tool can work on """ return set([form.QGISLayer for form in self.forms]) def formsforlayer(self, layer): for form in self.forms: if form.QGISLayer == layer: yield form def reset(self): self.forms = [] self.layersupdated.emit(False) def getFeatures(self, rect): rq = QgsFeatureRequest().setFilterRect(rect) self.band.reset() for layer in self.layers(): forms = list(self.formsforlayer(layer)) rq = QgsFeatureRequest().setFilterRect(rect) for feature in layer.getFeatures(rq): if feature.isValid(): yield feature, forms def toSearchRect(self, point): searchRadius = self.canvas.extent().width() * ( self.radius / 100.0 ) point = self.toMapCoordinates(point) rect = QgsRectangle() rect.setXMinimum(point.x() - searchRadius) rect.setXMaximum(point.x() + searchRadius) rect.setYMinimum(point.y() - searchRadius) rect.setYMaximum(point.y() + searchRadius) return rect def canvasPressEvent(self, event): self.selectrect.setRect( 0, 0, 0, 0 ) self.selectband = QgsRubberBand(self.canvas, QGis.Polygon ) self.selectband.setColor(QColor.fromRgb(0,0,255, 65)) self.selectband.setWidth(5) def canvasMoveEvent(self, event): if not event.buttons() == Qt.LeftButton: return if not self.dragging: self.dragging = True self.selectrect.setTopLeft(event.pos()) self.selectrect.setBottomRight(event.pos()) maptoolutils.setRubberBand(self.canvas, self.selectrect, self.selectband) def canvasReleaseEvent(self, event): if self.dragging: geometry = self.selectband.asGeometry() if not geometry: return rect = geometry.boundingBox() else: rect = self.toSearchRect(event.pos()) self.dragging = False self.selectband.reset() features = dict(self.getFeatures(rect)) print features if len(features) == 1: feature = features.keys()[0] forms = features.values()[0] if len(forms) == 1: self.finished.emit(forms[0], feature) else: self.featuresfound.emit(features) elif len(features) > 0: self.featuresfound.emit(features) def isEditTool(self): return True
class ParentMapTool(QgsMapTool): def __init__(self, iface, settings, action, index_action): """ Class constructor """ self.iface = iface self.canvas = self.iface.mapCanvas() self.settings = settings self.show_help = bool(int(self.settings.value('status/show_help', 1))) self.index_action = index_action self.layer_arc = None self.layer_connec = None self.layer_gully = None self.layer_node = None self.schema_name = None self.controller = None self.dao = None self.snapper_manager = None # Call superclass constructor and set current action QgsMapTool.__init__(self, self.canvas) self.setAction(action) # Change map tool cursor self.cursor = QCursor() self.cursor.setShape(Qt.CrossCursor) # Get default cursor self.std_cursor = self.parent().cursor() # Set default vertex marker color = QColor(255, 100, 255) self.vertex_marker = QgsVertexMarker(self.canvas) self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE) self.vertex_marker.setColor(color) self.vertex_marker.setIconSize(15) self.vertex_marker.setPenWidth(3) # Set default rubber band color_selection = QColor(254, 178, 76, 63) self.rubber_band = QgsRubberBand(self.canvas, 2) self.rubber_band.setColor(color) self.rubber_band.setFillColor(color_selection) self.rubber_band.setWidth(1) self.reset() self.force_active_layer = True def get_cursor_multiple_selection(self): """ Set cursor for multiple selection """ path_folder = os.path.join(os.path.dirname(__file__), os.pardir) path_cursor = os.path.join(path_folder, 'icons', '201.png') if os.path.exists(path_cursor): cursor = QCursor(QPixmap(path_cursor)) else: cursor = QCursor(Qt.ArrowCursor) return cursor def set_controller(self, controller): self.controller = controller self.schema_name = controller.schema_name self.plugin_dir = self.controller.plugin_dir if self.snapper_manager is None: self.snapper_manager = SnappingConfigManager(self.iface) self.snapper_manager.controller = controller def deactivate(self): # Uncheck button self.action().setChecked(False) # Restore previous snapping self.snapper_manager.recover_snapping_options() # Enable snapping self.snapper_manager.enable_snapping(True) # Recover cursor self.canvas.setCursor(self.std_cursor) # Remove highlight self.vertex_marker.hide() def recover_previus_maptool(self): if self.controller.prev_maptool: self.iface.mapCanvas().setMapTool(self.controller.prev_maptool) self.controller.prev_maptool = None def remove_vertex(self): """ Remove vertex_marker from canvas""" vertex_items = [ i for i in self.iface.mapCanvas().scene().items() if issubclass(type(i), QgsVertexMarker) ] for ver in vertex_items: if ver in self.iface.mapCanvas().scene().items(): if self.vertex_marker == ver: self.iface.mapCanvas().scene().removeItem(ver) def set_icon(self, widget, icon): """ Set @icon to selected @widget """ # Get icons folder icons_folder = os.path.join(self.plugin_dir, 'icons') icon_path = os.path.join(icons_folder, str(icon) + ".png") if os.path.exists(icon_path): widget.setIcon(QIcon(icon_path)) else: self.controller.log_info("File not found", parameter=icon_path) def set_action_pan(self): """ Set action 'Pan' """ try: self.iface.actionPan().trigger() except Exception: pass def reset_rubber_band(self, geom_type="polygon"): try: if geom_type == "polygon": geom_type = QgsWkbTypes.PolygonGeometry elif geom_type == "line": geom_type = QgsWkbTypes.LineString self.rubber_band.reset(geom_type) except: pass def reset(self): self.reset_rubber_band() self.snapped_feat = None def cancel_map_tool(self): """ Executed if user press right button or escape key """ # Reset rubber band self.reset() # Deactivate map tool self.deactivate() self.set_action_pan() def remove_markers(self): """ Remove previous markers """ vertex_items = [ i for i in list(self.canvas.scene().items()) if issubclass(type(i), QgsVertexMarker) ] for ver in vertex_items: if ver in list(self.canvas.scene().items()): self.canvas.scene().removeItem(ver) def refresh_map_canvas(self): """ Refresh all layers present in map canvas """ self.canvas.refreshAllLayers() for layer_refresh in self.canvas.layers(): layer_refresh.triggerRepaint() def open_dialog(self, dlg=None, dlg_name=None, info=True, maximize_button=True, stay_on_top=True): """ Open dialog """ # Check database connection before opening dialog if not self.controller.check_db_connection(): return if dlg is None or type(dlg) is bool: dlg = self.dlg # Manage i18n of the dialog if dlg_name: self.controller.manage_translation(dlg_name, dlg) # Manage stay on top, maximize/minimize button and information button # if info is True maximize flag will be ignored # To enable maximize button you must set info to False flags = Qt.WindowCloseButtonHint if info: flags |= Qt.WindowSystemMenuHint | Qt.WindowContextHelpButtonHint else: if maximize_button: flags |= Qt.WindowMinMaxButtonsHint if stay_on_top: flags |= Qt.WindowStaysOnTopHint dlg.setWindowFlags(flags) # Open dialog if issubclass(type(dlg), GwDialog): dlg.open() elif issubclass(type(dlg), GwMainWindow): dlg.show() else: dlg.show() def close_dialog(self, dlg=None, set_action_pan=True): """ Close dialog """ if dlg is None or type(dlg) is bool: dlg = self.dlg try: self.save_settings(dlg) dlg.close() if set_action_pan: map_tool = self.canvas.mapTool() # If selected map tool is from the plugin, set 'Pan' as current one if map_tool.toolName() == '': self.set_action_pan() except AttributeError: pass def load_settings(self, dialog=None): """ Load QGIS settings related with dialog position and size """ if dialog is None: dialog = self.dlg try: x = self.controller.plugin_settings_value(dialog.objectName() + "_x") y = self.controller.plugin_settings_value(dialog.objectName() + "_y") width = self.controller.plugin_settings_value( dialog.objectName() + "_width", dialog.property('width')) height = self.controller.plugin_settings_value( dialog.objectName() + "_height", dialog.property('height')) if int(x) < 0 or int(y) < 0: dialog.resize(int(width), int(height)) else: screens = ctypes.windll.user32 screen_x = screens.GetSystemMetrics(78) screen_y = screens.GetSystemMetrics(79) if int(x) > screen_x: x = int(screen_x) - int(width) if int(y) > screen_y: y = int(screen_y) dialog.setGeometry(int(x), int(y), int(width), int(height)) except: pass def save_settings(self, dialog=None): """ Save QGIS settings related with dialog position and size """ if dialog is None: dialog = self.dlg try: self.controller.plugin_settings_set_value( dialog.objectName() + "_width", dialog.property('width')) self.controller.plugin_settings_set_value( dialog.objectName() + "_height", dialog.property('height')) self.controller.plugin_settings_set_value( dialog.objectName() + "_x", dialog.pos().x()) self.controller.plugin_settings_set_value( dialog.objectName() + "_y", dialog.pos().y()) except: pass def check_expression(self, expr_filter, log_info=False): """ Check if expression filter @expr is valid """ if log_info: self.controller.log_info(expr_filter) expr = QgsExpression(expr_filter) if expr.hasParserError(): message = "Expression Error" self.controller.log_warning(message, parameter=expr_filter) return False, expr return True, expr def get_composers_list(self): layour_manager = QgsProject.instance().layoutManager().layouts() active_composers = [layout for layout in layour_manager] return active_composers def get_composer_index(self, name): index = 0 composers = self.get_composers_list() for comp_view in composers: composer_name = comp_view.name() if composer_name == name: break index += 1 return index def canvasMoveEvent(self, event): # Make sure active layer is always 'v_edit_node' cur_layer = self.iface.activeLayer() if cur_layer != self.layer_node and self.force_active_layer: self.iface.setActiveLayer(self.layer_node) # Hide highlight and get coordinates self.vertex_marker.hide() event_point = self.snapper_manager.get_event_point(event) # Snapping result = self.snapper_manager.snap_to_current_layer(event_point) if self.snapper_manager.result_is_valid(): self.snapper_manager.add_marker(result, self.vertex_marker) def create_body(self, form='', feature='', filter_fields='', extras=None): """ Create and return parameters as body to functions""" client = f'$${{"client":{{"device":4, "infoType":1, "lang":"ES"}}, ' form = f'"form":{{{form}}}, ' feature = '"feature":{' + feature + '}, ' filter_fields = '"filterFields":{' + filter_fields + '}' page_info = '"pageInfo":{}' data = '"data":{' + filter_fields + ', ' + page_info if extras: data += ', ' + extras data += f'}}}}$$' body = "" + client + form + feature + data return body def refresh_legend(self): """ This function solves the bug generated by changing the type of feature. Mysteriously this bug is solved by checking and unchecking the categorization of the tables. # TODO solve this bug """ layers = [ self.controller.get_layer_by_tablename('v_edit_node'), self.controller.get_layer_by_tablename('v_edit_connec'), self.controller.get_layer_by_tablename('v_edit_gully') ] for layer in layers: if layer: ltl = QgsProject.instance().layerTreeRoot().findLayer( layer.id()) ltm = self.iface.layerTreeView().model() legendNodes = ltm.layerLegendNodes(ltl) for ln in legendNodes: current_state = ln.data(Qt.CheckStateRole) ln.setData(Qt.Unchecked, Qt.CheckStateRole) ln.setData(Qt.Checked, Qt.CheckStateRole) ln.setData(current_state, Qt.CheckStateRole) def put_layer_into_toc(self, tablename=None, the_geom="the_geom", field_id="id", group='GW Layers'): """ Put layer from postgres DB into TOC""" schema_name = self.controller.credentials['schema'].replace('"', '') uri = QgsDataSourceUri() uri.setConnection(self.controller.credentials['host'], self.controller.credentials['port'], self.controller.credentials['db'], self.controller.credentials['user'], self.controller.credentials['password']) if not field_id: field_id = self.controller.get_pk(tablename) if not field_id: field_id = "id" uri.setDataSource(schema_name, f'{tablename}', the_geom, None, field_id) layer = QgsVectorLayer(uri.uri(), f'{tablename}', "postgres") root = QgsProject.instance().layerTreeRoot() my_group = root.findGroup(group) if my_group is None: my_group = root.insertGroup(0, group) my_group.insertLayer(0, layer) self.iface.mapCanvas().refresh() return layer def populate_info_text(self, dialog, data, force_tab=True, reset_text=True, tab_idx=1): change_tab = False text = utils_giswater.getWidgetText(dialog, 'txt_infolog', return_string_null=False) if reset_text: text = "" for item in data['info']['values']: if 'message' in item: if item['message'] is not None: text += str(item['message']) + "\n" if force_tab: change_tab = True else: text += "\n" utils_giswater.setWidgetText(dialog, 'txt_infolog', text + "\n") qtabwidget = dialog.findChild(QTabWidget, 'mainTab') if change_tab and qtabwidget is not None: qtabwidget.setCurrentIndex(tab_idx) return change_tab
class BucketFill: """A little plugin to allow you to set the color of a vector class by clicking on it.""" def __init__(self, IFACE): # Save reference to the QGIS interface self.iface = IFACE self.canvas = self.iface.mapCanvas() self.bucketTool = QgsMapToolEmitPoint(self.canvas) self.polygonFlag = True self.rubberband = QgsRubberBand(self.canvas, self.polygonFlag) def initGui(self): """Called by QGIS to add gui elements to its Mainwindow etc. BucketFill class. Args: None Returns: None Raises: None """ self.initActions() # Add toolbar button and menu item - colour chooser self.iface.addToolBarIcon(self.colorChooserAction) self.iface.addPluginToMenu("&Bucket fill", self.colorChooserAction) # Add toolbar button and menu item - map tool self.iface.addToolBarIcon(self.bucketFillAction) self.iface.addPluginToMenu("&Bucket fill", self.bucketFillAction) def initActions(self): """Setup actions. Implemented in a separate function so it can be used in the context of our testing framework. Args: None Returns: None Raises: None """ # Create action that will start plugin configuration self.colorChooserAction = (QAction( QIcon(":/plugins/bucketfill/icon.png"), "Bucket fill", self.iface.mainWindow())) self.bucketFillAction = (QAction( QIcon(":/plugins/bucketfill/bucket.png"), "Bucket fill", self.iface.mainWindow())) # connect the action to the chooseColor method QObject.connect(self.colorChooserAction, SIGNAL("triggered()"), self.chooseColor) QObject.connect(self.bucketFillAction, SIGNAL("triggered()"), self.enableBucketTool) QObject.connect( self.bucketTool, SIGNAL("canvasClicked(const QgsPoint &, Qt::MouseButton)"), self.setColorForClass) def unload(self): """Constructor for the BucketFill class. Args: None Returns: None Raises: None """ self.iface.removePluginMenu("&Bucket fill", self.colorChooserAction) self.iface.removeToolBarIcon(self.colorChooserAction) self.iface.removeToolBarIcon(self.bucketFillAction) def chooseColor(self): """Show a color picker to let the user choose a color. Args: None Returns: None Raises: None """ mySettings = QSettings() try: myInitialColor = QColor( mySettings.value("vectorbucketfill/current_color")) except: myInitialColor = QColor(255, 255, 255) #myColor = QColor() myColor = QColorDialog.getColor(initial=myInitialColor) #myColorSelect = BucketFillDialog() if QColor.isValid(myColor): # do something useful mySettings.setValue("vectorbucketfill/current_color", myColor) def enableBucketTool(self): """Make the bucket tool active on the canvas. Args: None Returns: None Raises: None """ self.canvas.setMapTool(self.bucketTool) def setColorForClass(self, thePoint, theButton): """Set the color of the active layer's feature class that falls under the cursor Args: * thePoint - a QgsPoint indicating where the click on the canvas took place in map coordinates of the canvas. * theButton - a Qt::MouseButton enumerator indicating which button was clicked with Returns: None Raises: None """ # get the active layer myLayer = self.getActiveVectorLayer() # get style class list myStyles = self.getStyleClassList(myLayer) # identify click xy on canvas (map coords) myClickBox = self.getClickBbox(thePoint) # convert myClickBox to map coords #myExtent = self.pixelToCrsBox(myClickBox, self.canvas, myLayer) #settrace() # make a rubber band for visual confirmation of the click location myRubberBand = self.makeRubberBand(myClickBox) # use provider to select based on attr and bbox, and get first feature # from resulting list myFeature = self.getFirstFeature(myLayer, myClickBox) # find the symbol for said feature #mySymbol = self.getSymbolForFeature(myFeature) # clone class # set fill color for class # replace original with altered clone # refresh the canvas def getActiveVectorLayer(self): """Get the active vector layer. Args: None Returns: A valid QGIS vector layer Raises: IncorrectLayerTypeException if current layer is not a vector layer NoCurrentLayerException if no layer is selected. """ # get active layer for canvas myLayer = self.iface.activeLayer() if myLayer is None: myMessage = ('There is no current layer. Load a vector layer and ' 'select it before using it.') raise ex.NoCurrentLayerException(myMessage) # check that it's a vector if myLayer.type() == QgsMapLayer.VectorLayer: return myLayer else: myMessage = 'Current layer is not a vector layer.' raise ex.IncorrectLayerTypeException(myMessage) def getStyleClassList(self, theLayer): """ Get the list of style classes in the given layer. Args: Object: the active layer. Returns: A list of styles from the given layer. Raises: UnknownSymbolTypeException if symbol type is unknown. OldSymbologyException if layer uses old symbology. """ if not theLayer.isUsingRendererV2(): myMessage = ('This plugin does not currently' ' support old symbology.') raise ex.OldSymbologyException(myMessage) myRenderer = theLayer.rendererV2() myType = myRenderer.type() myStylesList = [] if myType == 'singleSymbol': mySymbol = myRenderer.symbol() myStylesList.append(mySymbol) elif myType == 'categorizedSymbol': for myCategory in myRenderer.categories(): mySymbol = myCategory.symbol().clone() myStylesList.append(mySymbol) elif myType == 'graduatedSymbol': for myRange in myRenderer.ranges(): mySymbol = myRange.symbol().clone() myStylesList.append(mySymbol) else: myMessage = 'Unknown symbol type.' raise ex.UnknownSymbolTypeException(myMessage) return myStylesList def getClickBbox(self, thePoint): """ Get a tiny bbox around a mouse click. Args: Point object. Returns: Tiny QgsRectangle bbox around point. Raises: CoordinateProcessingException if bbox creation encounters error. """ # get the xy coords #QMessageBox.information(None, 'VF', str(thePoint)) myX = thePoint.x() myY = thePoint.y() myUnitsPerPixel = self.canvas.mapUnitsPerPixel() # create a little bbox from clicked coords try: myBbox = QgsRectangle() myBbox.setXMinimum(myX - myUnitsPerPixel) myBbox.setYMinimum(myY - myUnitsPerPixel) myBbox.setXMaximum(myX + myUnitsPerPixel) myBbox.setYMaximum(myY + myUnitsPerPixel) #QMessageBox.information(None, 'VF', myBbox.toString()) return myBbox except: msg = 'Click coordinates could not be processed.' raise ex.CoordinateProcessingException(msg) def pixelToCrsBox(self, theClickBox, theCanvas, theLayer): """ Takes a bbox in pixel coords, converts it to a bbox in layer coords. Args: The bbox that needs to be converted. The current canvas. The current layer. Returns: The converted bbox. Raises: None """ # converts from screen to map canvas crs myMapToPixel = theCanvas.getCoordinateTransform() myX1 = theClickBox.xMinimum() myY1 = theClickBox.yMinimum() myPoint1 = myMapToPixel.toMapCoordinates(myX1, myY1) myX2 = theClickBox.xMaximum() myY2 = theClickBox.yMaximum() myPoint2 = myMapToPixel.toMapCoordinates(myX2, myY2) myRectangle = QgsRectangle(myPoint1, myPoint2) myExtent = theCanvas.mapRenderer()\ .mapToLayerCoordinates(theLayer, myRectangle) print "COMPUTED EXTENT: %s, %s, %s, %s" % ( myExtent.xMinimum(), myExtent.yMinimum(), myExtent.xMaximum(), myExtent.yMaximum()) return myExtent def makeRubberBand(self, theRectangle): """Makes a rubber band select on the canvas where the user clicked.""" self.rubberband.reset(True) self.rubberband = QgsRubberBand(self.canvas, True) self.rubberband.setColor(QColor(255, 0, 0)) self.rubberband.setWidth(10) self.rubberband.addPoint(QgsPoint(\ theRectangle.xMinimum(), theRectangle.yMinimum())) self.rubberband.addPoint(QgsPoint(\ theRectangle.xMaximum(), theRectangle.yMinimum())) self.rubberband.addPoint(QgsPoint(\ theRectangle.xMaximum(), theRectangle.yMaximum())) self.rubberband.addPoint(QgsPoint(\ theRectangle.xMinimum(), theRectangle.yMaximum())) def getFirstFeature(self, theLayer, theClickBox): """ Gets the first feature within the bbox in the active layer. Args: The current layer. The converted bbox. Returns: A feature. Raises: LayerLoadException if data could not be loaded. NoSelectedFeatureException if no feature is selected. """ myProvider = theLayer.dataProvider() if myProvider is None: msg = ('Could not obtain data provider from ' 'layer "%s"' % theLayer.source()) raise ex.LayerLoadException(msg) #myLayerExtent = theLayer.extent() myProvider.rewind() myAttributes = myProvider.attributeIndexes() myFetchGeometryFlag = False myUseIntersectFlag = False QMessageBox.information(None, 'Provider', str(myProvider)) QMessageBox.information(None, 'Box', str(theClickBox)) self.rubberband.reset(True) mySelection = myProvider.select(myAttributes, theClickBox, myFetchGeometryFlag, myUseIntersectFlag) mySelection = myProvider.select(myAttributes, theClickBox, False) #theLayer.select([]) # we don't actually need the attributes #theLayer.setSelectedFeatures([myF.id() for myF in theLayer]) # select all the feature ids if mySelection == None: myFeatureCount = theLayer.featureCount() raise ex.NoSelectedFeatureException( "No feature selected. Using " "provider {%s}, " "attributes {%s}, and " "rectangle {%s} with " "extents {%s, %s, %s, %s}. " "Layer has %s features in total." % ( str(myProvider), #str(myAttributes), "attrs", str(theClickBox), theClickBox.xMinimum(), theClickBox.yMinimum(), theClickBox.xMaximum(), theClickBox.yMaximum(), str(myFeatureCount))) else: myFeature = myProvider.nextFeature(mySelection) return myFeature def getStyleForFeature(self, theFeature): """ Gets the class of the feature passed to it. Args: A feature. Returns: A class. Raises: None. """ pass
class QgepMapToolDigitizeDrainageChannel(QgsMapTool): ''' This is used to digitize a drainage channel. It lets you digitize two points and then creates a polygon based on these two points by adding an orthogonal offset at each side. Input: x==============x Output: ---------------- | | ---------------- Usage: Connect to the signals deactivated() and geometryDigitized() If geometryDigitized() is called you can use the member variable geometry which will contain a rectangle polygon deactivated() will be emited after a right click ''' geometryDigitized = pyqtSignal() def __init__(self, iface, layer): QgsMapTool.__init__(self, iface.mapCanvas()) self.iface = iface self.canvas = iface.mapCanvas() self.layer = layer self.rubberband = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.LineGeometry) self.rubberband.setColor(QColor("#ee5555")) self.rubberband.setWidth(2) self.firstPoint = None self.messageBarItem = None self.geometry = None def activate(self): """ Map tool is activated """ QgsMapTool.activate(self) self.canvas.setCursor(QCursor(Qt.CrossCursor)) msgtitle = self.tr('Digitizing Drainage Channel') msg = self.tr('Digitize start and end point. Rightclick to abort.') self.messageBarItem = QgsMessageBar.createMessage(msgtitle, msg) self.iface.messageBar().pushItem(self.messageBarItem) def deactivate(self): """ Map tool is deactivated """ QgsMapTool.deactivate(self) self.iface.messageBar().popWidget(self.messageBarItem) try: self.iface.mapCanvas().scene().removeItem(self.rubberband) del self.rubberband except AttributeError: # Called repeatedly... bail out pass self.canvas.unsetCursor() def canvasMoveEvent(self, event): """ Mouse is moved: Update rubberband :param event: coordinates etc. """ mousepos = event.mapPoint() self.rubberband.movePoint(mousepos) def canvasReleaseEvent(self, event): """ Canvas is released. This means: * start digitizing * stop digitizing (create a rectangle * if the Ctrl-modifier is pressed, ask for the rectangle width :param event: coordinates etc. """ if event.button() == Qt.RightButton: self.deactivate() else: mousepos = self.canvas.getCoordinateTransform()\ .toMapCoordinates(event.pos().x(), event.pos().y()) self.rubberband.addPoint(mousepos) if self.firstPoint: # If the first point was set before, we are doing the second one lp1 = self.rubberband.asGeometry().asPolyline()[0] lp2 = self.rubberband.asGeometry().asPolyline()[1] width = 0.2 if QApplication.keyboardModifiers() & Qt.ControlModifier: dlg = QDialog() dlg.setLayout(QGridLayout()) dlg.layout().addWidget(QLabel(self.tr('Enter width'))) txt = QLineEdit('0.2') dlg.layout().addWidget(txt) bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) dlg.layout().addWidget(bb) bb.accepted.connect(dlg.accept) bb.rejected.connect(dlg.reject) if dlg.exec_(): try: width = float(txt.text()) except ValueError: width = 0.2 length = math.sqrt( math.pow(lp1.x() - lp2.x(), 2) + math.pow(lp1.y() - lp2.y(), 2)) xd = lp2.x() - lp1.x() yd = lp2.y() - lp1.y() pt1 = QgsPointXY(lp1.x() + width * (yd / length), lp1.y() - width * (xd / length)) pt2 = QgsPointXY(lp1.x() - width * (yd / length), lp1.y() + width * (xd / length)) pt3 = QgsPointXY(lp2.x() - width * (yd / length), lp2.y() + width * (xd / length)) pt4 = QgsPointXY(lp2.x() + width * (yd / length), lp2.y() - width * (xd / length)) self.geometry = QgsGeometry.fromPolygonXY( [[pt1, pt2, pt3, pt4, pt1]]) self.geometryDigitized.emit() self.firstPoint = mousepos
class SplineTool(QgsMapToolEdit): def __init__(self, iface): super(SplineTool, self).__init__(iface.mapCanvas()) self.iface = iface self.canvas = self.iface.mapCanvas() self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.snap_marker = QgsVertexMarker(self.canvas) self.snapping_utils = self.canvas.snappingUtils() self.points = [] # digitized, not yet interpolated points self.type = QgsWkbTypes.LineGeometry # layer geometry type self.tolerance = None self.tightness = None self.is_polygon = None self.cursor = QCursor( QPixmap([ "16 16 3 1", " c None", ". c #FF0000", "+ c #FFFFFF", " ", " +.+ ", " ++.++ ", " +.....+ ", " +. .+ ", " +. . .+ ", " +. . .+ ", " ++. . .++", " ... ...+... ...", " ++. . .++", " +. . .+ ", " +. . .+ ", " ++. .+ ", " ++.....+ ", " ++.++ ", " +.+ ", ])) s = QgsSettings() self.snap_col = s.value("/qgis/digitizing/snap_color", QColor("#ff00ff")) def canvasMoveEvent(self, event): color = QColor(255, 0, 0, 100) self.rb.setColor(color) self.rb.setWidth(1) point = self.toMapCoordinates(event.pos()) # try to snap to a feature result = self.snapping_utils.snapToMap(point) if result.isValid(): point = result.point() self.update_snap_marker(snapped_pt=point) else: self.update_snap_marker() points = list(self.points) points.append(QgsPoint(point)) points = interpolate(points) self.set_rubber_band_points(points) def canvasReleaseEvent(self, event): color = QColor(255, 0, 0, 100) self.rb.setColor(color) self.rb.setWidth(1) point = self.toMapCoordinates(event.pos()) if event.button() == Qt.LeftButton: # try to snap to a feature result = self.snapping_utils.snapToMap(point) if result.isValid(): point = result.point() self.points.append(QgsPoint(point)) points = interpolate(self.points) self.set_rubber_band_points(points) else: if len(self.points) >= 2: # refresh without last point self.refresh() self.create_feature() self.reset_points() self.reset_rubber_band() self.canvas.refresh() def keyPressEvent(self, e): if e.key() == Qt.Key_Escape: self.deactivate() self.activate() elif e.key() == Qt.Key_Backspace: if self.points: self.points.pop() points = interpolate(self.points) self.set_rubber_band_points(points) self.canvas.refresh() def reset_points(self): self.points = [] # Create feature from digitized points, i.e. without the last moving point # where right click happened. This the same way how core QGIS Add Feature works. def create_feature(self): layer = self.iface.activeLayer() provider = layer.dataProvider() fields = provider.fields() f = QgsFeature(fields) coords = [QgsPointXY(pt) for pt in interpolate(self.points)] proj = QgsProject.instance() if layer.crs() != proj.crs(): trans_context = proj.transformContext() transf = QgsCoordinateTransform(proj.crs(), layer.crs(), trans_context) coords_tmp = coords[:] coords = [] for point in coords_tmp: transformed_pt = transf.transform(point) coords.append(transformed_pt) # Add geometry to feature if self.is_polygon: g = QgsGeometry.fromPolygonXY([coords]) else: g = QgsGeometry.fromPolylineXY(coords) f.setGeometry(g) # Add attribute fields to feature for field in fields.toList(): ix = fields.indexFromName(field.name()) f[field.name()] = provider.defaultValue(ix) layer.beginEditCommand("Feature added") settings = QSettings() disable_attributes = settings.value( "/qgis/digitizing/disable_enter_attribute_values_dialog", False, type=bool) layer.addFeature(f) if disable_attributes: layer.endEditCommand() else: dlg = self.iface.getFeatureForm(layer, f) if dlg.exec_(): layer.endEditCommand() else: layer.destroyEditCommand() def refresh(self): if self.points: points = interpolate(self.points) self.set_rubber_band_points(points) def canvasPressEvent(self, event): pass def showSettingsWarning(self): pass def activate(self): self.canvas.setCursor(self.cursor) layer = self.iface.activeLayer() self.type = layer.geometryType() self.is_polygon = False if self.type == QgsWkbTypes.PolygonGeometry: self.is_polygon = True def reset_rubber_band(self): self.rb.reset(self.type) def set_rubber_band_points(self, points): self.reset_rubber_band() for point in points: update = point is points[-1] if isinstance(point, QgsPoint): point = QgsPointXY(point) self.rb.addPoint(point, update) def update_snap_marker(self, snapped_pt=None): self.canvas.scene().removeItem(self.snap_marker) if snapped_pt is None: return self.snap_marker = QgsVertexMarker(self.canvas) self.snap_marker.setCenter(snapped_pt) self.snap_marker.setIconSize(16) self.snap_marker.setIconType(QgsVertexMarker.ICON_BOX) self.snap_marker.setPenWidth(3) self.snap_marker.setColor(self.snap_col) def deactivate(self): self.reset_points() self.update_snap_marker() self.reset_rubber_band() QgsMapToolEdit.deactivate(self) def isZoomTool(self): return False def isTransient(self): return False def isEditTool(self): return True
class CaptureCoordinateTool(QgsMapTool): def __init__(self, canvas, txtXCoord, txtYCoord, annotation=None): self.canvas = canvas self.txtXCoord = txtXCoord self.txtYCoord = txtYCoord QgsMapToolEmitPoint.__init__(self, self.canvas) self.annotation = annotation self.mSnapper = QgsMapCanvasSnapper(canvas) self.rubberBand = QgsRubberBand(canvas, QGis.Point) self.rubberBand.setColor(Qt.red) self.rubberBand.setWidth(10) self.rubberBandClick = QgsRubberBand(canvas, QGis.Point) self.rubberBandClick.setColor(Qt.green) self.rubberBandClick.setWidth(3) # lblDoc = QTextDocument(label) # self.annotation.setDocument(lblDoc) # self.annotation.setFrameBackgroundColor(QColor(0,0,0,0)) # self.annotation.setFrameSize( QSizeF( 30, 20 ) ) self.reset() def reset(self): self.Point = None # def canvasPressEvent(self, e): def canvasReleaseEvent(self, e): # self.Point = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas) self.Point = self.snapPoint(e.pos()) if self.annotation is not None: self.annotation.setMapPosition(self.Point) self.annotation.show() else: self.rubberBandClick.reset(QGis.Point) # snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas, True) self.rubberBandClick.addPoint(self.Point) self.rubberBandClick.show() # self.setOffsetFromReferencePoint (QPointF(self.Point.x(),self.Point.y())) self.txtXCoord.setText(str(self.Point.x())) # print str(self.Point.x()) self.txtYCoord.setText(str(self.Point.y())) def canvasMoveEvent(self, e): if define._snapping == False: return self.rubberBand.reset(QGis.Point) # snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas, True) snapPoint = self.snapPoint(e.pos(), True) if snapPoint == None: return self.rubberBand.addPoint(snapPoint) self.rubberBand.show() def snapPoint(self, p, bNone=False): if define._snapping == False: return define._canvas.getCoordinateTransform().toMapCoordinates(p) snappingResults = self.mSnapper.snapToBackgroundLayers(p) if (snappingResults[0] != 0 or len(snappingResults[1]) < 1): if bNone: return None else: return define._canvas.getCoordinateTransform( ).toMapCoordinates(p) else: return snappingResults[1][0].snappedVertex def deactivate(self): self.rubberBand.reset(QGis.Point) QgsMapTool.deactivate(self) self.emit(SIGNAL("deactivated()"))
class ItemWidgetBase(QFrame): checkedStateChanged = pyqtSignal() thumbnailChanged = pyqtSignal() def __init__(self, item): QFrame.__init__(self) self.item = item self.is_updating_checkbox = False self.setMouseTracking(True) self.setStyleSheet("ItemWidgetBase{border: 2px solid transparent;}") def _setup_ui(self, text, thumbnailurl): self.lockLabel = QLabel() iconSize = QSize(16, 16) self.lockLabel.setPixmap(LOCK_ICON.pixmap(iconSize)) self.checkBox = QCheckBox("") self.checkBox.stateChanged.connect(self.check_box_state_changed) self.nameLabel = QLabel(text) self.iconLabel = QLabel() self.labelZoomTo = QLabel() self.labelZoomTo.setPixmap(ZOOMTO_ICON.pixmap(QSize(18, 18))) self.labelZoomTo.setToolTip("Zoom to extent") self.labelZoomTo.mousePressEvent = self.zoom_to_extent self.labelAddPreview = QLabel() self.labelAddPreview.setPixmap(ADD_PREVIEW_ICON.pixmap(QSize(18, 18))) self.labelAddPreview.setToolTip("Add preview layer to map") self.labelAddPreview.mousePressEvent = self._add_preview_clicked layout = QHBoxLayout() layout.setMargin(0) layout.addWidget(self.checkBox) layout.addWidget(self.lockLabel) pixmap = QPixmap(PLACEHOLDER_THUMB, 'SVG') self.thumbnail = None thumb = pixmap.scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) self.iconLabel.setFixedSize(48, 48) layout.addWidget(self.iconLabel) if thumbnailurl is not None: download_thumbnail(thumbnailurl, self) layout.addWidget(self.nameLabel) layout.addStretch() layout.addWidget(self.labelZoomTo) layout.addWidget(self.labelAddPreview) layout.addSpacing(10) self.setLayout(layout) self.footprint = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self.footprint.setStrokeColor(PLANET_COLOR) self.footprint.setWidth(2) def set_thumbnail(self, img): self.thumbnail = QPixmap(img) thumb = self.thumbnail.scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) self.thumbnailChanged.emit() def is_selected(self): return self.checkBox.isChecked() def _geom_bbox_in_project_crs(self): transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance().crs(), QgsProject.instance()) return transform.transformBoundingBox(self.geom.boundingBox()) def _geom_in_project_crs(self): transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance().crs(), QgsProject.instance()) geom = QgsGeometry(self.geom) geom.transform(transform) return geom def show_footprint(self): self.footprint.setToGeometry(self._geom_in_project_crs()) def hide_footprint(self): self.footprint.reset(QgsWkbTypes.PolygonGeometry) def enterEvent(self, event): self.setStyleSheet( "ItemWidgetBase{border: 2px solid rgb(0, 157, 165);}") self.show_footprint() def leaveEvent(self, event): self.setStyleSheet("ItemWidgetBase{border: 2px solid transparent;}") self.hide_footprint() def zoom_to_extent(self, evt): rect = QgsRectangle(self._geom_bbox_in_project_crs()) rect.scale(1.05) iface.mapCanvas().setExtent(rect) iface.mapCanvas().refresh() def _add_preview_clicked(self, evt): self.add_preview() @waitcursor def add_preview(self): if is_segments_write_key_valid(): item_ids = [ f"{img['properties'][ITEM_TYPE]}:{img[ID]}" for img in self.item.images() ] analytics.track(PlanetClient.getInstance().user()["email"], "Scene preview added to map", {"images": item_ids}) create_preview_group(self.name(), self.item.images()) def check_box_state_changed(self): self.checkedStateChanged.emit() self.is_updating_checkbox = True total = self.item.childCount() if self.checkBox.isTristate(): self.checkBox.setTristate(False) self.checkBox.setChecked(False) else: for i in range(total): w = self.item.treeWidget().itemWidget(self.item.child(i), 0) w.set_checked(self.checkBox.isChecked()) self.is_updating_checkbox = False def update_checkbox(self): if self.is_updating_checkbox: return selected = 0 total = self.item.childCount() for i in range(total): w = self.item.treeWidget().itemWidget(self.item.child(i), 0) if w.is_selected(): selected += 1 self.checkBox.blockSignals(True) if selected == total: self.checkBox.setTristate(False) self.checkBox.setCheckState(Qt.Checked) elif selected == 0: self.checkBox.setTristate(False) self.checkBox.setCheckState(Qt.Unchecked) else: self.checkBox.setTristate(True) self.checkBox.setCheckState(Qt.PartiallyChecked) self.checkBox.blockSignals(False) self.checkedStateChanged.emit() def set_checked(self, checked): self.checkBox.setChecked(checked) def update_thumbnail(self): thumbnails = self.scene_thumbnails() if thumbnails and None not in thumbnails: bboxes = [img[GEOMETRY] for img in self.item.images()] pixmap = createCompoundThumbnail(bboxes, thumbnails) thumb = pixmap.scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) self.thumbnailChanged.emit() def scene_thumbnails(self): thumbnails = [] for i in range(self.item.childCount()): w = self.item.treeWidget().itemWidget(self.item.child(i), 0) thumbnails.extend(w.scene_thumbnails()) return thumbnails
class CaptureCoordinateToolUpdate(QgsMapTool): def __init__(self, canvas, annotation=None): self.canvas = canvas # self.tableView = tableView # self.standardItemModel = standardItemModel # self.txtXCoord = txtXCoord # self.txtYCoord = txtYCoord QgsMapToolEmitPoint.__init__(self, self.canvas) self.annotation = annotation self.mSnapper = QgsMapCanvasSnapper(canvas) self.rubberBand = QgsRubberBand(canvas, QGis.Point) self.rubberBand.setColor(Qt.red) self.rubberBand.setWidth(10) self.rubberBandClick = QgsRubberBand(canvas, QGis.Point) self.rubberBandClick.setColor(Qt.green) self.rubberBandClick.setWidth(3) self.obstaclesLayerList = QgisHelper.getSurfaceLayers( SurfaceTypes.Obstacles) self.demLayerList = QgisHelper.getSurfaceLayers(SurfaceTypes.DEM) # lblDoc = QTextDocument(label) # self.annotation.setDocument(lblDoc) # self.annotation.setFrameBackgroundColor(QColor(0,0,0,0)) # self.annotation.setFrameSize( QSizeF( 30, 20 ) ) self.reset() def reset(self): self.Point = None # def canvasPressEvent(self, e): def canvasReleaseEvent(self, e): pointBackground = e.pos() # self.Point = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas) self.Point, self.pointID, self.layer = self.snapPoint(e.pos()) self.selectedLayerFromSnapPoint = None resultValueList = [] if self.annotation is not None: self.annotation.setMapPosition(self.Point) self.annotation.show() else: self.rubberBandClick.reset(QGis.Point) # snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas, True) self.rubberBandClick.addPoint(self.Point) self.rubberBandClick.show() self.selectedLayerFromSnapPoint = define._canvas.currentLayer() # if self.obstaclesLayerList != None: # for obstacleLayer in self.obstaclesLayerList: # if self.layer == None: # break # if obstacleLayer.name() == self.layer.name(): # self.selectedLayerFromSnapPoint = self.layer # break if self.selectedLayerFromSnapPoint != None and isinstance( self.selectedLayerFromSnapPoint, QgsVectorLayer) and self.pointID != None: # if self.pointID == None: # resultValueList.append("Background") # # resultValueList.append(str(self.Point.x())) # resultValueList.append(str(self.Point.y())) # resultValueList.append("0.0") # else: dataProvider = self.selectedLayerFromSnapPoint.dataProvider() featureIter = dataProvider.getFeatures( QgsFeatureRequest(self.pointID)) feature = None for feature0 in featureIter: feature = feature0 idx = self.selectedLayerFromSnapPoint.fieldNameIndex('Name') if not idx == -1: idValue = feature.attributes()[idx] resultValueList.append(idValue.toString()) else: resultValueList.append("") # itemList.append(QStandardItem(idValue.toString())) resultValueList.append(str(self.Point.x())) resultValueList.append(str(self.Point.y())) idx = self.selectedLayerFromSnapPoint.fieldNameIndex('Altitude') if not idx == -1: altitudeValue = feature.attributes()[idx] resultValueList.append(altitudeValue.toString()) else: resultValueList.append("0.0") else: if self.Point != None: identifyResult = None idValue = "Background" if self.demLayerList != None: for demLayer in self.demLayerList: identifyResults = demLayer.dataProvider().identify( self.Point, QgsRaster.IdentifyFormatValue) identifyResult = identifyResults.results() if identifyResult != None and identifyResult[1].toString( ) != "": idValue = "DEM" resultValueList.append(idValue) resultValueList.append(str(self.Point.x())) resultValueList.append(str(self.Point.y())) if identifyResult != None and identifyResult[1].toString( ) != "": resultValueList.append(identifyResult[1].toString()) else: resultValueList.append("0") self.emit(SIGNAL("resultPointValueList"), resultValueList) def canvasMoveEvent(self, e): if define._snapping == False: return self.rubberBand.reset(QGis.Point) # snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas, True) snapPoint, snapPointID, layer = self.snapPoint(e.pos(), True) if snapPoint == None: return self.rubberBand.addPoint(snapPoint) self.rubberBand.show() # print snapPointID def snapPoint(self, p, bNone=False): if define._snapping == False: return ( define._canvas.getCoordinateTransform().toMapCoordinates(p), None, None) snappingResults = self.mSnapper.snapToCurrentLayer( p, QgsSnapper.SnapToVertex) if (snappingResults[0] != 0 or len(snappingResults[1]) < 1): if bNone: return (None, None, None) else: return (define._canvas.getCoordinateTransform(). toMapCoordinates(p), None, None) else: return (snappingResults[1][0].snappedVertex, snappingResults[1][0].snappedAtGeometry, snappingResults[1][0].layer) def deactivate(self): self.rubberBand.reset(QGis.Point) QgsMapTool.deactivate(self) self.emit(SIGNAL("deactivated()"))
class AddPipeTool(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.mouse_pt = None self.mouse_clicked = False self.first_click = False self.rubber_band = QgsRubberBand(self.canvas(), False) self.rubber_band.setColor(QColor(255, 128, 128)) self.rubber_band.setWidth(1) self.rubber_band.setBrushStyle(Qt.Dense4Pattern) self.rubber_band.reset() self.snapper = None self.snapped_feat_id = None self.snapped_vertex = None self.snapped_vertex_nr = None self.vertex_marker = QgsVertexMarker(self.canvas()) self.elev = None self.diameter_dialog = None def canvasPressEvent(self, event): if event.button() == Qt.RightButton: self.mouse_clicked = False if event.button() == Qt.LeftButton: self.mouse_clicked = True def canvasMoveEvent(self, event): self.mouse_pt = self.toMapCoordinates(event.pos()) last_ix = self.rubber_band.numberOfVertices() self.rubber_band.movePoint(last_ix - 1, (self.snapped_vertex if self.snapped_vertex is not None else self.mouse_pt)) elev = raster_utils.read_layer_val_from_coord(self.params.dem_rlay, self.mouse_pt, 1) self.elev = elev if elev is not None: self.data_dock.lbl_elev_val.setText("{0:.2f}".format(self.elev)) else: self.data_dock.lbl_elev_val.setText('-') # Mouse not clicked: snapping to closest vertex match = self.snapper.snapToMap(self.mouse_pt) if match.isValid(): # Pipe starts from an existing vertex self.snapped_feat_id = match.featureId() self.snapped_vertex = match.point() self.snapped_vertex_nr = match.vertexIndex() self.vertex_marker.setCenter(self.snapped_vertex) self.vertex_marker.setColor(QColor(255, 0, 0)) self.vertex_marker.setIconSize(10) self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE) self.vertex_marker.setPenWidth(3) self.vertex_marker.show() # else: # It's a new, isolated pipe self.snapped_vertex = None self.snapped_feat_id = None self.vertex_marker.hide() def canvasReleaseEvent(self, event): # if not self.mouse_clicked: # return if event.button() == Qt.LeftButton: # Update rubber bands self.rubber_band.addPoint( (self.snapped_vertex if self.snapped_vertex is not None else self.mouse_pt), True) if self.first_click: self.rubber_band.addPoint( (self.snapped_vertex if self.snapped_vertex is not None else self.mouse_pt), True) self.first_click = not self.first_click elif event.button() == Qt.RightButton: # try: pipe_band_geom = self.rubber_band.asGeometry() # No rubber band geometry and feature snapped: pop the context menu if pipe_band_geom is None and self.snapped_feat_id is not None: menu = QMenu() section_action = menu.addAction('Section...') # TODO: softcode diameter_action = menu.addAction( 'Change diameter...') # TODO: softcode action = menu.exec_(self.iface.mapCanvas().mapToGlobal( QPoint(event.pos().x(), event.pos().y()))) pipe_ft = vector_utils.get_feats_by_id(self.params.pipes_vlay, self.snapped_feat_id)[0] if action == section_action: if self.params.dem_rlay is None: self.iface.messageBar().pushMessage( Parameters.plug_in_name, 'No DEM selected. Cannot edit section.', QgsMessageBar.WARNING, 5) # TODO: softcode else: # Check whether the pipe is all inside the DEM pipe_pts = pipe_ft.geometry().asPolyline() for pt in pipe_pts: if not self.params.dem_rlay.extent().contains(pt): self.iface.messageBar().pushMessage( Parameters.plug_in_name, 'Some pipe vertices fall outside of the DEM. Cannot edit section.', QgsMessageBar.WARNING, 5) # TODO: softcode return # Check whether the start/end nodes have an elevation value (start_node_ft, end_node_ft) = NetworkUtils.find_start_end_nodes( self.params, pipe_ft.geometry()) start_node_elev = start_node_ft.attribute( Junction.field_name_elev) end_node_elev = end_node_ft.attribute( Junction.field_name_elev) if start_node_elev == NULL or end_node_elev == NULL: self.iface.messageBar().pushMessage( Parameters.plug_in_name, 'Missing elevation value in start or end node attributes. Cannot edit section.', QgsMessageBar.WARNING, 5) # TODO: softcode return pipe_dialog = PipeSectionDialog( self.iface.mainWindow(), self.iface, self.params, pipe_ft) pipe_dialog.exec_() elif action == diameter_action: old_diam = pipe_ft.attribute(Pipe.field_name_diameter) self.diameter_dialog = DiameterDialog( self.iface.mainWindow(), self.params, old_diam) self.diameter_dialog.exec_() # Exec creates modal dialog new_diameter = self.diameter_dialog.get_diameter() if new_diameter is None: return # Update pipe diameter vector_utils.update_attribute(self.params.pipes_vlay, pipe_ft, Pipe.field_name_diameter, new_diameter) # Check if a valve is present adj_valves = NetworkUtils.find_links_adjacent_to_link( self.params, self.params.pipes_vlay, pipe_ft, True, True, False) if adj_valves['valves']: self.iface.messageBar().pushMessage( Parameters.plug_in_name, 'Valves detected on the pipe: need to update their diameters too.', QgsMessageBar.WARNING, 5) # TODO: softcode return # There's a rubber band: create new pipe if pipe_band_geom is not None: # Finalize line rubberband_pts = pipe_band_geom.asPolyline()[:-1] rubberband_pts = self.remove_duplicated_point(rubberband_pts) if len(rubberband_pts) < 2: return # Check whether the pipe points are located on existing nodes junct_nrs = [0] for p in range(1, len(rubberband_pts) - 1): overlapping_nodes = NetworkUtils.find_overlapping_nodes( self.params, rubberband_pts[p]) if overlapping_nodes['junctions'] or overlapping_nodes[ 'reservoirs'] or overlapping_nodes['tanks']: junct_nrs.append(p) junct_nrs.append(len(rubberband_pts) - 1) new_pipes_nr = len(junct_nrs) - 1 new_pipes_fts = [] new_pipes_eids = [] for np in range(new_pipes_nr): pipe_eid = NetworkUtils.find_next_id( self.params.pipes_vlay, Pipe.prefix) # TODO: softcode demand = float(self.data_dock.txt_pipe_demand.text()) diameter = float(self.data_dock.txt_pipe_diameter.text()) loss = float(self.data_dock.txt_pipe_loss.text()) roughness = float( self.data_dock.lbl_pipe_roughness_val_val.text()) status = self.data_dock.cbo_pipe_status.currentText() material = self.data_dock.cbo_pipe_roughness.currentText() pipe_desc = self.data_dock.txt_pipe_desc.text() pipe_tag = self.data_dock.cbo_pipe_tag.currentText() pipe_ft = LinkHandler.create_new_pipe( self.params, pipe_eid, diameter, loss, roughness, status, material, rubberband_pts[junct_nrs[np]:junct_nrs[np + 1] + 1], True, pipe_desc, pipe_tag) self.rubber_band.reset() new_pipes_fts.append(pipe_ft) new_pipes_eids.append(pipe_eid) emitter_coeff_s = self.data_dock.txt_junction_emit_coeff.text() if emitter_coeff_s is None or emitter_coeff_s == '': emitter_coeff = float(0) else: emitter_coeff = float( self.data_dock.txt_junction_emit_coeff.text()) # Description junction_desc = self.data_dock.txt_junction_desc.text() # Tag junction_tag = self.data_dock.cbo_junction_tag.currentText() # Create start and end node, if they don't exist (start_junction, end_junction) = NetworkUtils.find_start_end_nodes( self.params, new_pipes_fts[0].geometry()) new_start_junction = None if not start_junction: new_start_junction = rubberband_pts[0] junction_eid = NetworkUtils.find_next_id( self.params.junctions_vlay, Junction.prefix) elev = raster_utils.read_layer_val_from_coord( self.params.dem_rlay, new_start_junction, 1) if elev is None: elev = 0 # If elev is none, and the DEM is selected, it's better to inform the user if self.params.dem_rlay is not None: self.iface.messageBar().pushMessage( Parameters.plug_in_name, 'Elevation value not available: element elevation set to 0.', QgsMessageBar.WARNING, 5) # TODO: softcode deltaz = float(self.data_dock.txt_junction_deltaz.text()) j_demand = float(self.data_dock.txt_junction_demand.text()) pattern = self.data_dock.cbo_junction_pattern.itemData( self.data_dock.cbo_junction_pattern.currentIndex()) if pattern is not None: pattern_id = pattern.id else: pattern_id = None NodeHandler.create_new_junction( self.params, new_start_junction, junction_eid, elev, j_demand, deltaz, pattern_id, emitter_coeff, junction_desc, junction_tag) (start_junction, end_junction) = NetworkUtils.find_start_end_nodes( self.params, new_pipes_fts[len(new_pipes_fts) - 1].geometry()) new_end_junction = None if not end_junction: new_end_junction = rubberband_pts[len(rubberband_pts) - 1] junction_eid = NetworkUtils.find_next_id( self.params.junctions_vlay, Junction.prefix) elev = raster_utils.read_layer_val_from_coord( self.params.dem_rlay, new_end_junction, 1) if elev is None: elev = 0 # If elev is none, and the DEM is selected, it's better to inform the user if self.params.dem_rlay is not None: self.iface.messageBar().pushMessage( Parameters.plug_in_name, 'Elevation value not available: element elevation set to 0.', QgsMessageBar.WARNING, 5) # TODO: softcode deltaz = float(self.data_dock.txt_junction_deltaz.text()) pattern = self.data_dock.cbo_junction_pattern.itemData( self.data_dock.cbo_junction_pattern.currentIndex()) if pattern is not None: pattern_id = pattern.id else: pattern_id = None NodeHandler.create_new_junction( self.params, new_end_junction, junction_eid, elev, demand, deltaz, pattern_id, emitter_coeff, junction_desc, junction_tag) # If end or start node intersects a pipe, split it if new_start_junction: for pipe_ft in self.params.pipes_vlay.getFeatures(): if pipe_ft.attribute(Pipe.field_name_eid) != new_pipes_eids[0] and\ pipe_ft.geometry().distance(QgsGeometry.fromPoint(new_start_junction)) < self.params.tolerance: LinkHandler.split_pipe(self.params, pipe_ft, new_start_junction) if new_end_junction: for pipe_ft in self.params.pipes_vlay.getFeatures(): if pipe_ft.attribute(Pipe.field_name_eid) != new_pipes_eids[-1] and\ pipe_ft.geometry().distance(QgsGeometry.fromPoint(new_end_junction)) < self.params.tolerance: LinkHandler.split_pipe(self.params, pipe_ft, new_end_junction) # except Exception as e: # self.rubber_band.reset() # self.iface.messageBar().pushWarning('Cannot add new pipe to ' + self.params.pipes_vlay.name() + ' layer', repr(e)) # traceback.print_exc(file=sys.stdout) def keyReleaseEvent(self, event): if event.key() == Qt.Key_Escape: self.rubber_band.reset() def activate(self): self.update_snapper() # Editing if not self.params.junctions_vlay.isEditable(): self.params.junctions_vlay.startEditing() if not self.params.pipes_vlay.isEditable(): self.params.pipes_vlay.startEditing() def deactivate(self): QgsProject.instance().setSnapSettingsForLayer( self.params.junctions_vlay.id(), True, QgsSnapper.SnapToVertex, QgsTolerance.MapUnits, 0, True) QgsProject.instance().setSnapSettingsForLayer( self.params.reservoirs_vlay.id(), True, QgsSnapper.SnapToVertex, QgsTolerance.MapUnits, 0, True) QgsProject.instance().setSnapSettingsForLayer( self.params.tanks_vlay.id(), True, QgsSnapper.SnapToVertex, QgsTolerance.MapUnits, 0, True) QgsProject.instance().setSnapSettingsForLayer( self.params.pipes_vlay.id(), True, QgsSnapper.SnapToSegment, QgsTolerance.MapUnits, 0, True) # self.rubber_band.reset() self.data_dock.btn_add_pipe.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 reset_marker(self): self.outlet_marker.hide() self.canvas().scene().removeItem(self.outlet_marker) def remove_duplicated_point(self, pts): # This is needed because the rubber band sometimes returns duplicated points purged_pts = [pts[0]] for p in enumerate(range(len(pts) - 1), 1): if pts[p[0]] == pts[p[0] - 1]: continue else: purged_pts.append(pts[p[0]]) return purged_pts def update_snapper(self): layers = { self.params.junctions_vlay: QgsPointLocator.Vertex, self.params.reservoirs_vlay: QgsPointLocator.Vertex, self.params.tanks_vlay: QgsPointLocator.Vertex, self.params.pipes_vlay: QgsPointLocator.All } self.snapper = NetworkUtils.set_up_snapper(layers, self.iface.mapCanvas(), self.params.snap_tolerance) # Needed by Observable def update(self, observable): self.update_snapper()
class ProfiletoolMapTool(QgsMapTool): # Signals sig_clearMap = pyqtSignal() sig_createProfile = pyqtSignal() sig_changeCoord = pyqtSignal(QgsPointXY, str) def __init__(self, canvas, drawLineButton, showProfileButton): #buttonShowProf QgsMapTool.__init__(self, canvas) self.canvas = canvas self.cursor = QCursor(Qt.CrossCursor) # Red line self.rubberband = QgsRubberBand(self.canvas) self.rubberband.setWidth(3) self.rubberband.setColor(QColor(231, 28, 35)) # Buttons from main dialog self.drawLineButton = drawLineButton self.buttonShowProf = showProfileButton # Coordinates of drawn line points self.pointsToDraw = [] # Temporary save double clicks self.dblclktemp = None # Drawn line geometry self.drawnLine = None # Point markers on each end of the line self.markers = [] # Backup the last active Tool before the pofile tool became active self.savedTool = self.canvas.mapTool() def drawLine(self): # Emit signal that clears map and deletes profile self.sig_clearMap.emit() self.reset() self.canvas.setMapTool(self) # runs function self.activate() def activate(self): self.canvas.setCursor(self.cursor) def deactivate(self): self.canvas.setCursor(QCursor(Qt.OpenHandCursor)) self.pointsToDraw = [] # Stop pressing down button self.drawLineButton.setChecked(False) def reset(self): self.removeStueMarker() self.canvas.setMapTool(self.savedTool) self.rubberband.reset() self.pointsToDraw = [] self.dblclktemp = None self.drawnLine = None def canvasMoveEvent(self, event): if len(self.pointsToDraw) > 0: self.rubberband.reset() line = [self.pointsToDraw[0], event.mapPoint()] self.rubberband.setToGeometry(QgsGeometry.fromPolylineXY(line), None) def canvasReleaseEvent(self, event): mapPos = event.mapPoint() if mapPos == self.dblclktemp: self.dblclktemp = None return else: # Mark point with marker symbol self.drawStueMarker(mapPos) # Klick ist first point of line if len(self.pointsToDraw) == 0: self.rubberband.reset() self.pointsToDraw.append(mapPos) return # Klick is second point of line elif len(self.pointsToDraw) == 1: self.pointsToDraw.append(mapPos) self.removeStueMarker() self.dblclktemp = mapPos self.drawnLine = self.createDigiFeature(self.pointsToDraw) self.sig_changeCoord.emit(self.pointsToDraw[0], 'A') self.sig_changeCoord.emit(self.pointsToDraw[1], 'E') self.canvas.setMapTool(self.savedTool) # self.deactivate() def setCursor(self, cursor): self.cursor = cursor def updateLine(self, points): self.rubberband.setToGeometry(QgsGeometry.fromPolylineXY(points), None) self.drawnLine = self.createDigiFeature(points) self.drawStueMarker(points[0]) self.drawStueMarker(points[1]) def drawStueMarker(self, point): marker = QgsStueMarker(self.canvas) marker.setCenter(point) self.markers.append(marker) self.canvas.refresh() def removeStueMarker(self, position=-1): if position >= 0: marker = self.markers[position] self.canvas.scene().removeItem(marker) self.markers.pop(position) else: for marker in self.markers: self.canvas.scene().removeItem(marker) self.markers = [] self.canvas.refresh() @staticmethod def createDigiFeature(pnts): line = QgsGeometry.fromPolylineXY(pnts) qgFeat = QgsFeature() qgFeat.setGeometry(line) return qgFeat
class TaskingDockWidget(BASE, WIDGET): def __init__( self, parent=None, ): super().__init__(parent=parent) self.setupUi(self) self.rect = None self.prev_map_tool = None self.btnMapTool.setIcon(TASKING_ICON) self.btnMapTool.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.footprint = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self.footprint.setStrokeColor(PLANET_COLOR) self.footprint.setFillColor(QColor(204, 235, 239, 100)) self.footprint.setWidth(2) self.marker = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.marker.setIcon(QgsRubberBand.ICON_SVG) self.marker.setSvgIcon(SVG_ICON, QPoint(-15, -30)) self.map_tool = AOICaptureMapTool(iface.mapCanvas()) self.map_tool.aoi_captured.connect(self.aoi_captured) self.btnMapTool.toggled.connect(self._set_map_tool) iface.mapCanvas().mapToolSet.connect(self._map_tool_set) self.textBrowserPoint.setHtml("No point selected") self.btnOpenDashboard.setEnabled(False) self.btnOpenDashboard.clicked.connect(self._open_tasking_dashboard) self.btnCancel.clicked.connect(self.cancel_clicked) self.visibilityChanged.connect(self.visibility_changed) self.textBrowserPoint.viewport().setAutoFillBackground(False) def aoi_captured(self, rect, pt): self.pt = pt self.rect = rect self.footprint.setToGeometry(QgsGeometry.fromRect(rect)) transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance().crs(), QgsProject.instance(), ) transformed = transform.transform(pt) self.marker.setToGeometry(QgsGeometry.fromPointXY(transformed)) self._set_map_tool(False) text = f""" <p><b>Selected Point Coordinates</b></p> <p align="center">Latitude : {pt.x():.4f}</p> <p align="center">Longitude : {pt.y():.4f}</p> """ self.textBrowserPoint.setHtml(text) self.btnCancel.setEnabled(True) self.btnOpenDashboard.setEnabled(True) def cancel_clicked(self): self.footprint.reset(QgsWkbTypes.PolygonGeometry) self.marker.reset(QgsWkbTypes.PointGeometry) self.btnOpenDashboard.setEnabled(False) self.textBrowserPoint.setHtml("") self.btnCancel.setEnabled(False) self._set_map_tool(False) def _set_map_tool(self, checked): if checked: self.prev_map_tool = iface.mapCanvas().mapTool() iface.mapCanvas().setMapTool(self.map_tool) else: if self.prev_map_tool is not None: iface.mapCanvas().setMapTool(self.prev_map_tool) def _map_tool_set(self, new, old): if new != self.map_tool: self.btnMapTool.blockSignals(True) self.btnMapTool.setChecked(False) self.btnMapTool.blockSignals(False) def visibility_changed(self, visible): if not visible: self.cancel_clicked() def _open_tasking_dashboard(self): dialog = WarningDialog(self.pt) dialog.exec()
class GeorefRasterBy2PointsMapTool(QgsMapToolEmitPoint): def __init__(self, iface): self.iface = iface self.canvas = iface.mapCanvas() QgsMapToolEmitPoint.__init__(self, self.canvas) self.rasterShadow = RasterShadowMapCanvasItem(self.canvas) self.firstPoint = None self.rubberBandOrigin = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry) self.rubberBandOrigin.setColor(Qt.red) self.rubberBandOrigin.setIcon(QgsRubberBand.ICON_CIRCLE) self.rubberBandOrigin.setIconSize(7) self.rubberBandOrigin.setWidth(2) self.rubberBandDisplacement = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.rubberBandDisplacement.setColor(Qt.red) self.rubberBandDisplacement.setWidth(1) self.rubberBandExtent = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.rubberBandExtent.setColor(Qt.red) self.rubberBandExtent.setWidth(2) self.isLayerVisible = True self.reset() def setLayer(self, layer): self.layer = layer def reset(self): self.startPoint = self.endPoint = self.firstPoint = None self.isEmittingPoint = False self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry) self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rasterShadow.reset() self.layer = None def deactivate(self): QgsMapToolEmitPoint.deactivate(self) self.reset() def canvasPressEvent(self, e): if self.firstPoint is None: self.startPoint = self.toMapCoordinates(e.pos()) self.endPoint = self.startPoint self.isEmittingPoint = True self.originalCenter = self.layer.center # this tool do the displacement itself TODO update so it is done by # transformed coordinates + new center) self.originalCornerPoints = \ self.layer.transformedCornerCoordinates( *self.layer.transformParameters()) self.isLayerVisible = isLayerVisible(self.iface, self.layer) setLayerVisible(self.iface, self.layer, False) self.showDisplacement(self.startPoint, self.endPoint) self.layer.history.append({ "action": "2pointsA", "center": self.layer.center }) else: self.startPoint = self.toMapCoordinates(e.pos()) self.endPoint = self.startPoint self.startY = e.pos().y() self.endY = self.startY self.isEmittingPoint = True self.height = self.canvas.height() self.isLayerVisible = isLayerVisible(self.iface, self.layer) setLayerVisible(self.iface, self.layer, False) rotation = self.computeRotation() xScale = yScale = self.computeScale() self.showRotationScale(rotation, xScale, yScale) self.layer.history.append({ "action": "2pointsB", "center": self.layer.center, "xScale": self.layer.xScale, "yScale": self.layer.yScale, "rotation": self.layer.rotation }) def canvasReleaseEvent(self, e): self.isEmittingPoint = False self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rasterShadow.reset() if self.firstPoint is None: x = (self.originalCenter.x() + self.endPoint.x() - self.startPoint.x()) y = (self.originalCenter.y() + self.endPoint.y() - self.startPoint.y()) self.layer.setCenter(QgsPointXY(x, y)) self.firstPoint = self.endPoint setLayerVisible(self.iface, self.layer, self.isLayerVisible) self.layer.repaint() self.layer.commitTransformParameters() else: rotation = self.computeRotation() xScale = yScale = self.computeScale() self.layer.moveCenterFromPointRotate(self.firstPoint, rotation, xScale, yScale) self.layer.setRotation(self.layer.rotation + rotation) self.layer.setScale(self.layer.xScale * xScale, self.layer.yScale * yScale) setLayerVisible(self.iface, self.layer, self.isLayerVisible) self.layer.repaint() self.layer.commitTransformParameters() self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry) self.rasterShadow.reset() self.firstPoint = None self.startPoint = self.endPoint = None def canvasMoveEvent(self, e): if not self.isEmittingPoint: return self.endPoint = self.toMapCoordinates(e.pos()) if self.firstPoint is None: self.showDisplacement(self.startPoint, self.endPoint) else: self.endY = e.pos().y() rotation = self.computeRotation() xScale = yScale = self.computeScale() self.showRotationScale(rotation, xScale, yScale) def computeRotation(self): # The angle is the difference between angle # horizontal/endPoint-firstPoint and horizontal/startPoint-firstPoint. dX0 = self.startPoint.x() - self.firstPoint.x() dY0 = self.startPoint.y() - self.firstPoint.y() dX = self.endPoint.x() - self.firstPoint.x() dY = self.endPoint.y() - self.firstPoint.y() return math.degrees(math.atan2(-dY, dX) - math.atan2(-dY0, dX0)) def computeScale(self): # The scale is the ratio between endPoint-firstPoint and # startPoint-firstPoint. dX0 = self.startPoint.x() - self.firstPoint.x() dY0 = self.startPoint.y() - self.firstPoint.y() dX = self.endPoint.x() - self.firstPoint.x() dY = self.endPoint.y() - self.firstPoint.y() return math.sqrt((dX * dX + dY * dY) / (dX0 * dX0 + dY0 * dY0)) def showRotationScale(self, rotation, xScale, yScale): center, _, _, _ = self.layer.transformParameters() # newRotation = rotation + originalRotation cornerPoints = self.layer.transformedCornerCoordinatesFromPoint( self.firstPoint, rotation, xScale, yScale) self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) for point in cornerPoints: self.rubberBandExtent.addPoint(point, False) self.rubberBandExtent.addPoint(cornerPoints[0], True) self.rubberBandExtent.show() # Calculate the displacement of the center due to the rotation from # another point. newCenterDX = (cornerPoints[0].x() + cornerPoints[2].x()) / 2 - center.x() newCenterDY = (cornerPoints[0].y() + cornerPoints[2].y()) / 2 - center.y() self.rasterShadow.reset(self.layer) self.rasterShadow.setDeltaDisplacement(newCenterDX, newCenterDY, False) self.rasterShadow.setDeltaScale(xScale, yScale, False) self.rasterShadow.setDeltaRotation(rotation, True) self.rasterShadow.show() self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) point0 = QgsPointXY(self.startPoint.x(), self.startPoint.y()) point1 = QgsPointXY(self.firstPoint.x(), self.firstPoint.y()) point2 = QgsPointXY(self.endPoint.x(), self.endPoint.y()) self.rubberBandDisplacement.addPoint(point0, False) self.rubberBandDisplacement.addPoint(point1, False) self.rubberBandDisplacement.addPoint(point2, True) # true to update canvas self.rubberBandDisplacement.show() def showDisplacement(self, startPoint, endPoint): self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry) self.rubberBandOrigin.addPoint(endPoint, True) self.rubberBandOrigin.show() self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry) point1 = QgsPointXY(startPoint.x(), startPoint.y()) point2 = QgsPointXY(endPoint.x(), endPoint.y()) self.rubberBandDisplacement.addPoint(point1, False) self.rubberBandDisplacement.addPoint(point2, True) # true to update canvas self.rubberBandDisplacement.show() self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry) for point in self.originalCornerPoints: self._addDisplacementToPoint(self.rubberBandExtent, point, False) # for closing self._addDisplacementToPoint(self.rubberBandExtent, self.originalCornerPoints[0], True) self.rubberBandExtent.show() self.rasterShadow.reset(self.layer) self.rasterShadow.setDeltaDisplacement( self.endPoint.x() - self.startPoint.x(), self.endPoint.y() - self.startPoint.y(), True) self.rasterShadow.show() def _addDisplacementToPoint(self, rubberBand, point, doUpdate): x = point.x() + self.endPoint.x() - self.startPoint.x() y = point.y() + self.endPoint.y() - self.startPoint.y() self.rubberBandExtent.addPoint(QgsPointXY(x, y), doUpdate)
class RectangleMapTool(QgsMapToolEmitPoint): boxCreated = pyqtSignal(QgsRectangle) def __init__(self, canvas): self.canvas = canvas QgsMapToolEmitPoint.__init__(self, self.canvas) self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes().GeometryType(2)) self.rubberBand.setColor(Qt.red) self.rubberBand.setBrushStyle(Qt.Dense6Pattern) self.rubberBand.setWidth(1) self.reset() def reset(self): self.startPoint = self.endPoint = None self.isEmittingPoint = False self.rubberBand.reset(QgsWkbTypes().GeometryType(2)) def canvasPressEvent(self, e): self.startPoint = self.toMapCoordinates(e.pos()) self.endPoint = self.startPoint self.isEmittingPoint = True self.showRect(self.startPoint, self.endPoint) def canvasReleaseEvent(self, e): self.isEmittingPoint = False r = self.rectangle() if r is not None: self.boxCreated.emit(r) def canvasMoveEvent(self, e): if not self.isEmittingPoint: return self.endPoint = self.toMapCoordinates(e.pos()) self.showRect(self.startPoint, self.endPoint) def showRect(self, startPoint, endPoint): self.rubberBand.reset(QgsWkbTypes().GeometryType(2)) if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y(): return point1 = QgsPointXY(startPoint.x(), startPoint.y()) point2 = QgsPointXY(startPoint.x(), endPoint.y()) point3 = QgsPointXY(endPoint.x(), endPoint.y()) point4 = QgsPointXY(endPoint.x(), startPoint.y()) self.rubberBand.addPoint(point1, False) self.rubberBand.addPoint(point2, False) self.rubberBand.addPoint(point3, False) self.rubberBand.addPoint(point4, True) # true to update canvas self.rubberBand.show() def rectangle(self): if self.startPoint is None or self.endPoint is None: return None elif self.startPoint.x() == self.endPoint.x() or self.startPoint.y( ) == self.endPoint.y(): return None self.rubberBand.hide() srsCrs = self.canvas.mapSettings().destinationCrs() dstCrs = QgsCoordinateReferenceSystem( 4326, QgsCoordinateReferenceSystem.EpsgCrsId) coordinateTransformer = QgsCoordinateTransform(srsCrs, dstCrs, QgsProject.instance()) rect = coordinateTransformer.transform( QgsRectangle(self.startPoint, self.endPoint)) return rect
class RectangleMapTool(QgsMapToolEmitPoint): """ Map tool that lets the user define the analysis extents. """ rectangle_created = pyqtSignal() deactivated = pyqtSignal() def __init__(self, canvas): """Constructor for the map tool. :param canvas: Canvas that tool will interact with. :type canvas: QgsMapCanvas """ self.canvas = canvas self.start_point = None self.end_point = None self.is_emitting_point = False QgsMapToolEmitPoint.__init__(self, self.canvas) self.rubber_band = QgsRubberBand(self.canvas, geometryType=QGis.Line) self.rubber_band.setColor(QColor(0, 0, 240, 100)) # Needs QGIS 2.6 # self.rubber_band.setFillColor(QColor(0, 0, 240, 0)) self.rubber_band.setWidth(1) self.reset() def reset(self): """ Clear the rubber band for the analysis extents. """ self.start_point = self.end_point = None self.is_emitting_point = False self.rubber_band.reset(QGis.Polygon) def canvasPressEvent(self, e): """ Handle canvas press events so we know when user is capturing the rect. :param e: A Qt event object. :type: QEvent """ self.start_point = self.toMapCoordinates(e.pos()) self.end_point = self.start_point self.is_emitting_point = True self.show_rectangle(self.start_point, self.end_point) def canvasReleaseEvent(self, e): """ Handle canvas release events has finished capturing e :param e: A Qt event object. :type: QEvent """ _ = e self.is_emitting_point = False self.rectangle_created.emit() def canvasMoveEvent(self, e): """ :param e: :return: """ if not self.is_emitting_point: return self.end_point = self.toMapCoordinates(e.pos()) self.show_rectangle(self.start_point, self.end_point) def show_rectangle(self, start_point, end_point): """ Show the rectangle on the canvas. :param start_point: QGIS Point object representing the origin ( top left). :type start_point: QgsPoint :param end_point: QGIS Point object representing the contra-origin ( bottom right). :type end_point: QgsPoint :return: """ self.rubber_band.reset(QGis.Polygon) if (start_point.x() == end_point.x() or start_point.y() == end_point.y()): return point1 = start_point point2 = QgsPoint(end_point.x(), start_point.y()) point3 = end_point point4 = QgsPoint(start_point.x(), end_point.y()) update_canvas = False self.rubber_band.addPoint(point1, update_canvas) self.rubber_band.addPoint(point2, update_canvas) self.rubber_band.addPoint(point3, update_canvas) self.rubber_band.addPoint(point4, update_canvas) # noinspection PyArgumentEqualDefault # no False so canvas will update # close the polygon otherwise it shows as a filled rect self.rubber_band.addPoint(point1) self.rubber_band.show() def rectangle(self): """ Accessor for the rectangle. :return: A rectangle showing the designed extent. :rtype: QgsRectangle """ if self.start_point is None or self.end_point is None: return None elif self.start_point.x() == self.end_point.x() or \ self.start_point.y() == self.end_point.y(): return None return QgsRectangle(self.start_point, self.end_point) def set_rectangle(self, rectangle): """ Set the rectangle for the selection. :param rectangle: :return: """ if rectangle == self.rectangle(): return False if rectangle is None: self.reset() else: self.start_point = QgsPoint( rectangle.xMinimum(), rectangle.yMinimum()) self.end_point = QgsPoint( rectangle.xMaximum(), rectangle.yMaximum()) self.show_rectangle(self.start_point, self.end_point) return True def deactivate(self): """ Disable the tool. """ QgsMapTool.deactivate(self) self.deactivated.emit()
class VideoWidget(QVideoWidget): def __init__(self, parent=None): ''' Constructor ''' super(VideoWidget, self).__init__(parent) self.surface = VideoWidgetSurface(self) self.Tracking_RubberBand = QRubberBand(QRubberBand.Rectangle, self) self.Censure_RubberBand = QRubberBand(QRubberBand.Rectangle, self) pal = QPalette() pal.setBrush(QPalette.Highlight, QBrush(QColor(Qt.blue))) self.Tracking_RubberBand.setPalette(pal) pal = QPalette() pal.setBrush(QPalette.Highlight, QBrush(QColor(Qt.black))) self.Censure_RubberBand.setPalette(pal) self.var_currentMouseMoveEvent = None self._interaction = InteractionState() self._filterSatate = FilterState() self.setUpdatesEnabled(True) self.snapped = False self.zoomed = False self._isinit = False self.gt = None self.drawCesure = [] self.poly_coordinates, self.drawPtPos, self.drawLines, self.drawRuler, self.drawPolygon = [], [], [], [], [] self.poly_RubberBand = QgsRubberBand(iface.mapCanvas(), True) # Polygon type # set rubber band style color = QColor(176, 255, 128) self.poly_RubberBand.setColor(color) color.setAlpha(190) self.poly_RubberBand.setStrokeColor(color) self.poly_RubberBand.setWidth(3) self.parent = parent.parent() self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.setAttribute(Qt.WA_NoSystemBackground) self.setAttribute(Qt.WA_PaintOnScreen) self.setAttribute(Qt.WA_OpaquePaintEvent) self.setAttribute(Qt.WA_DeleteOnClose) palette = self.palette() palette.setColor(QPalette.Background, Qt.black) self.setPalette(palette) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.offset, self.origin, self.pressPos, self.dragPos = QPoint( ), QPoint(), QPoint(), QPoint() self.tapTimer = QBasicTimer() self.zoomPixmap, self.maskPixmap = QPixmap(), QPixmap() def removeLastLine(self): ''' Remove Last Line Objects ''' if len(self.drawLines) > 0: for pt in range(len(self.drawLines) - 1, -1, -1): del self.drawLines[pt] try: if self.drawLines[pt - 1][0] is None: break except Exception: None self.UpdateSurface() AddDrawLineOnMap(self.drawLines) return def removeLastSegmentLine(self): ''' Remove Last Segment Line Objects ''' if len(self.drawLines) > 0: del self.drawLines[-1] self.UpdateSurface() AddDrawLineOnMap(self.drawLines) return def removeAllLines(self): ''' Resets Line List ''' self.drawLines = [] self.UpdateSurface() # Clear all Layer RemoveAllDrawLineOnMap() def ResetDrawRuler(self): ''' Resets Ruler List ''' self.drawRuler = [] def removeAllCensure(self): ''' Remove All Censure Objects ''' self.drawCesure = [] def removeLastCensured(self): ''' Remove Last Censure Objects ''' if len(self.drawCesure) > 0: del self.drawCesure[-1] def removeLastPoint(self): ''' Remove All Point Drawer Objects ''' if len(self.drawPtPos) > 0: del self.drawPtPos[-1] self.UpdateSurface() RemoveLastDrawPointOnMap() return def removeAllPoint(self): ''' Remove All Point Drawer Objects ''' self.drawPtPos = [] self.UpdateSurface() # Clear all Layer RemoveAllDrawPointOnMap() return def removeAllPolygon(self): ''' Remove All Polygon Drawer Objects ''' self.drawPolygon = [] self.UpdateSurface() # Clear all Layer RemoveAllDrawPolygonOnMap() def removeLastPolygon(self): ''' Remove Last Polygon Drawer Objects ''' if len(self.drawPolygon) > 0: for pt in range(len(self.drawPolygon) - 1, -1, -1): del self.drawPolygon[pt] try: if self.drawPolygon[pt - 1][0] is None: break except Exception: None self.UpdateSurface() # remove last index layer RemoveLastDrawPolygonOnMap() def currentMouseMoveEvent(self, event): self.var_currentMouseMoveEvent = event def keyPressEvent(self, event): ''' Exit fullscreen ''' if event.key() == Qt.Key_Escape and self.isFullScreen(): self.setFullScreen(False) event.accept() elif event.key() == Qt.Key_Enter and event.modifiers() & Qt.Key_Alt: self.setFullScreen(not self.isFullScreen()) event.accept() else: super(VideoWidget, self).keyPressEvent(event) def mouseDoubleClickEvent(self, event): """ :type event: QMouseEvent :param event: :return: """ if GetImageHeight() == 0: return if (not vut.IsPointOnScreen(event.x(), event.y(), self.surface)): return if self.gt is not None and self._interaction.lineDrawer: self.drawLines.append([None, None, None]) self.UpdateSurface() return if self.gt is not None and self._interaction.ruler: self.drawRuler.append([None, None, None]) self.UpdateSurface() return if self.gt is not None and self._interaction.polygonDrawer: self.drawPolygon.append([None, None, None]) AddDrawPolygonOnMap(self.poly_coordinates) # Empty RubberBand for _ in range(self.poly_RubberBand.numberOfVertices()): self.poly_RubberBand.removeLastPoint() # Empty List self.poly_coordinates = [] self.UpdateSurface() return self.setFullScreen(not self.isFullScreen()) event.accept() def videoSurface(self): ''' Return video Surface ''' return self.surface def UpdateSurface(self): ''' Update Video Surface ''' self.surface.widget.update() def sizeHint(self): ''' This property holds the recommended size for the widget ''' return self.surface.surfaceFormat().sizeHint() def GetCurrentFrame(self): ''' Return current frame QImage ''' return self.surface.image def SetInvertColor(self, value): ''' Set Invert color filter ''' self._filterSatate.invertColorFilter = value def SetObjectTracking(self, value): ''' Set Object Tracking ''' self._interaction.objectTracking = value def SetRuler(self, value): ''' Set Ruler ''' self._interaction.ruler = value def SetHandDraw(self, value): ''' Set Hand Draw ''' self._interaction.HandDraw = value def SetCensure(self, value): ''' Set Censure Video Parts ''' self._interaction.censure = value def SetGray(self, value): ''' Set gray scale ''' self._filterSatate.grayColorFilter = value def SetMirrorH(self, value): ''' Set Horizontal Mirror ''' self._filterSatate.MirroredHFilter = value def SetEdgeDetection(self, value): ''' Set Canny Edge filter ''' self._filterSatate.edgeDetectionFilter = value def SetAutoContrastFilter(self, value): ''' Set Automatic Contrast filter ''' self._filterSatate.contrastFilter = value def SetMonoFilter(self, value): ''' Set mono filter ''' self._filterSatate.monoFilter = value def RestoreFilters(self): ''' Remove and restore all video filters ''' self._filterSatate.clear() def RestoreDrawer(self): ''' Remove and restore all Drawer Options ''' self._interaction.clear() def paintEvent(self, event): ''' Paint Event ''' self.gt = GetGCPGeoTransform() self.painter = QPainter(self) self.painter.setRenderHint(QPainter.HighQualityAntialiasing) if (self.surface.isActive()): videoRect = self.surface.videoRect() if not videoRect.contains(event.rect()): region = event.region() region.subtracted(QRegion(videoRect)) brush = self.palette().window() for rect in region.rects(): self.painter.fillRect(rect, brush) try: self.painter = self.surface.paint(self.painter) except Exception: None else: self.painter.fillRect(event.rect(), self.palette().window()) try: SetImageSize(self.surface.currentFrame.width(), self.surface.currentFrame.height()) except Exception: None # Draw On Video draw.drawOnVideo(self.drawPtPos, self.drawLines, self.drawPolygon, self.drawRuler, self.drawCesure, self.painter, self.surface, self.gt) # Magnifier Glass if self.zoomed and self._interaction.magnifier: draw.drawMagnifierOnVideo(self.width(), self.height(), self.maskPixmap, self.dragPos, self.zoomPixmap, self.surface, self.painter, self.offset) self.painter.end() return def resizeEvent(self, event): """ :type event: QMouseEvent :param event: :return: """ QWidget.resizeEvent(self, event) self.zoomed = False self.surface.updateVideoRect() def mouseMoveEvent(self, event): """ :type event: QMouseEvent :param event: :return: """ if GetImageHeight() == 0: return # check if the point is on picture (not in black borders) if (not vut.IsPointOnScreen(event.x(), event.y(), self.surface)): return if self._interaction.pointDrawer or self._interaction.polygonDrawer or self._interaction.lineDrawer or self._interaction.ruler: self.setCursor(QCursor(Qt.CrossCursor)) # Cursor Coordinates if self.gt is not None: Longitude, Latitude, Altitude = vut.GetPointCommonCoords( event, self.surface) txt = "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>" txt += "<span style='font-size:9pt; font-weight:normal;'>" + \ ("%.3f" % Longitude) + "</span>" txt += "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>" txt += "<span style='font-size:9pt; font-weight:normal;'>" + \ ("%.3f" % Latitude) + "</span>" if hasElevationModel(): txt += "<span style='font-size:10pt; font-weight:bold;'> Alt :</span>" txt += "<span style='font-size:9pt; font-weight:normal;'>" + \ ("%.0f" % Altitude) + "</span>" else: txt += "<span style='font-size:10pt; font-weight:bold;'> Alt :</span>" txt += "<span style='font-size:9pt; font-weight:normal;'>-</span>" self.parent.lb_cursor_coord.setText(txt) else: self.parent.lb_cursor_coord.setText( "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>" + "<span style='font-size:9pt; font-weight:normal;'>-</span>" + "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>" + "<span style='font-size:9pt; font-weight:normal;'>-</span>" + "<span style='font-size:10pt; font-weight:bold;'> Alt :</span>" + "<span style='font-size:9pt; font-weight:normal;'>-</span>") if not event.buttons(): return if not self.Tracking_RubberBand.isHidden(): self.Tracking_RubberBand.setGeometry( QRect(self.origin, event.pos()).normalized()) if not self.Censure_RubberBand.isHidden(): self.Censure_RubberBand.setGeometry( QRect(self.origin, event.pos()).normalized()) if not self.zoomed: delta = event.pos() - self.pressPos if not self.snapped: self.pressPos = event.pos() self.pan(delta) self.tapTimer.stop() return else: threshold = 10 self.snapped &= delta.x() < threshold self.snapped &= delta.y() < threshold self.snapped &= delta.x() > -threshold self.snapped &= delta.y() > -threshold else: self.dragPos = event.pos() self.surface.updateVideoRect() def pan(self, delta): """ Pan Action (Magnifier method)""" self.offset += delta self.surface.updateVideoRect() def timerEvent(self, _): """ Time Event (Magnifier method)""" if not self.zoomed: self.activateMagnifier() self.surface.updateVideoRect() def mousePressEvent(self, event): """ :type event: QMouseEvent :param event: :return: """ if GetImageHeight() == 0: return if event.button() == Qt.LeftButton: self.snapped = True self.pressPos = self.dragPos = event.pos() self.tapTimer.stop() self.tapTimer.start(100, self) if (not vut.IsPointOnScreen(event.x(), event.y(), self.surface)): self.UpdateSurface() return # point drawer if self.gt is not None and self._interaction.pointDrawer: Longitude, Latitude, Altitude = vut.GetPointCommonCoords( event, self.surface) pointIndex = len(self.drawPtPos) + 1 AddDrawPointOnMap(pointIndex, Longitude, Latitude, Altitude) self.drawPtPos.append([Longitude, Latitude, Altitude]) # polygon drawer if self.gt is not None and self._interaction.polygonDrawer: Longitude, Latitude, Altitude = vut.GetPointCommonCoords( event, self.surface) self.poly_RubberBand.addPoint(QgsPointXY(Longitude, Latitude)) self.poly_coordinates.extend(QgsPointXY(Longitude, Latitude)) self.drawPolygon.append([Longitude, Latitude, Altitude]) # line drawer if self.gt is not None and self._interaction.lineDrawer: Longitude, Latitude, Altitude = vut.GetPointCommonCoords( event, self.surface) self.drawLines.append([Longitude, Latitude, Altitude]) AddDrawLineOnMap(self.drawLines) if self._interaction.objectTracking: self.origin = event.pos() self.Tracking_RubberBand.setGeometry( QRect(self.origin, QSize())) self.Tracking_RubberBand.show() if self._interaction.censure: self.origin = event.pos() self.Censure_RubberBand.setGeometry(QRect( self.origin, QSize())) self.Censure_RubberBand.show() # Ruler drawer if self.gt is not None and self._interaction.ruler: Longitude, Latitude, Altitude = vut.GetPointCommonCoords( event, self.surface) self.drawRuler.append([Longitude, Latitude, Altitude]) # if not called, the paint event is not triggered. self.UpdateSurface() def activateMagnifier(self): """ Activate Magnifier Glass """ self.zoomed = True self.tapTimer.stop() self.surface.updateVideoRect() def SetMagnifier(self, value): """ Set Magnifier Glass """ self._interaction.magnifier = value def SetPointDrawer(self, value): """ Set Point Drawer """ self._interaction.pointDrawer = value def SetLineDrawer(self, value): """ Set Line Drawer """ self._interaction.lineDrawer = value def SetPolygonDrawer(self, value): """ Set Polygon Drawer """ self._interaction.polygonDrawer = value def mouseReleaseEvent(self, _): """ :type event: QMouseEvent :param event: :return: """ if self._interaction.censure: geom = self.Tracking_RubberBand.geometry() self.Censure_RubberBand.hide() self.drawCesure.append([geom]) if self._interaction.objectTracking: geom = self.Tracking_RubberBand.geometry() bbox = (geom.x(), geom.y(), geom.width(), geom.height()) frame = convertQImageToMat(self.GetCurrentFrame()) self.Tracking_RubberBand.hide() self.tracker = cv2.TrackerBoosting_create() self.tracker.clear() ok = self.tracker.init(frame, bbox) if ok: self._isinit = True else: self._isinit = False def leaveEvent(self, _): self.parent.lb_cursor_coord.setText("") self.setCursor(QCursor(Qt.ArrowCursor))
class BaseTool(QgsMapToolEmitPoint): __metaclass__ = ABCMeta apply = pyqtSignal(dict) def _apply(self): self.collect_data() if not self._data else None self._data[k.geometry] = { k.line: self.line_band.asGeometry(), k.polygon: self.poly_band.asGeometry() } self.apply.emit(self._data) self.reset() def __init__(self, canvas): self.canvas = canvas QgsMapToolEmitPoint.__init__(self, self.canvas) self.replaced_tool = canvas.mapTool() self.points = [] self.done = True self._line_band = None self._poly_band = None self._markers = [] self._info = None self._line_color = Qt.black self._poly_color = Qt.lightGray self._data = {} @property def n_points(self): return len(self.points) @property def has_points(self): return self.n_points > 1 @property def info(self): if not self._info: self._info = QLabel(parent=self.canvas) font = self._info.font() font.setPointSize(10) font.setFamily('Courier New') self._info.setFont(font) self._info.setStyleSheet('color: black') return self._info @property def line_band(self): if self._line_band is None: self._line_band = QgsRubberBand(self.canvas) self._line_band.setColor(self._line_color) self._line_band.setOpacity(1) self._line_band.setWidth(1) self._line_band.reset(QgsWkbTypes.LineGeometry) return self._line_band @property def poly_band(self): if self._poly_band is None: self._poly_band = QgsRubberBand(self.canvas) self._poly_band.setColor(self._poly_color) self._poly_band.setOpacity(0.1) self._poly_band.setWidth(0.1) self._poly_band.reset(QgsWkbTypes.PolygonGeometry) return self._poly_band @property def markers(self): if not self._markers: line_points = self.line_points line_points = line_points if line_points else self.points for point in line_points: index = line_points.index(point) is_extreme_point = index == 0 or index == len(line_points) - 1 marker = QgsVertexMarker(self.canvas) marker.setColor(self._line_color) marker.setFillColor( self._poly_color if not is_extreme_point else Qt.red) marker.setOpacity(1) marker.setPenWidth(1) marker.setIconSize(5) marker.setIconType(QgsVertexMarker.ICON_CIRCLE) marker.setCenter(point) self._markers.append(marker) return self._markers @property @abstractmethod def line_points(self): """точки для отрисовки линии""" @property @abstractmethod def poly_points(self): """точки для отрисовки фона""" def draw(self): if not self.has_points: return self.reset() line_points = self.line_points for point in line_points: is_last_point = line_points.index(point) == len(line_points) - 1 self.line_band.addPoint(point, doUpdate=is_last_point) poly_points = self.poly_points for point in poly_points: is_last_point = poly_points.index(point) == len(poly_points) - 1 self.poly_band.addPoint(point, doUpdate=is_last_point) self.show() @abstractmethod def collect_data(self): """сбор данных для отправки клиенту""" @abstractmethod def collect_info(self): """ подготовка данных к отображению рядом с курсором мыши""" def show_info(self): self.info.hide() self.info.setText(self.collect_info()) tl = self.canvas.mapToGlobal(self.canvas.rect().topLeft()) self.info.move(QCursor.pos().x() + 15 - tl.x(), QCursor.pos().y() - tl.y()) self.info.show() def reset(self): for marker in self.markers: marker.hide() self.markers.clear() self.line_band.reset(QgsWkbTypes.LineGeometry) self.poly_band.reset(QgsWkbTypes.PolygonGeometry) def show(self): for marker in self.markers: marker.show() self.line_band.show() self.poly_band.show() self.show_info() def set_done(self, clear): if clear: self.reset() else: self._apply() self.done = True self.points = [] self.canvas.setMapTool(self.replaced_tool) self.canvas.refresh() self.info.hide() self._info = None def canvasPressEvent(self, e): if e.button() == Qt.RightButton: self.set_done(clear=True) if e.button() == Qt.LeftButton: self.done = False def canvasReleaseEvent(self, e): if self.done or e.button() != Qt.LeftButton: return p = self.toMapCoordinates(e.pos()) self.points.append(p) self.done = False self.draw() def canvasMoveEvent(self, e): if self.done: return p = self.toMapCoordinates(e.pos()) self.points.pop() if self.has_points else None self.points.append(p) self.done = False self.draw() def canvasDoubleClickEvent(self, e): if not self.done: self.set_done(clear=False) def keyPressEvent(self, e): if e.key() == Qt.Key_Escape: self.set_done(clear=True) if e.key() in (Qt.Key_Return, Qt.Key_Enter): self.set_done(clear=False) def deactivate(self): if not self.done: self.set_done(clear=True) super(BaseTool, self).deactivate()