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) def setCursorStyle(self): cursor = QCursor() cursor.setShape(self.cursorStyle) self.setCursor(cursor) def activate(self): self.caller.setChecked(True) self.setCursorStyle() def deactivate(self): self.canvas.scene().removeItem(self.rb) self.tool_deactivated.emit() self.caller.setChecked(False) QgsMapTool.deactivate(self) def setGeometry(self, geo): self.rb.setToGeometry(geo) def canvasReleaseEvent(self, mouseEvent): if mouseEvent.button() == Qt.LeftButton: if not self.active: self.active = True self.geometry_changed.emit(QgsGeometry(), False) self.rb.reset(QgsWkbTypes.LineGeometry) self.rb.addPoint(mouseEvent.mapPoint()) if self.rb.numberOfVertices() > 1: self.geometry_changed.emit(self.rb.asGeometry(), False) elif mouseEvent.button() == Qt.RightButton: if self.rb.numberOfVertices() > 2: self.active = False self.rb.removeLastPoint() geo = self.rb.asGeometry() self.geometry_changed.emit(geo, True) else: self.rb.reset(QgsWkbTypes.LineGeometry) def canvasMoveEvent(self, mouseEvent): if self.rb.numberOfVertices() > 1 and self.active: self.rb.removeLastPoint() self.rb.addPoint(mouseEvent.mapPoint()) pass
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 self.center=None # get selection color selcolor =self.canvas.selectionColor() mycolor = QColor(selcolor.red(), selcolor.green(), selcolor.blue(), 40) self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.rb.setStrokeColor(QColor(255, 0, 0, 40)) self.rb.setFillColor(mycolor) self.rb.setLineStyle(Qt.PenStyle(Qt.SolidLine)) self.rb.setWidth(2) def setCursorStyle(self): cursor = QCursor() cursor.setShape(self.cursorStyle) self.setCursor(cursor) def activate(self): self.caller.setChecked(True) self.setCursorStyle() def deactivate(self): self.canvas.scene().removeItem(self.rb) self.tool_deactivated.emit() self.caller.setChecked(False) QgsMapTool.deactivate(self) def setGeometry(self,geo): self.rb.setToGeometry(geo) def canvasReleaseEvent(self, mouseevent): if mouseevent.button() == Qt.LeftButton: self.active = False self.geometry_changed.emit(self.rb.asGeometry(),True) pass def canvasMoveEvent(self, mouseEvent): if self.active: cp = self.toMapCoordinates(mouseEvent.pos()) rec = QgsRectangle(self.center, cp) self.rb.setToGeometry(QgsGeometry.fromRect(rec)) self.geometry_changed.emit(self.rb.asGeometry(),True) pass 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
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()
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()
class QgsMapToolSelectPolygon(QgsMapTool): def __init__(self, canvas): QgsMapTool.__init__(self, canvas) self.mRubberBand = None self.mCursor = Qt.ArrowCursor self.mFillColor = QColor(254, 178, 76, 63) self.mBorderColour = QColor(254, 58, 29, 100) self.mCanvas = canvas def canvasPressEvent(self, e): if (self.mRubberBand == None): self.mRubberBand = QgsRubberBand(self.mCanvas, QGis.Polygon) self.mRubberBand.setFillColor(self.mFillColor) self.mRubberBand.setBorderColor(self.mBorderColour) if (e.button() == Qt.LeftButton): self.mRubberBand.addPoint(self.toMapCoordinates(e.pos())) else: if (self.mRubberBand.numberOfVertices() > 2): polygonGeom = self.mRubberBand.asGeometry() # QgsMapToolSelectUtils.setSelectFeatures( self.mCanvas, polygonGeom, e ) QgsMapToolSelectUtils.setSelectFeatures1( self.mCanvas, polygonGeom, e) self.mRubberBand.reset(QGis.Polygon) self.mRubberBand = None def canvasMoveEvent(self, e): if (self.mRubberBand == None): return if (self.mRubberBand.numberOfVertices() > 0): self.mRubberBand.removeLastPoint(0) self.mRubberBand.addPoint(self.toMapCoordinates(e.pos()))
class DrawPolygonMapTool(QgsMapTool): polygonSelected = pyqtSignal(object) def __init__(self, canvas): QgsMapTool.__init__(self, canvas) self.canvas = canvas self.extent = None self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.rubberBand.setFillColor(RB_FILL) self.rubberBand.setStrokeColor(RB_STROKE) self.rubberBand.setWidth(1) self.vertex_count = 1 # two points are dropped initially def canvasReleaseEvent(self, event): if event.button() == Qt.RightButton: if self.rubberBand is None: return # TODO: validate geom before firing signal self.extent.removeDuplicateNodes() self.polygonSelected.emit(self.extent) self.rubberBand.reset(QgsWkbTypes.PolygonGeometry) del self.rubberBand self.rubberBand = None self.vertex_count = 1 # two points are dropped initially return elif event.button() == Qt.LeftButton: if self.rubberBand is None: self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.rubberBand.setFillColor(RB_FILL) self.rubberBand.setStrokeColor(RB_STROKE) self.rubberBand.setWidth(1) self.rubberBand.addPoint(event.mapPoint()) self.extent = self.rubberBand.asGeometry() self.vertex_count += 1 def canvasMoveEvent(self, event): if self.rubberBand is None: pass elif not self.rubberBand.numberOfVertices(): pass elif self.rubberBand.numberOfVertices() == self.vertex_count: if self.vertex_count == 2: mouse_vertex = self.rubberBand.numberOfVertices() - 1 self.rubberBand.movePoint(mouse_vertex, event.mapPoint()) else: self.rubberBand.addPoint(event.mapPoint()) else: mouse_vertex = self.rubberBand.numberOfVertices() - 1 self.rubberBand.movePoint(mouse_vertex, event.mapPoint()) def deactivate(self): QgsMapTool.deactivate(self) if self.rubberBand is not None: self.rubberBand.reset(QgsWkbTypes.PolygonGeometry) self.deactivated.emit()
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 )
class QgsMapToolSelectRadius(QgsMapTool): def __init__(self, canvas): QgsMapTool.__init__(self, canvas) self.mRubberBand = None self.mCursor = Qt.ArrowCursor # self.mFillColor = QColor( 254, 178, 76, 63 ) # self.mBorderColour = QColor( 254, 58, 29, 100 ) self.mDragging = False self.mCanvas = canvas def canvasPressEvent(self, e): if (e.button() != Qt.LeftButton): return self.mRadiusCenter = self.toMapCoordinates(e.pos()) def canvasMoveEvent(self, e): if (e.buttons() != Qt.LeftButton): return if (not self.mDragging): if (self.mRubberBand == None): self.mRubberBand = QgsRubberBand(self.mCanvas, QGis.Polygon) self.mDragging = True radiusEdge = self.toMapCoordinates(e.pos()) self.setRadiusRubberBand(radiusEdge) def canvasReleaseEvent(self, e): if (e.button() != Qt.LeftButton): return if (not self.mDragging): if (self.mRubberBand == None): self.mRubberBand = QgsRubberBand(self.mCanvas, QGis.Polygon) self.mRadiusCenter = self.toMapCoordinates(e.pos()) radiusEdge = self.toMapCoordinates( QPoint(e.pos().x() + 1, e.pos().y() + 1)) self.setRadiusRubberBand(radiusEdge) radiusGeometry = self.mRubberBand.asGeometry() # QgsMapToolSelectUtils.setSelectFeatures( self.mCanvas, radiusGeometry, e ) QgsMapToolSelectUtils.setSelectFeatures1(self.mCanvas, radiusGeometry, e) self.mRubberBand.reset(QGis.Polygon) self.mRubberBand = None self.mDragging = False def setRadiusRubberBand(self, radiusEdge): r = math.sqrt(self.mRadiusCenter.sqrDist(radiusEdge)) self.mRubberBand.reset(QGis.Polygon) i = 0 while i < 41: theta = i * (2.0 * 3.141592 / 40) radiusPoint = QgsPoint( self.mRadiusCenter.x() + r * math.cos(theta), self.mRadiusCenter.y() + r * math.sin(theta)) self.mRubberBand.addPoint(radiusPoint) i += 1
class RubberBandPolygon(QgsMapTool): def __init__(self, canvas): QgsMapTool.__init__(self, canvas) self.mCanvas = canvas self.mRubberBand = None self.mRubberBand0 = QgsRubberBand(self.mCanvas, QGis.Polygon) self.mCursor = Qt.ArrowCursor self.mFillColor = QColor(254, 178, 76, 63) self.mBorderColour = QColor(254, 58, 29, 100) self.mRubberBand0.setBorderColor(self.mBorderColour) self.polygonGeom = None self.drawFlag = False # self.constructionLayer = constructionLayer def canvasPressEvent(self, e): if (self.mRubberBand == None): self.mRubberBand0.reset(QGis.Polygon) # define._canvas.clearCache () self.mRubberBand = QgsRubberBand(self.mCanvas, QGis.Polygon) self.mRubberBand0 = QgsRubberBand(self.mCanvas, QGis.Polygon) self.mRubberBand.setFillColor(self.mFillColor) self.mRubberBand.setBorderColor(self.mBorderColour) self.mRubberBand0.setFillColor(self.mFillColor) self.mRubberBand0.setBorderColor(self.mBorderColour) if (e.button() == Qt.LeftButton): self.mRubberBand.addPoint(self.toMapCoordinates(e.pos())) else: if (self.mRubberBand.numberOfVertices() > 2): self.polygonGeom = self.mRubberBand.asGeometry() else: return # QgsMapToolSelectUtils.setSelectFeatures( self.mCanvas, polygonGeom, e ) self.mRubberBand.reset(QGis.Polygon) self.mRubberBand0.addGeometry(self.polygonGeom, None) self.mRubberBand0.show() self.mRubberBand = None self.emit(SIGNAL("outputResult"), self.polygonGeom) def canvasMoveEvent(self, e): pass if (self.mRubberBand == None): return if (self.mRubberBand.numberOfVertices() > 0): self.mRubberBand.removeLastPoint(0) self.mRubberBand.addPoint(self.toMapCoordinates(e.pos())) def deactivate(self): # self.rubberBand.reset(QGis.Point) QgsMapTool.deactivate(self) self.emit(SIGNAL("deactivated()"))
class FreehandPolygonMaptool(QgsMapTool, QObject): trigger = pyqtSignal(QgsGeometry) def __init__(self, canvas): QgsMapTool.__init__(self,canvas) self.canvas = canvas self.rb = QgsRubberBand(canvas, QgsWkbTypes.PolygonGeometry) self.rb.setColor(QColor(255, 0, 0, 50)) def activate(self): self.rb.reset(QgsWkbTypes.PolygonGeometry) def deactivate(self): self.rb.reset(QgsWkbTypes.PolygonGeometry) def canvasMoveEvent(self, ev): worldPoint = QgsMapToPixel.toMapCoordinates(self.canvas.getCoordinateTransform(), ev.pos().x(), ev.pos().y()) self.rb.movePoint(worldPoint) def canvasPressEvent(self, ev): if ev.button() == Qt.LeftButton: """ Add a new point to the rubber band """ worldPoint = QgsMapToPixel.toMapCoordinates(self.canvas.getCoordinateTransform(), ev.pos().x(), ev.pos().y()) self.rb.addPoint(worldPoint) elif ev.button() == Qt.RightButton: """ Send back the geometry to the calling class """ self.trigger.emit(self.rb.asGeometry()) def isZoomTool(self): return False def isTransient(self): return False def isEditTool(self): return False
class QgsMapToolSelectFreehand(QgsMapTool): def __init__(self, canvas): QgsMapTool.__init__(self, canvas) self.mRubberBand = None self.mCursor = Qt.ArrowCursor self.mFillColor = QColor(254, 178, 76, 63) self.mBorderColour = QColor(254, 58, 29, 100) self.mDragging = False self.mCanvas = canvas def canvasPressEvent(self, e): if (e.button() != Qt.LeftButton): return if (self.mRubberBand == None): self.mRubberBand = QgsRubberBand(self.mCanvas, QGis.Polygon) self.mRubberBand.setFillColor(self.mFillColor) self.mRubberBand.setBorderColor(self.mBorderColour) self.mRubberBand.addPoint(self.toMapCoordinates(e.pos())) self.mDragging = True def canvasMoveEvent(self, e): if (not self.mDragging or self.mRubberBand == None): return self.mRubberBand.addPoint(self.toMapCoordinates(e.pos())) def canvasReleaseEvent(self, e): selectedFeatures = [] if (self.mRubberBand == None): return if (self.mRubberBand.numberOfVertices() > 2): shapeGeom = self.mRubberBand.asGeometry() selectedFeatures = QgsMapToolSelectUtils.setSelectFeatures1( self.mCanvas, shapeGeom, e) self.mRubberBand.reset(QGis.Polygon) self.mRubberBand = None self.mDragging = False self.emit(SIGNAL("getSelectFeatures"), selectedFeatures)
class ApisMapToolEmitPolygonAndPoint(QgsMapTool, ApisMapToolMixin): mappingFinished = pyqtSignal(QgsGeometry, QgsGeometry, QgsCoordinateReferenceSystem) def __init__(self, canvas): QgsMapTool.__init__(self, canvas) self.canvas = canvas self.rubberBand = None self.tempRubberBand = None self.vertexMarker = None self.capturedPoints = [] self.derivedPoint = None self.capturing = False self.setCursor(Qt.CrossCursor) def canvasReleaseEvent(self, event): if event.button() == Qt.LeftButton: if not self.capturing: self.startCapturing() self.addVertex(event.pos()) elif event.button() == Qt.RightButton: point = self.getDerivedPoint() polygon = self.getCapturedPolygon() self.stopCapturing() if point != None and polygon != None: pointGeom = self.getPointGeometry(point) polygonGeom = self.getPolygonGeometry(polygon) if pointGeom != None and polygonGeom != None: self.mappingFinished.emit(pointGeom, polygonGeom, self.canvas.mapSettings().destinationCrs()) else: self.clearScene() else: self.clearScene() def canvasMoveEvent(self, event): if self.tempRubberBand != None and self.capturing: mapPt = self.transformCoordinates(event.pos()) self.tempRubberBand.movePoint(mapPt) def keyPressEvent(self, event): if event.key() == Qt.Key_Backspace or event.key() == Qt.Key_Delete: self.removeLastVertex() event.ignore() if event.key() == Qt.Key_Escape: self.stopCapturing() self.clearScene() if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter: point = self.getDerivedPoint() polygon = self.getCapturedPolygon() self.stopCapturing() if point != None and polygon != None: pointGeom = self.getPointGeometry(point) polygonGeom = self.getPolygonGeometry(polygon) if pointGeom != None and polygonGeom != None: self.mappingFinished.emit(pointGeom, polygonGeom, self.canvas.mapSettings().destinationCrs()) else: self.clearScene() else: self.clearScene() def startCapturing(self): self.clearScene() self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon) self.rubberBand.setWidth(2) self.rubberBand.setFillColor(QColor(220, 0, 0, 120)) self.rubberBand.setBorderColor(QColor(220, 0, 0)) self.rubberBand.setLineStyle(Qt.DotLine) self.rubberBand.show() self.tempRubberBand = QgsRubberBand(self.canvas, QGis.Polygon) self.tempRubberBand.setWidth(2) self.tempRubberBand.setFillColor(QColor(0, 0, 0, 0)) self.tempRubberBand.setBorderColor(QColor(220, 0, 0)) self.tempRubberBand.setLineStyle(Qt.DotLine) self.tempRubberBand.show() self.vertexMarker = QgsVertexMarker(self.canvas) self.vertexMarker.setIconType(1) self.vertexMarker.setColor(QColor(220, 0, 0)) self.vertexMarker.setIconSize(16) self.vertexMarker.setPenWidth(3) self.vertexMarker.show() self.capturing = True def clearScene(self): if self.vertexMarker: self.canvas.scene().removeItem(self.vertexMarker) self.vertexMarker = None if self.rubberBand: self.canvas.scene().removeItem(self.rubberBand) self.rubberBand = None if self.tempRubberBand: self.canvas.scene().removeItem(self.tempRubberBand) self.tempRubberBand = None def stopCapturing(self): if self.vertexMarker and self.rubberBand and self.rubberBand.numberOfVertices() < 3: self.canvas.scene().removeItem(self.vertexMarker) self.vertexMarker = None if self.rubberBand and self.rubberBand.numberOfVertices() < 3: self.canvas.scene().removeItem(self.rubberBand) self.rubberBand = None if self.tempRubberBand: self.canvas.scene().removeItem(self.tempRubberBand) self.tempRubberBand = None self.capturing = False self.capturedPoints = [] self.derivedPoint = None self.canvas.refresh() def addVertex(self, canvasPoint): mapPt = self.transformCoordinates(canvasPoint) self.rubberBand.addPoint(mapPt) self.capturedPoints.append(mapPt) bandSize = self.rubberBand.numberOfVertices() if bandSize > 2: rubGeom = self.rubberBand.asGeometry() cpGeom = rubGeom.centroid() if not rubGeom.contains(cpGeom): cpGeom = rubGeom.pointOnSurface() #nearestCp = rubGeom.nearestPoint(cpGeom) self.vertexMarker.setCenter(cpGeom.asPoint()) self.derivedPoint = cpGeom.asPoint() self.vertexMarker.show() self.tempRubberBand.reset(QGis.Polygon) firstPoint = self.rubberBand.getPoint(0, 0) self.tempRubberBand.addPoint(firstPoint) self.tempRubberBand.movePoint(mapPt) self.tempRubberBand.addPoint(mapPt) def removeLastVertex(self): if not self.capturing: return bandSize = self.rubberBand.numberOfVertices() tempBandSize = self.tempRubberBand.numberOfVertices() numPoints = len(self.capturedPoints) if bandSize < 1 or numPoints < 1: return self.rubberBand.removePoint(-1) if bandSize > 1: if tempBandSize > 1: point = self.rubberBand.getPoint(0, bandSize - 2) self.tempRubberBand.movePoint(tempBandSize - 2, point) else: self.tempRubberBand.reset(QGis.Polygon) bandSize = self.rubberBand.numberOfVertices() if bandSize < 3: self.vertexMarker.hide() else: rubGeom = self.rubberBand.asGeometry() cpGeom = rubGeom.centroid() if not rubGeom.contains(cpGeom): cpGeom = rubGeom.pointOnSurface() #nearestCp = rubGeom.nearestPoint(cpGeom) self.vertexMarker.setCenter(cpGeom.asPoint()) self.derivedPoint = cpGeom.asPoint() self.vertexMarker.show() del self.capturedPoints[-1] def getCapturedPolygon(self): polygon = self.capturedPoints if len(polygon) < 3: return None else: return polygon def getDerivedPoint(self): point = self.derivedPoint if point == None: return None else: return point def getPointGeometry(self, geom): p = QgsGeometry.fromPoint(geom) if p.isGeosValid() and not p.isGeosEmpty(): return p else: return None def getPolygonGeometry(self, geom): p = QgsGeometry.fromPolygon([geom]) if p.isGeosValid() and not p.isGeosEmpty(): return p else: return None
class ALKISPolygonInfo(QgsMapTool): def __init__(self, plugin): QgsMapTool.__init__(self, plugin.iface.mapCanvas()) self.plugin = plugin self.iface = plugin.iface self.cursor = QCursor(QPixmap([ "16 16 3 1", " c None", ". c #FF0000", "+ c #FFFFFF", " ", " +.+ ", " ++.++ ", " +.....+ ", " +. .+ ", " +. . .+ ", " +. . .+ ", " ++. . .++", " ... ...+... ...", " ++. . .++", " +. . .+ ", " +. . .+ ", " ++. .+ ", " ++.....+ ", " ++.++ ", " +.+ " ])) self.rubberBand = QgsRubberBand(self.iface.mapCanvas(), self.plugin.PolygonGeometry) self.areaMarkerLayer = None def canvasPressEvent(self, e): if self.areaMarkerLayer is None: (layerId, ok) = QgsProject.instance().readEntry("alkis", "/areaMarkerLayer") if ok: self.areaMarkerLayer = self.plugin.mapLayer(layerId) if self.areaMarkerLayer is None: QMessageBox.warning(None, "ALKIS", u"Fehler: Flächenmarkierungslayer nicht gefunden!") def canvasMoveEvent(self, e): if self.rubberBand.numberOfVertices() > 0: point = self.iface.mapCanvas().getCoordinateTransform().toMapCoordinates(e.x(), e.y()) self.rubberBand.movePoint(point) def canvasReleaseEvent(self, e): point = self.iface.mapCanvas().getCoordinateTransform().toMapCoordinates(e.x(), e.y()) if e.button() == Qt.LeftButton: self.rubberBand.addPoint(point) return QApplication.setOverrideCursor(Qt.WaitCursor) if self.rubberBand.numberOfVertices() >= 3: g = self.plugin.transform( self.rubberBand.asGeometry() ) self.rubberBand.reset(self.plugin.PolygonGeometry) fs = self.plugin.highlight( where=u"st_intersects(wkb_geometry,st_geomfromtext('POLYGON((%s))'::text,%d))" % ( ",".join(["%.3lf %.3lf" % (p[0], p[1]) for p in g.asPolygon()[0]]), self.plugin.getepsg() ) ) if len(fs) == 0: QApplication.restoreOverrideCursor() QMessageBox.information(None, u"Fehler", u"Keine Flurstücke gefunden.") return gmlids = [] for e in fs: gmlids.append(e['gmlid']) try: s = QSettings("norBIT", "EDBSgen/PRO") for i in range(0, len(fs)): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(("localhost", int(s.value("norGISPort", "6102")))) sock.send("NORGIS_MAIN#EDBS#ALBKEY#{}#{}#".format(fs[i]['flsnr'], 0 if i + 1 == len(fs) else 1).encode("utf-8")) sock.close() if win32: window = win32gui.FindWindow(None, s.value("albWin", "norGIS")) win32gui.SetForegroundWindow(window) except socket.error: QMessageBox.information(None, u"Fehler", u"Verbindung zu norGIS schlug fehl.") else: self.rubberBand.reset(self.plugin.PolygonGeometry) QApplication.restoreOverrideCursor()
class Geo360Dialog(QWidget, Ui_orbitalDialog): """QGIS Plugin Implementation.""" def __init__(self, iface, parent=None, featuresId=None, layer=None): """Constructor.""" QDialog.__init__(self) self.setupUi(self) self.s = QSettings() self.plugin_path = os.path.dirname(os.path.realpath(__file__)) QTextCodec.setCodecForCStrings(QTextCodec.codecForName("UTF-8")) Gui.loadLatin1Encoding() self.iface = iface self.canvas = self.iface.mapCanvas() self.parent = parent #Orientation from image self.yaw = math.pi self.bearing = None self.layer = layer self.featuresId = featuresId #Restore Previous size self.RestoreSize() #defaults self.actualPointDx = None self.actualPointSx = None self.actualPointOrientation = None self.selected_features = qgsutils.getToFeature(self.canvas, self.layer, self.featuresId) #Get image path self.current_image = self.GetImage() QtGui.qApp.processEvents() #Creamos el visor self.CreateViewer() QtGui.qApp.processEvents() #Check if image exist if os.path.exists(self.current_image) is False: qgsutils.showUserAndLogMessage(self, u"Information: ", u"There is no associated image.", QgsMessageBar.INFO) self.ChangeUrlViewer(config.DEFAULT_EMPTY) self.setPosition() return #Set RubberBand self.setOrientation() self.setPosition() QtGui.qApp.processEvents() #Copy file to local server self.CopyFile(self.current_image) QtGui.qApp.processEvents() #Set Initial Yaw def SetInitialYaw(self): self.bearing = self.selected_features.attribute(config.column_yaw) self.view.browser.GetMainFrame().ExecuteFunction( "InitialYaw", self.bearing) return #Create Viewer def CreateViewer(self): qgsutils.showUserAndLogMessage(self, u"Information: ", u"Create viewer", QgsMessageBar.INFO, onlyLog=True) self.view = CefWidget(self) self.m_vbox = QVBoxLayout() self.m_vbox.addWidget(self.view) QtGui.qApp.processEvents() self.frame.setLayout(self.m_vbox) QtGui.qApp.processEvents() self.view.embed() QtGui.qApp.processEvents() return #Copy Image File in Local Server def CopyFile(self, src): qgsutils.showUserAndLogMessage(self, u"Information: ", u"Copiar imagem", QgsMessageBar.INFO, onlyLog=True) pattern = "^(?P<photo_id>\d+)[^\d].*jpg$" src_dir = src dst_dir = self.plugin_path + "\\viewer" #Delete images on first time for root, dirs, files in os.walk(dst_dir): for file in filter(lambda x: re.match(pattern, x), files): os.remove(os.path.join(root, file)) #Copy image in local folder dst_dir = dst_dir + "\\image.jpg" shutil.copy(src_dir, dst_dir) QtGui.qApp.processEvents() return #Restore Dialog Size def RestoreSize(self): dw = self.s.value("EquirectangularViewer/width") dh = self.s.value("EquirectangularViewer/height") if dw == None: return size = self.size() anim = QtCore.QPropertyAnimation(self, 'size', self) anim.setStartValue(size) anim.setEndValue(QtCore.QSize(dw, dh)) anim.setDuration(1) anim.start() QtGui.qApp.processEvents() return #Save Dialog Size def SaveSize(self): dw = self.width() dh = self.height() self.s.setValue("EquirectangularViewer/width", dw) self.s.setValue("EquirectangularViewer/height", dh) QtGui.qApp.processEvents() return #Get Selected Image def GetImage(self): try: path = qgsutils.getAttributeFromFeature(self.selected_features, config.column_name) except: qgsutils.showUserAndLogMessage(self, u"Information: ", u"Column not found.", QgsMessageBar.INFO) return qgsutils.showUserAndLogMessage(self, u"Information: ", str(path), QgsMessageBar.INFO, onlyLog=True) return path #Change Url Viewer def ChangeUrlViewer(self, new_url): self.view.browser.GetMainFrame().ExecuteJavascript( "window.location='%s'" % new_url) QtGui.qApp.processEvents() return #Reaload Image viewer def ReloadView(self, newId): self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) # this will activate the window self.activateWindow() QtGui.qApp.processEvents() self.selected_features = qgsutils.getToFeature(self.canvas, self.layer, newId) self.current_image = self.GetImage() #Check if image exist if os.path.exists(self.current_image) is False: qgsutils.showUserAndLogMessage( self, u"Information: ", u"It is not in the associated image.", QgsMessageBar.INFO) self.ChangeUrlViewer(config.DEFAULT_EMPTY) self.setPosition() return #Set RubberBand self.setOrientation() self.setPosition() #Copy file to local server self.CopyFile(self.current_image) self.ChangeUrlViewer(config.DEFAULT_URL) QtGui.qApp.processEvents() return #Expanded/Decreased Dialog def ResizeDialog(self): sender = QObject.sender(self) w = self.width() h = self.height() size = self.size() anim = QtCore.QPropertyAnimation(self, 'size', self) anim.setStartValue(size) if sender.objectName() == "btn_ZoomOut": anim.setEndValue(QtCore.QSize(w - 50, h - 50)) else: anim.setEndValue(QtCore.QSize(w + 50, h + 50)) anim.setDuration(300) anim.start() QtGui.qApp.processEvents() return #Get to Back Image def GetBackNextImage(self): qgsutils.removeAllHighlightFeaturesFromCanvasScene(self.canvas) sender = QObject.sender(self) lys = self.canvas.layers() #Check if mapa foto is loaded if len(lys) == 0: qgsutils.showUserAndLogMessage( self, u"Information: ", u"You need to upload the photo layer.", QgsMessageBar.INFO) return for layer in lys: if layer.name() == config.layer_name: self.encontrado = True self.iface.setActiveLayer(layer) QtGui.qApp.processEvents() f = self.selected_features ac_lordem = f.attribute(config.column_order) if sender.objectName() == "btn_back": new_lordem = int(ac_lordem) - 1 else: new_lordem = int(ac_lordem) + 1 #Filter mapa foto layer ids = [ feat.id() for feat in layer.getFeatures(QgsFeatureRequest( ).setFilterExpression("order ='" + str(new_lordem) + "'")) ] if len(ids) == 0: qgsutils.showUserAndLogMessage( self, u"Information: ", u"There is no superiority that follows.", QgsMessageBar.INFO) #Filter mapa foto layer ids = [ feat.id() for feat in layer.getFeatures(QgsFeatureRequest( ).setFilterExpression("order ='" + str(ac_lordem) + "'")) ] #Update selected feature self.ReloadView(ids[0]) return self.ReloadView(ids[0]) QtGui.qApp.processEvents() if self.encontrado == False: qgsutils.showUserAndLogMessage( self, u"Information: ", u"You need to upload the photo layer.", QgsMessageBar.INFO) return #FullScreen action button def FullScreen(self, bool): qgsutils.showUserAndLogMessage(self, u"Information: ", u"Fullscreen.", QgsMessageBar.INFO, onlyLog=True) if (bool): self.showFullScreen() else: self.showNormal() QtGui.qApp.processEvents() return @staticmethod def ActualOrientation(yaw): geo360Plugin = qgis.utils.plugins["EquirectangularViewer"] if geo360Plugin is not None: geo360Dialog = qgis.utils.plugins["EquirectangularViewer"].dlg if geo360Dialog is not None: geo360Dialog.UpdateOrientation(yaw=float(yaw)) return #Update Orientation def UpdateOrientation(self, yaw=None): self.bearing = self.selected_features.attribute(config.column_yaw) try: self.actualPointOrientation.reset() except: pass self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(), QGis.Line) self.actualPointOrientation.setColor(Qt.blue) self.actualPointOrientation.setWidth(5) self.actualPointOrientation.addPoint(self.actualPointDx) #End Point CS = self.canvas.mapUnitsPerPixel() * 25 A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2) A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2) self.actualPointOrientation.addPoint(QgsPoint(A1x, A1y)) #Vision Angle if yaw is not None: angle = float(self.bearing + yaw) * math.pi / -180 else: angle = float(self.bearing) * math.pi / -180 tmpGeom = self.actualPointOrientation.asGeometry() self.actualPointOrientation.setToGeometry( self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle), self.dumLayer) QtGui.qApp.processEvents() #Set Orientation in the firt time def setOrientation(self, yaw=None): self.bearing = self.selected_features.attribute(config.column_yaw) self.actualPointDx = self.selected_features.geometry().asPoint() try: self.actualPointOrientation.reset() except: pass QtGui.qApp.processEvents() self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(), QGis.Line) self.actualPointOrientation.setColor(Qt.blue) self.actualPointOrientation.setWidth(5) self.actualPointOrientation.addPoint(self.actualPointDx) #End Point CS = self.canvas.mapUnitsPerPixel() * 25 A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2) A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2) self.actualPointOrientation.addPoint(QgsPoint(A1x, A1y)) #Vision Angle if yaw is not None: angle = float(self.bearing + yaw) * math.pi / -180 else: angle = float(self.bearing) * math.pi / -180 tmpGeom = self.actualPointOrientation.asGeometry() self.rotateTool = transformGeometry() self.dumLayer = QgsVectorLayer("Point?crs=EPSG:4326", "temporary_points", "memory") self.actualPointOrientation.setToGeometry( self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle), self.dumLayer) QtGui.qApp.processEvents() #Set RubberBand Position def setPosition(self): self.actualPointDx = self.selected_features.geometry().asPoint() try: self.positionDx.reset() self.positionSx.reset() self.positionInt.reset() except: pass QtGui.qApp.processEvents() self.positionDx = QgsRubberBand(self.iface.mapCanvas(), QGis.Point) self.positionDx.setWidth(6) self.positionDx.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionDx.setIconSize(6) self.positionDx.setColor(Qt.black) self.positionSx = QgsRubberBand(self.iface.mapCanvas(), QGis.Point) self.positionSx.setWidth(5) self.positionSx.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionSx.setIconSize(4) self.positionSx.setColor(Qt.blue) self.positionInt = QgsRubberBand(self.iface.mapCanvas(), QGis.Point) self.positionInt.setWidth(5) self.positionInt.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionInt.setIconSize(3) self.positionInt.setColor(Qt.white) QtGui.qApp.processEvents() self.positionDx.addPoint(self.actualPointDx) self.positionSx.addPoint(self.actualPointDx) self.positionInt.addPoint(self.actualPointDx) QtGui.qApp.processEvents() #Close dialog def closeEvent(self, evt): qgsutils.showUserAndLogMessage(self, u"Information: ", u"Close dialog", QgsMessageBar.INFO, onlyLog=True) qgsutils.removeAllHighlightFeaturesFromCanvasScene(self.canvas) QtGui.qApp.processEvents() self.canvas.refresh() self.iface.actionPan().trigger() self.SaveSize() self.stopTimer() QtGui.qApp.processEvents() return
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 InfoTool(QgsMapTool): infoResults = pyqtSignal(dict) def __init__(self, canvas, snapradius = 2): super(InfoTool, self).__init__(canvas) self.canvas = 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): self.band.reset() for layer in self.selectionlayers: if (not layer.type() == QgsMapLayer.VectorLayer or layer.geometryType() == QGis.NoGeometry): continue rect = self.toLayerCoordinates(layer, rect) rq = QgsFeatureRequest().setFilterRect(rect).setFlags(QgsFeatureRequest.ExactIntersect) features = [] for feature in layer.getFeatures(rq): if feature.isValid(): features.append(feature) yield layer, features 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.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 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)) print results self.infoResults.emit(results)
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): 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 = [] for feature in layer.getFeatures(rq): if feature.isValid(): features.append(feature) yield layer, features 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): 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() else: 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 ExtractRasterValue(ParentMapTool): """ Button 18. User select nodes and assign raster elevation or value """ def __init__(self, iface, settings, action, index_action): """ Class constructor """ # Call ParentMapTool constructor super(ExtractRasterValue, self).__init__(iface, settings, action, index_action) self.dragging = False # Vertex marker self.vertexMarker = QgsVertexMarker(self.canvas) self.vertexMarker.setColor(QColor(255, 25, 25)) self.vertexMarker.setIconSize(11) self.vertexMarker.setIconType(QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X self.vertexMarker.setPenWidth(5) # Rubber band self.rubberBand = QgsRubberBand(self.canvas, True) mFillColor = QColor(100, 0, 0) self.rubberBand.setColor(mFillColor) self.rubberBand.setWidth(3) mBorderColor = QColor(254, 58, 29) self.rubberBand.setBorderColor(mBorderColor) # Select rectangle self.selectRect = QRect() # Init self.vectorLayer = None self.rasterLayer = None def reset(self): """ Clear selected features """ layer = self.vectorLayer if layer is not None: layer.removeSelection() # Graphic elements self.rubberBand.reset() def set_config_action(self, action_99): """ Get the config form action""" self.configAction = action_99 """ QgsMapTools inherited event functions """ def canvasMoveEvent(self, event): """ With left click the digitizing is finished """ if self.vectorLayer is None: return if event.buttons() == Qt.LeftButton: if not self.dragging: self.dragging = True self.selectRect.setTopLeft(event.pos()) self.selectRect.setBottomRight(event.pos()) self.set_rubber_band() else: # Hide highlight self.vertexMarker.hide() # Get the click x = event.pos().x() y = event.pos().y() eventPoint = QPoint(x, y) # Snapping (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint) # @UnusedVariable # That's the snapped point if result <> []: # Check Arc or Node for snapPoint in result: if snapPoint.layer == self.vectorLayer: # Get the point point = QgsPoint(result[0].snappedVertex) # Add marker self.vertexMarker.setCenter(point) self.vertexMarker.show() break def canvasPressEvent(self, event): self.selectRect.setRect(0, 0, 0, 0) self.rubberBand.reset() def canvasReleaseEvent(self, event): """ With left click the digitizing is finished """ if event.button() == Qt.LeftButton: # Get the click x = event.pos().x() y = event.pos().y() eventPoint = QPoint(x, y) # Node layer layer = self.vectorLayer # Not dragging, just simple selection if not self.dragging: # Snap to node (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint) # @UnusedVariable # That's the snapped point if result <> [] and (result[0].layer.name() == self.vectorLayer.name()): point = QgsPoint(result[0].snappedVertex) # @UnusedVariable layer.removeSelection() layer.select([result[0].snappedAtGeometry]) # Interpolate values self.raster_interpolate() # Hide highlight self.vertexMarker.hide() else: # Set valid values for rectangle's width and height if self.selectRect.width() == 1: self.selectRect.setLeft(self.selectRect.left() + 1) if self.selectRect.height() == 1: self.selectRect.setBottom(self.selectRect.bottom() + 1) self.set_rubber_band() selectGeom = self.rubberBand.asGeometry() # @UnusedVariable self.select_multiple_features(self.selectRectMapCoord) self.dragging = False # Interpolate values self.raster_interpolate() elif event.button() == Qt.RightButton: # Interpolate values self.raster_interpolate() def activate(self): # Check button self.action().setChecked(True) # Rubber band self.rubberBand.reset() # Store user snapping configuration self.snapperManager.storeSnappingOptions() # Clear snapping self.snapperManager.clearSnapping() # Get layers res = self.find_raster_layers() # if res == 0: # self.controller.show_warning("Raster configuration tool not properly configured.") # return # Change cursor self.canvas.setCursor(self.cursor) # Show help message when action is activated if self.show_help: message = ( "Right click to use current selection, select connec points by clicking or dragging (selection box)" ) self.controller.show_info(message, context_name="ui_message") # Control current layer (due to QGIS bug in snapping system) try: if self.canvas.currentLayer().type() == QgsMapLayer.VectorLayer: self.canvas.setCurrentLayer(self.layer_arc) except: self.canvas.setCurrentLayer(self.layer_arc) def deactivate(self): # Check button self.action().setChecked(False) # Rubber band self.rubberBand.reset() # Restore previous snapping self.snapperManager.recoverSnappingOptions() # Recover cursor self.canvas.setCursor(self.stdCursor) def nearestNeighbor(self, thePoint): ident = self.dataProv.identify(thePoint, QgsRaster.IdentifyFormatValue) value = None if ident is not None: # and ident.has_key(choosenBand+1): try: value = float(ident.results()[int(self.band)]) except TypeError: value = None if value == self.noDataValue: return None return value def writeInterpolation(self, f, fieldIdx): thePoint = f.geometry().asPoint() value = self.nearestNeighbor(thePoint) self.vectorLayer.changeAttributeValue(f.id(), fieldIdx, value) def raster_interpolate(self): """ Interpolate features value from raster """ # Interpolate values if self.vectorLayer is None and self.rasterLayer is None: return # Get data provider layer = self.vectorLayer self.dataProv = self.rasterLayer.dataProvider() if self.dataProv.srcNoDataValue(int(self.band)): self.noDataValue = self.dataProv.srcNoDataValue(int(self.band)) else: self.noDataValue = None self.continueProcess = True self.fieldIdx = "" self.fieldIdx = layer.fieldNameIndex(self.fieldName) if self.band == 0: self.controller.show_warning("You must choose a band for the raster layer.") return if self.fieldName == "": self.controller.show_warning("You must choose a field to write values.") return if self.fieldIdx < 0: self.controller.show_warning("Selected field does not exist in feature layer.") return k = 0 c = 0 f = QgsFeature() # Check features selected if layer.selectedFeatureCount() == 0: message = "You have to select at least one feature!" self.controller.show_warning(message, context_name="ui_message") return # Check editable if not layer.isEditable(): layer.startEditing() # Get selected id's ids = self.vectorLayer.selectedFeaturesIds() for fid in ids: k += 1 layer.getFeatures(QgsFeatureRequest(fid)).nextFeature(f) c += 1 self.writeInterpolation(f, self.fieldIdx) QCoreApplication.processEvents() self.controller.show_info( "%u values have been updated in layer %s.%s over %u points using %s raster" % (c, self.vectorLayer.name(), self.fieldName, k, self.table_raster) ) # Check editable if layer.isEditable(): layer.commitChanges() # Refresh map canvas self.rubberBand.reset() self.iface.mapCanvas().refresh() def set_rubber_band(self): # Coordinates transform transform = self.canvas.getCoordinateTransform() # Coordinates ll = transform.toMapCoordinates(self.selectRect.left(), self.selectRect.bottom()) lr = transform.toMapCoordinates(self.selectRect.right(), self.selectRect.bottom()) ul = transform.toMapCoordinates(self.selectRect.left(), self.selectRect.top()) ur = transform.toMapCoordinates(self.selectRect.right(), self.selectRect.top()) # Rubber band self.rubberBand.reset() self.rubberBand.addPoint(ll, False) self.rubberBand.addPoint(lr, False) self.rubberBand.addPoint(ur, False) self.rubberBand.addPoint(ul, False) self.rubberBand.addPoint(ll, True) self.selectRectMapCoord = QgsRectangle(ll, ur) def select_multiple_features(self, selectGeometry): # Default choice behaviour = QgsVectorLayer.SetSelection # Modifiers modifiers = QApplication.keyboardModifiers() if modifiers == Qt.ControlModifier: behaviour = QgsVectorLayer.AddToSelection elif modifiers == Qt.ShiftModifier: behaviour = QgsVectorLayer.RemoveFromSelection if self.vectorLayer is None: return # Change cursor QApplication.setOverrideCursor(Qt.WaitCursor) # Selection self.vectorLayer.selectByRect(selectGeometry, behaviour) # Old cursor QApplication.restoreOverrideCursor() def find_raster_layers(self): # Query database (form data) sql = "SELECT *" sql += " FROM " + self.schema_name + ".config_extract_raster_value" rows = self.controller.get_rows(sql) if not rows: self.controller.show_warning("Any data found in table config_extract_raster_value") self.configAction.activate(QAction.Trigger) return 0 # Layers row = rows[0] self.table_raster = row[1] self.band = row[2] self.table_vector = row[3] self.fieldName = row[4] # Check if we have any layer loaded layers = self.iface.legendInterface().layers() if len(layers) == 0: return # Init layers self.rasterLayer = None self.vectorLayer = None # Iterate over all layers to get the ones specified in 'db' config section for cur_layer in layers: if cur_layer.name() == self.table_raster: self.rasterLayer = cur_layer (uri_schema, uri_table) = self.controller.get_layer_source(cur_layer) # @UnusedVariable if uri_table is not None: if self.table_vector in uri_table: self.vectorLayer = cur_layer # Check config if self.vectorLayer is None or self.rasterLayer is None: self.configAction.activate(QAction.Trigger) # Set snapping if self.vectorLayer <> None: self.snapperManager.snapToLayer(self.vectorLayer) else: self.controller.show_warning("Check vector_layer in config form, layer does not exist or is not defined.") return 0 if self.rasterLayer == None: self.controller.show_warning("Check raster_layer in config form, layer does not exist or is not defined.") return 0 return 1
class DrawPolygon(QgsMapTool): """ This class is responsible for drawing a polygon on the map and returning the coordinates of it. """ selectionDone = pyqtSignal() move = pyqtSignal() def __init__(self, iface, parent): """ Initialize the draw polygon class :param iface: Interface to be displayed :param parent: Parent dialog, which initialized the class (should be JobAdaptDialog) """ canvas = iface QgsMapTool.__init__(self, canvas) self.canvas = canvas self.iface = iface self.parent = parent self.status = 0 self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.rb.setColor(QColor(254, 178, 76, 63)) def keyPressEvent(self, e): """ Called if a keyboard key got pressed :param e: Event """ if e.matches(QKeySequence.Undo): if self.rb.numberOfVertices() > 1: self.rb.removeLastPoint() def canvasPressEvent(self, e): """ Called if a mouse button got pressed on the map canvas. :param e: Event """ if e.button() == Qt.LeftButton: if self.status == 0: self.rb.reset(QgsWkbTypes.PolygonGeometry) self.status = 1 self.rb.addPoint(self.toMapCoordinates(e.pos())) else: if self.rb.numberOfVertices() > 2: self.status = 0 self.selectionDone.emit() geometry = self.rb.asGeometry() self.parent.draw_poly(geometry) else: self.reset() def canvasMoveEvent(self, e): """ Called if a mouse button got pressed on the map canvas. :param e: Event """ if self.rb.numberOfVertices() > 0 and self.status == 1: self.rb.removeLastPoint(0) self.rb.addPoint(self.toMapCoordinates(e.pos())) self.move.emit() def reset(self): """ Reseting the polygon """ self.status = 0 self.rb.reset(True) def deactivate(self): """ Deactivate the polygon """ self.rb.reset(True) QgsMapTool.deactivate(self)
class QgepMapToolAddFeature(QgsMapToolAdvancedDigitizing): """ Base class for adding features """ def __init__(self, iface, layer): QgsMapToolAdvancedDigitizing.__init__(self, iface.mapCanvas(), iface.cadDockWidget()) 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(1) self.tempRubberband = QgsRubberBand(iface.mapCanvas(), layer.geometryType()) self.tempRubberband.setColor(QColor("#ee5555")) self.tempRubberband.setWidth(1) self.tempRubberband.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.rightClicked(event) else: self.leftClicked(event) def leftClicked(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.tempRubberband.reset() def rightClicked(self, _): """ On a right click we create a new feature from the existing rubberband and show the add dialog """ 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 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.tempRubberband.movePoint(mousepos) except TypeError: pass
class PlanetSearchResultsWidget(RESULTS_BASE, RESULTS_WIDGET): """ """ zoomToAOIRequested = pyqtSignal() setAOIRequested = pyqtSignal(dict) setSearchParamsRequested = pyqtSignal(dict, tuple) checkedCountChanged = pyqtSignal(int) grpBoxQuery: QGroupBox teQuery: QPlainTextEdit frameSearching: QFrame btnCancel: QToolButton btnShowQuery: QToolButton btnZoomToAOI: QToolButton btnSetAOI: QToolButton btnSetSearchParams: QToolButton lblSearching: QLabel frameResults: QFrame def __init__(self, parent=None, iface=None, api_key=None, request_type=None, request=None, response_timeout=RESPONSE_TIMEOUT, sort_order=None): super().__init__(parent=parent) self.setupUi(self) self._parent = parent self._iface = iface # TODO: Grab responseTimeOut from plugin settings and override default self._response_timeout = response_timeout self._request_type = request_type self._request = request self.sort_order = sort_order self.teQuery.setPlainText(json.dumps(request, indent=2)) # self.grpBoxQuery.setSaveCollapsedState(False) # self.grpBoxQuery.setCollapsed(True) self.grpBoxQuery.hide() self.btnZoomToAOI.clicked.connect(self._zoom_to_request_aoi) self.btnSetAOI.clicked.connect(self._set_aoi_from_request) self.btnSetSearchParams.clicked.connect(self._set_search_params_from_request) self.btnShowQuery.clicked.connect(self._toggle_query) self._aoi_box = None self._setup_request_aoi_box() self.results_tree = PlanetSearchResultsView( parent=self, iface=iface, api_key=api_key, request_type=request_type, request=request, response_timeout=self._response_timeout, sort_order=sort_order ) self.results_tree.checkedCountChanged[int].connect( self.checked_count_changed) self.frameResults.layout().addWidget(self.results_tree) self.results_tree.setHidden(True) search_model = self.results_tree.search_model() if self.results_tree.search_model(): search_model.searchFinished.connect(self._search_finished) search_model.searchNoResults.connect(self._search_no_results) search_model.searchCancelled.connect(self._search_cancelled) search_model.searchTimedOut[int].connect(self._search_timed_out) self.btnCancel.clicked.connect(search_model.cancel_search) self.waiting_spinner = QtWaitingSpinner( self.frameResults, centerOnParent=True, disableParentWhenSpinning=False, modality=Qt.NonModal ) self.waiting_spinner.setRoundness(80.0) self.waiting_spinner.setMinimumTrailOpacity(15.0) self.waiting_spinner.setTrailFadePercentage(75.0) self.waiting_spinner.setNumberOfLines(15) self.waiting_spinner.setLineLength(14.0) self.waiting_spinner.setLineWidth(3.0) self.waiting_spinner.setInnerRadius(8.0) self.waiting_spinner.setRevolutionsPerSecond(1.0) self.waiting_spinner.setColor(PLANET_COLOR) self.waiting_spinner.start() self.waiting_spinner.show() search_model.start_api_search() # QTimer.singleShot(0, search_model.start_api_search) def _nix_waiting_spinner(self): self.waiting_spinner.stop() self.waiting_spinner.hide() def checked_count(self): return self.results_tree.checked_count() def checked_queue(self): return self.results_tree.checked_queue() @pyqtSlot(int) def checked_count_changed(self, count): if type(self._parent).__name__ == 'QTabWidget': # self._parent: QTabWidget tab_indx = self._parent.indexOf(self) if tab_indx != -1: txt = f'{self._request_type.capitalize()}' if count > 0: txt += f' ({count})' self._parent.setTabText(tab_indx, txt) self.checkedCountChanged.emit(count) @pyqtSlot() def _toggle_query(self): if self.grpBoxQuery.isVisible(): self.grpBoxQuery.hide() self.btnShowQuery.setIcon( QIcon(':/plugins/planet_explorer/expand-triangle.svg') ) else: self.grpBoxQuery.show() self.btnShowQuery.setIcon( QIcon(':/plugins/planet_explorer/collapse-triangle.svg') ) @pyqtSlot() def _search_finished(self): self._nix_waiting_spinner() self.frameSearching.hide() self.results_tree.show() @pyqtSlot() def _search_no_results(self): self._nix_waiting_spinner() self.lblSearching.setText('No results found') self.btnCancel.hide() self.results_tree.hide() @pyqtSlot() def _search_cancelled(self): self._nix_waiting_spinner() self.lblSearching.setText('Search cancelled') self.btnCancel.hide() self.results_tree.hide() @pyqtSlot(int) def _search_timed_out(self, timeout): self._nix_waiting_spinner() self.lblSearching.setText(f'Search timed out ({timeout} seconds)') self.btnCancel.hide() self.results_tree.hide() def _setup_request_aoi_box(self): if self._iface: log.debug('iface is available, adding aoi box support') self._aoi_box = QgsRubberBand( self._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) else: log.debug('iface is None, skipping footprint support') self._aoi_box = None @pyqtSlot() def clear_aoi_box(self): if self._aoi_box: self._aoi_box.reset(QgsWkbTypes.PolygonGeometry) @pyqtSlot() def _zoom_to_request_aoi(self): if not self._iface: log.debug('No iface object, skipping AOI extent') return aoi_geom = None if self._request_type == RESOURCE_DAILY: aoi_geom = geometry_from_request(self._request) if not aoi_geom: log.debug('No AOI geometry defined, skipping zoom to AOI') return qgs_geom: QgsGeometry = qgsgeometry_from_geojson(aoi_geom) self._aoi_box.setToGeometry( qgs_geom, QgsCoordinateReferenceSystem("EPSG:4326") ) self.show_aoi() zoom_canvas_to_aoi(aoi_geom, iface_obj=self._iface) self.zoomToAOIRequested.emit() def hide_aoi_if_matches_geom(self,geom): if self._aoi_box is not None: color = (QColor(0, 0, 0, 0) if self._aoi_box.asGeometry().equals(geom) else SEARCH_AOI_COLOR) self._aoi_box.setStrokeColor(color) def show_aoi(self): if self._aoi_box is not None: self._aoi_box.setStrokeColor(SEARCH_AOI_COLOR) def aoi_geom(self): if self._aoi_box is not None: return self._aoi_box.asGeometry() @pyqtSlot() def _set_aoi_from_request(self): self.setAOIRequested.emit(self._request) @pyqtSlot() def _set_search_params_from_request(self): self.setSearchParamsRequested.emit(self._request, self.sort_order) @pyqtSlot() def clean_up(self): self.results_tree.clean_up() self.clear_aoi_box() # noinspection PyPep8Naming def closeEvent(self, event): self.clean_up() super().closeEvent(self, event) def request_query(self): return self._request
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, QGis.Polygon ) self.selectrect = QRect() self.dragging = False self.selectionlayers = [] def getFeatures(self, rect, firstonly=False): # 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.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) 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, 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.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() 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)) RoamEvents.selectioncleared.emit() RoamEvents.selectionchanged.emit(results)
class EarthMineQGIS(QObject): """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface super(EarthMineQGIS, self).__init__() self.movingfeature = None self.iface = iface self.viewer = None self.canvas = self.iface.mapCanvas() self.settings = QSettings() # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value("locale/userLocale")[0:2] locale_path = os.path.join(self.plugin_dir, "i18n", "EarthMineQGIS_{}.qm".format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > "4.3.3": QCoreApplication.installTranslator(self.translator) self.pointtool = QgsMapToolEmitPoint(self.canvas) self.pointtool.canvasClicked.connect(self.set_viewer_location) self.settingsdialog = SettingsDialog(self.iface.mainWindow()) self.actions = [] self.menu = self.tr(u"&Earthmine") self.toolbar = self.iface.addToolBar(u"EarthMineQGIS") self.toolbar.setObjectName(u"EarthMineQGIS") self.legend = self.iface.legendInterface() emcolor = QColor(1, 150, 51) self.tempband = QgsRubberBand(self.canvas, QGis.Line) self.tempband.setWidth(5) self.tempband.setColor(emcolor) self.tempbandpoints = QgsRubberBand(self.canvas, QGis.Point) self.tempbandpoints.setWidth(7) self.tempbandpoints.setColor(emcolor) self.movingband = QgsRubberBand(self.canvas, QGis.Point) self.movingband.setWidth(5) self.movingband.setColor(emcolor) self.layersignals = [] self.marker = None def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ":/icons/settings" self.add_action( icon_path, text=self.tr(u"Show Settings"), callback=self.show_settings, parent=self.iface.mainWindow() ) icon_path = ":/icons/viewer" self.add_action( icon_path, text=self.tr(u"Earthmine Viewer"), callback=self.open_viewer, parent=self.iface.mainWindow() ) self.marker = PostionMarker(self.canvas) self.marker.hide() self.viewer = Viewer(callbackobject=self) self.viewer.trackingChanged.connect(self.marker.setTracking) self.viewer.setLocationTriggered.connect(partial(self.canvas.setMapTool, self.pointtool)) self.viewer.updateFeatures.connect(self.update_earthmine_features) self.viewer.layerChanged.connect(self.iface.setActiveLayer) self.viewer.clearLine.connect(self.clear_bands) self.viewer.closed.connect(self.remove_items) self.iface.currentLayerChanged.connect(self.viewer.update_current_layer) cursor = QCursor(QPixmap(":/icons/location")) self.pointtool.setCursor(cursor) self.pointtool.setAction(self.viewer.setlocationaction) def remove_items(self): self.marker.setTracking(False) self.disconnect_projectsignals() self.iface.actionPan().trigger() def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" self.canvas.scene().removeItem(self.marker) del self.marker self.disconnect_projectsignals() for action in self.actions: self.iface.removePluginMenu(self.tr(u"&Earthmine"), action) self.iface.removeToolBarIcon(action) del self.toolbar self.iface.removeDockWidget(self.viewer) self.viewer.deleteLater() def disconnect_projectsignals(self): safe_disconnect(QgsMapLayerRegistry.instance().layerWasAdded, self.connect_layer_signals) safe_disconnect(QgsMapLayerRegistry.instance().layersRemoved, self.layers_removed) safe_disconnect(self.canvas.layersChanged, self.layers_changed) safe_disconnect(self.iface.projectRead, self.connect_signals) safe_disconnect(self.canvas.selectionChanged, self.selection_changed) safe_disconnect(self.canvas.selectionChanged, self.viewer.selection_changed) def clear_bands(self): self.tempband.reset(QGis.Line) self.tempbandpoints.reset(QGis.Point) def visible_layers(self): """ Return the visible layers shown in the map canvas :return: """ return (layer for layer, visible in self.layers_with_states() if visible) def layers_with_states(self): for layer in maplayers(): if not layer.type() == QgsMapLayer.VectorLayer: continue if not layer.geometryType() in [QGis.Point, QGis.Line]: continue yield layer, self.legend.isLayerVisible(layer) def _layer_feature_added(self, featureid): layer = self.sender() if not layer: return self.layer_feature_added(layer, featureid) def layer_feature_added(self, layer, featureid): if not self.viewer: return feature = layer.getFeatures(QgsFeatureRequest(featureid)).next() renderer = layer.rendererV2() transform = self.coordinatetransform(layer) featuredata = to_feature_data(layer.id(), feature, renderer, transform) geomtype = layer.geometryType() layerdata = dict(id=layer.id(), geomtype=QGis.vectorGeometryType(geomtype)) self.viewer.load_features(layerdata, featuredata) def _layer_feature_delete(self, featureid): layer = self.sender() if not layer: return self.layer_feature_delete(layer, featureid) def layer_feature_delete(self, layer, featureid): if not self.viewer: return self.viewer.remove_feature(layer.id(), featureid) def _layer_geometry_changed(self, featureid, geometry): layer = self.sender() if not layer: return self.layer_geometry_changed(layer, featureid, geometry) def layer_geometry_changed(self, layer, featureid, geometry): if not self.viewer: return geomtype = layer.geometryType() if geomtype == QGis.Point: geom = geometry.asPoint() transform = self.coordinatetransform(layer) point = transform.transform(geom, QgsCoordinateTransform.ReverseTransform) location = dict(lat=point.y(), lng=point.x()) self.viewer.edit_feature(layer.id(), featureid, [location]) elif geomtype == QGis.Line: self.layer_feature_delete(layer, featureid) self.layer_feature_added(layer, featureid) def connect_layer_signals(self, layer): if not layer.type() == QgsMapLayer.VectorLayer: return layer.featureAdded.connect(self._layer_feature_added) layer.featureDeleted.connect(self._layer_feature_delete) layer.editingStarted.connect(self.layer_editstate_changed) layer.editingStopped.connect(self.layer_editstate_changed) # HACK The new style doesn't work here # http://hub.qgis.org/issues/6573 signal = SIGNAL("geometryChanged(QgsFeatureId, QgsGeometry&)") self.connect(layer, signal, self._layer_geometry_changed) self.load_layer_features(layers=[layer]) def layer_editstate_changed(self): layer = self.sender() if layer == self.iface.activeLayer(): self.viewer.layer_changed(layer) def disconnect_signals(self): self.disconnect_projectsignals() for layer in maplayers(): if not layer.type() == QgsMapLayer.VectorLayer: return safe_disconnect(layer.featureAdded, self._layer_feature_added) safe_disconnect(layer.featureDeleted, self._layer_feature_delete) safe_disconnect(layer.editingStarted, self.layer_editstate_changed) safe_disconnect(layer.editingStopped, self.layer_editstate_changed) # HACK The new style doesn't work here # http://hub.qgis.org/issues/6573 signal = SIGNAL("geometryChanged(QgsFeatureId, QgsGeometry&)") self.disconnect(layer, signal, self._layer_geometry_changed) def connect_signals(self): for layer in maplayers(): self.connect_layer_signals(layer) self.center_on_canvas() def set_viewer_location(self, point, mousebutton): transform = self.coordinatetransform() point = transform.transform(point, QgsCoordinateTransform.ReverseTransform) self.viewer.set_location(point) def distancearea(self): area = QgsDistanceArea() dest = self.canvas.mapRenderer().destinationCrs() area.setSourceCrs(dest) return area, dest.mapUnits() def coordinatetransform(self, layer=None): """ Return the transform for WGS84 -> QGIS projection. """ source = QgsCoordinateReferenceSystem() source.createFromWkt( 'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]' ) if not layer: dest = self.canvas.mapRenderer().destinationCrs() else: dest = layer.crs() transform = QgsCoordinateTransform(source, dest) return transform def earthmine_settings(self): settings = {} with settinggroup(self.settings, "plugins/Earthmine"): for key in ["serviceUrl", "baseDataUrl", "apiKey", "secretKey", "viewerUrl"]: if not self.settings.contains(key): raise EarthmineSettingsError("{} not set".format(key)) value = self.settings.value(key, type=str) if value is None: raise EarthmineSettingsError("{} not set".format(key)) settings[key] = value return settings @pyqtSlot() def ready(self): """ Called when the viewer is ready to be started. At this point the viewer hasn't been loaded so no other methods apart from startViewer will be handled. """ settings = self.earthmine_settings() self.viewer.startViewer(settings) @pyqtSlot() def viewerReady(self): """ Called once the viewer is loaded and ready to get location events. """ self.disconnect_signals() self.connect_signals() self.iface.projectRead.connect(self.connect_signals) self.canvas.layersChanged.connect(self.layers_changed) self.canvas.selectionChanged.connect(self.selection_changed) self.canvas.selectionChanged.connect(self.viewer.selection_changed) QgsMapLayerRegistry.instance().layersRemoved.connect(self.layers_removed) QgsMapLayerRegistry.instance().layerWasAdded.connect(self.connect_layer_signals) self.center_on_canvas() self.viewer.activelayercombo.setLayer(self.iface.activeLayer()) def center_on_canvas(self): point = self.canvas.extent().center() transform = self.coordinatetransform() point = transform.transform(point, QgsCoordinateTransform.ReverseTransform) self.viewer.set_location(point) self.viewer.infoaction.toggle() def selection_changed(self, layer): ids = [feature.id() for feature in layer.selectedFeatures()] if not ids: self.viewer.clear_selection(layer.id()) else: self.viewer.set_selection(layer.id(), ids) def layers_changed(self): layerstates = self.layers_with_states() for layer, visible in layerstates: layerid = layer.id() viewerloaded = self.viewer.layer_loaded(layerid) QgsMessageLog.instance().logMessage(layerid, "Earthmine") QgsMessageLog.instance().logMessage("Viewer State:" + str(viewerloaded), "Earthmine") QgsMessageLog.instance().logMessage("QGIS State:" + str(visible), "Earthmine") if (viewerloaded and visible) or (not viewerloaded and not visible): QgsMessageLog.instance().logMessage("Ignoring as states match", "Earthmine") continue if viewerloaded and not visible: QgsMessageLog.instance().logMessage( "Clearing layer because viewer loaded and disabled in QGIS", "Earthmine" ) self.viewer.clear_layer_features(layerid) continue if not viewerloaded and visible: QgsMessageLog.instance().logMessage("Loading layer", "Earthmine") self.load_layer_features(layers=[layer]) continue def layers_removed(self, layers): for layerid in layers: self.viewer.clear_layer_features(layerid) @pyqtSlot(str, float, float) def viewChanged(self, event, yaw, angle): self.marker.setAngle(angle) self.marker.setYaw(yaw) @pyqtSlot(str, str) def getInfo(self, layerid, featureid): featureid = int(featureid) activelayer = self.iface.activeLayer() if not activelayer: return activetool = self.viewer.active_tool() if not activetool in ["Info", "Select"]: return # Only show information for the active layer if not layerid == activelayer.id(): return layer = layer_by_id(layerid) if activetool == "Select": layer.setSelectedFeatures([featureid]) elif activetool == "Info": rq = QgsFeatureRequest(featureid) feature = layer.getFeatures(rq).next() dlg = get_feature_form(layer, feature) if dlg.dialog().exec_(): self.canvas.refresh() @pyqtSlot(str, str, float, float, bool) def featureMoved(self, layerid, featureid, lat, lng, end): layer = layer_by_id(layerid) transform = self.coordinatetransform(layer) point = transform.transform(lng, lat) if not end: self.movingband.show() self.movingband.setToGeometry(QgsGeometry.fromPoint(point), layer) self.movingband.updatePosition() self.movingband.update() else: self.movingband.hide() feature = feature_by_id(layer, featureid) startpoint = feature.geometry().asPoint() dx = point.x() - startpoint.x() dy = point.y() - startpoint.y() layer.beginEditCommand("Feature Moved") # Block signals for this move as the geometry changed signal will re add the geometry on use. layer.blockSignals(True) layer.translateFeature(feature.id(), dx, dy) layer.blockSignals(False) self.canvas.refresh() layer.endEditCommand() @pyqtSlot(str, str) def onError(self, message, stacktrace=None): self.iface.messageBar().pushMessage("Earthmine", message, QgsMessageBar.WARNING) QgsMessageLog.logMessage(stacktrace, "Earthmine") @pyqtSlot(float, float, float) def addPoint(self, lat, lng, z): layer = self.viewer.active_layer if not layer.isEditable(): self.iface.messageBar().pushMessage( "Earthmine", "Selected layer isn't editable. Please enable edit mode to add features", duration=3, level=QgsMessageBar.WARNING, ) return transform = self.coordinatetransform(layer) point = transform.transform(lng, lat) geom = QgsGeometry.fromPoint(point) self.add_feature(layer, geom, z) def add_feature(self, layer, geom, z=None): feature = QgsFeature(layer.pendingFields()) if z and self.viewer.copyZvalue: try: feature["Z"] = z except KeyError: QgsMessageLog.log("No Z found on layer {}".format(layer.name())) pass feature.setGeometry(geom) dlg = get_feature_form(layer, feature, isadd=True) if dlg.dialog().exec_(): self.canvas.refresh() @pyqtSlot(str, bool, str) def drawLine(self, points, end, stats): points = json.loads(points) stats = json.loads(stats) QgsMessageLog.logMessage(str(stats), "Earthmine") self.tempband.reset(QGis.Line) self.tempbandpoints.reset(QGis.Point) color = QColor(self.viewer.current_action_color) self.tempband.setColor(color) self.tempbandpoints.setColor(color) layer = self.viewer.active_layer transform = self.coordinatetransform(layer) earthminepoints = [] for point in points: newpoint = transform.transform(point["lng"], point["lat"]) self.tempband.addPoint(newpoint) self.tempbandpoints.addPoint(newpoint) empoint = EarthminePoint(newpoint, point) earthminepoints.append(empoint) if end and not self.viewer.mode == "Vertical": geom = self.tempband.asGeometry() self.add_feature(layer, geom) self.clear_bands() self.viewer.geom = EarthmineLine(earthminepoints, stats) self.tempband.show() self.tempbandpoints.show() @pyqtSlot(str, str, str, float) def locationChanged(self, lat, lng, yaw, angle): transform = self.coordinatetransform() point = transform.transform(float(lng), float(lat)) self.marker.setCenter(point) yaw = float(yaw) self.marker.setAngle(angle) self.marker.setYaw(yaw) self.marker.setTracking(self.viewer.tracking) if self.marker.tracking: rect = QgsRectangle(point, point) extentlimt = QgsRectangle(self.canvas.extent()) extentlimt.scale(0.95) if not extentlimt.contains(point): self.canvas.setExtent(rect) self.canvas.refresh() # Clear old features self.viewer.clear_features() self.load_layer_features(point) def update_earthmine_features(self, viewfeatures): self.viewer.clear_features() if viewfeatures: self.load_layer_features() def load_layer_features(self, point=None, layers=None): # TODO Move this logic into the viewer and let it track it's position if point is None and self.marker.map_pos is None: return if point is None: point = self.marker.map_pos area, units = self.distancearea() rect = search_area(units, area, point) if layers is None: layers = self.visible_layers() for layer in layers: transform = self.coordinatetransform(layer) # Transform the rect source = self.canvas.mapRenderer().destinationCrs() dest = layer.crs() recttransform = QgsCoordinateTransform(source, dest) rect = recttransform.transformBoundingBox(rect) features = list(get_features_in_area(layer, rect, transform, self.canvas.mapSettings())) geomtype = layer.geometryType() layerdata = dict(id=layer.id(), geomtype=QGis.vectorGeometryType(geomtype)) self.viewer.load_features(layerdata, features) # noinspection PyMethodMayBeStatic def tr(self, message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate("EarthMineQGIS", message) def add_action( self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None, ): """Add a toolbar icon to the InaSAFE toolbar. :param icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :type icon_path: str :param text: Text that should be shown in menu items for this action. :type text: str :param callback: Function to be called when the action is triggered. :type callback: function :param enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :type enabled_flag: bool :param add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :type add_to_menu: bool :param add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :type add_to_toolbar: bool :param status_tip: Optional text to s, "Earhtmine"how in a popup when mouse pointer hovers over the action. :type status_tip: str :param parent: Parent widget for the new action. Defaults None. :type parent: QWidget :param whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.actions list. :rtype: QAction """ icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.iface.addPluginToMenu(self.menu, action) self.actions.append(action) return action def open_viewer(self): """Run method that performs all the real work""" try: settings = self.earthmine_settings() except EarthmineSettingsError as ex: self.onError(ex.message) self.show_settings() return url = settings["viewerUrl"] if not url.startswith("http"): url = url.replace("\\\\", "\\") url = QUrl.fromLocalFile(url) else: url = QUrl(url) if not self.viewer.isVisible(): self.iface.addDockWidget(Qt.RightDockWidgetArea, self.viewer) self.viewer.loadviewer(url) def show_settings(self): self.settingsdialog.show()
class FinderBox(QComboBox): running = False toFinish = 0 searchStarted = pyqtSignal() searchFinished = pyqtSignal() def __init__(self, finders, iface, parent=None): self.iface = iface self.mapCanvas = iface.mapCanvas() self.rubber = QgsRubberBand(self.mapCanvas) self.rubber.setColor(QColor(255, 255, 50, 200)) self.rubber.setIcon(self.rubber.ICON_CIRCLE) self.rubber.setIconSize(15) self.rubber.setWidth(4) self.rubber.setBrushStyle(Qt.NoBrush) QComboBox.__init__(self, parent) self.setEditable(True) self.setInsertPolicy(QComboBox.InsertAtTop) self.setMinimumHeight(27) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.insertSeparator(0) self.lineEdit().returnPressed.connect(self.search) self.resultView = QTreeView() self.resultView.setHeaderHidden(True) self.resultView.setMinimumHeight(300) self.resultView.activated.connect(self.itemActivated) self.resultView.pressed.connect(self.itemPressed) self.setView(self.resultView) self.resultModel = ResultModel(self) self.setModel(self.resultModel) self.finders = finders for finder in self.finders.values(): finder.resultFound.connect(self.resultFound) finder.limitReached.connect(self.limitReached) finder.finished.connect(self.finished) finder.message.connect(self.message) def __del__(self): if self.rubber: self.iface.mapCanvas().scene().removeItem(self.rubber) del self.rubber def search(self): if self.running: return toFind = self.lineEdit().text() if not toFind or toFind == '': return self.running = True self.searchStarted.emit() self.resultModel.clearResults() self.resultModel.truncateHistory(MySettings().value("historyLength")) self.resultModel.setLoading(True) self.showPopup() QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) # create categories in special order and count activated ones for finder in self.finders.values(): if finder.activated(): self.resultModel.addResult(finder.name) bbox = self.mapCanvas.fullExtent() for finder in self.finders.values(): if finder.activated(): finder.start(toFind, bbox=bbox) def stop(self): for finder in self.finders.values(): if finder.isRunning(): finder.stop() def resultFound(self, finder, layername, value, geometry, srid): self.resultModel.addResult(finder.name, layername, value, geometry, srid) self.resultView.expandAll() def limitReached(self, finder, layername): self.resultModel.addEllipsys(finder.name, layername) def finished(self, finder): for finder in self.finders.values(): if finder.isRunning(): return self.running = False self.searchFinished.emit() self.resultModel.setLoading(False) QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) def message(self, finder, message, level): self.iface.messageBar().pushMessage("Quick Finder", message, level, 3) def itemActivated(self, index): item = self.resultModel.itemFromIndex(index) self.showItem(item) def itemPressed(self, index): item = self.resultModel.itemFromIndex(index) if QApplication.mouseButtons() == Qt.LeftButton: self.showItem(item) def showItem(self, item): if isinstance(item, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) geometry = self.transformGeom(item) self.rubber.reset(geometry.type()) self.rubber.setToGeometry(geometry, None) self.zoomToRubberBand() return if isinstance(item, GroupItem): child = item.child(0) if isinstance(child, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) self.rubber.reset(child.geometry.type()) for i in xrange(0, item.rowCount()): geometry = self.transformGeom(item.child(i)) self.rubber.addGeometry(geometry, None) self.zoomToRubberBand() return if item.__class__.__name__ == 'QStandardItem': self.resultModel.setSelected(None, self.resultView.palette()) self.rubber.reset() return def transformGeom(self, item): geometry = item.geometry src_crs = QgsCoordinateReferenceSystem() src_crs.createFromSrid(item.srid) dest_crs = self.mapCanvas.mapRenderer().destinationCrs() geom = item.geometry geom.transform( QgsCoordinateTransform(src_crs, dest_crs) ) return geom def zoomToRubberBand(self): geom = self.rubber.asGeometry() if geom: rect = geom.boundingBox() rect.scale(1.5) self.mapCanvas.setExtent(rect) self.mapCanvas.refresh()
class TrackWidget(QWidget, Ui_Track): def __init__(self, parent=None): super(TrackWidget, self).__init__(parent) self.setupUi(self) self.title = "Display track" self.canvas = None self.band = None self.color_btn = None self.center = False self.position = None self.geom_type = None self.marker = None self.hidden = False self.centerButton.setEnabled(False) icon = QIcon(":/resources/mActionSave.svg") self.save_track_pushButton.setIcon(icon) self.save_track_pushButton.setToolTip("Save Track") self.save_track_pushButton.clicked.connect(self.save_track) def init(self, title, canvas, default_color, geom_type, marker): self.canvas = canvas self.geom_type = geom_type self.track_groupBox.setTitle(title) if marker: # Add marker self.marker = marker self.with_marker = True else: self.with_marker = False # Add rubber band self.band = QgsRubberBand(self.canvas, self.geom_type) if self.geom_type == QgsWkbTypes.PointGeometry: self.band.setIcon(QgsRubberBand.ICON_CIRCLE) self.band.setIconSize(12) else: self.band.setWidth(3) # Add color button widget for picking color self.color_btn = QgsColorButton() self.horizontal_layout_color.insertWidget(1, self.color_btn, 0, Qt.AlignLeft) self.color_btn.colorChanged.connect(self.color_changed) self.color_btn.setDefaultColor(default_color) self.color_btn.setColor(default_color) # Set signals self.centerButton.clicked.connect(self.center_to_location) self.clearTrackButton.clicked.connect(self.clear_track) def color_changed(self): transparent_color = QColor(self.color_btn.color()) transparent_color.setAlpha(80) self.band.setColor(transparent_color) if self.with_marker: self.marker.set_color(QColor(self.color_btn.color())) def add_position(self, position): self.band.addPoint(position) def track_update_canvas(self, position, heading): self.centerButton.setEnabled(True) self.position = position self.add_position(position) if self.with_marker: self.marker.set_center(position, heading) if self.isHidden(): if self.with_marker: self.marker.hide() self.band.hide() else: if self.with_marker: self.marker.show() self.band.show() def center_to_location(self): """ Center to last received position on the map. """ rect = QgsRectangle(self.position, self.position) self.canvas.setExtent(rect) self.canvas.zoomScale(400) self.canvas.refresh() def hide_band(self): self.band.hide() def hide_marker(self): if self.with_marker: self.marker.hide() def clear_track(self): self.band.reset(self.geom_type) def save_track(self): """ Save the track to disk """ layer_name, selected_filter = QFileDialog.getSaveFileName(None, 'Save Track', "", 'Shapefile (*.shp);;KML (*.kml);;GPX (*.gpx)') if layer_name != '': if self.geom_type == QgsWkbTypes.PointGeometry: geometric_object = "MultiPoint?crs=epsg:4326" else: geometric_object = "LineString?crs=epsg:4326" layer = QgsVectorLayer( geometric_object, layer_name, "memory") feature = QgsFeature() feature.setGeometry(self.band.asGeometry()) layer.dataProvider().addFeatures([feature]) if selected_filter == "Shapefile (*.shp)": if not layer_name.endswith('.shp'): layer_name = layer_name + '.shp' ret = QgsVectorFileWriter.writeAsVectorFormat(layer, layer_name, "utf-8", QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId), "ESRI Shapefile") if ret == QgsVectorFileWriter.NoError: logger.info(layer.name() + " saved to " + layer_name) elif selected_filter == "KML (*.kml)": if not layer_name.endswith('.kml'): layer_name = layer_name + '.kml' QgsVectorFileWriter.writeAsVectorFormat(layer, layer_name, "utf-8", QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId), "KML") elif selected_filter == "GPX (*.gpx)": if not layer_name.endswith('.gpx'): layer_name = layer_name + '.gpx' ds_options = list() ds_options.append("GPX_USE_EXTENSIONS=TRUE") QgsVectorFileWriter.writeAsVectorFormat(layer, layer_name, "utf-8", QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId), "GPX", datasourceOptions=ds_options) def close(self): self.hide_band() self.hide_marker()
class osmSearchDialog(QDockWidget , Ui_osmSearch ): def __init__(self,iface): self.iface = iface QDockWidget.__init__(self) self.setupUi(self) self.iface.addDockWidget(Qt.BottomDockWidgetArea,self) self.canvas = self.iface.mapCanvas() self.rb = QgsRubberBand(self.canvas, QGis.Point) self.rb.setColor(QColor( 255, 0, 0, 150 )) self.searchCacheLimit = 1000 self.wgs84 = QgsCoordinateReferenceSystem() self.wgs84.createFromSrid(4326) self.proj = self.canvas.mapRenderer().destinationCrs() self.transform = QgsCoordinateTransform(self.wgs84, self.proj) self.bSearch.clicked.connect(self.startSearch) self.eOutput.currentItemChanged.connect(self.itemChanged) self.eOutput.clickedOutsideOfItems.connect(self.itemChanged) self.eText.cleared.connect(self.clearEdit) self.canvas.mapRenderer().destinationSrsChanged.connect(self.crsChanged) self.iface.newProjectCreated.connect(self.clearEdit) self.iface.projectRead.connect(self.clearEdit) self.cbCenter.stateChanged.connect(self.autocenter) db = cacheDB() self.autocompleteList = db.getAutocompleteList() db.closeConnection() self.completer = QCompleter(self.autocompleteList) self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.eText.setCompleter(self.completer) def startSearch(self): text = self.eText.text().encode('utf-8') if text == "": self.clearEdit() #url = 'http://open.mapquestapi.com/nominatim/v1/search.php' url = 'http://nominatim.openstreetmap.org/search' params = urllib.urlencode({'q': text,'format': 'json','polygon_text':'1'}) response = json.load(urllib2.urlopen(url+'?'+params)) self.loadData(response) def loadData(self, data): self.rb.reset(QGis.Point) self.eOutput.clear() items = [] for d in data: try: geometry = d['geotext'] except KeyError: geometry = 'POINT(%s %s)' % (d['lon'], d['lat']) item = QTreeWidgetItem([d['display_name'], d['type']]) item.setData(0, Qt.UserRole, geometry) if geometry.lower().startswith('point'): item.setIcon(0, QgsApplication.getThemeIcon('/mIconPointLayer.svg')) elif geometry.lower().startswith('linestring'): item.setIcon(0, QgsApplication.getThemeIcon('/mIconLineLayer.svg')) elif geometry.lower().startswith('polygon'): item.setIcon(0, QgsApplication.getThemeIcon('/mIconPolygonLayer.svg')) items.append(item) if items: self.eOutput.insertTopLevelItems(0, items) self.addSearchTerm(unicode(self.eText.text().lower())) else: self.iface.messageBar().pushMessage('Nothing was found!', QgsMessageBar.CRITICAL, 2) def itemChanged(self, current=None, previous=None): if current: wkt = str(current.data(0,Qt.UserRole)) geom = QgsGeometry.fromWkt(wkt) if self.proj.srsid() != 4326: try: geom.transform(self.transform) except: self.iface.messageBar().pushMessage('CRS transformation error!', QgsMessageBar.CRITICAL, 2) self.rb.reset(QGis.Point) return self.rb.setToGeometry(geom, None) if self.cbCenter.isChecked(): self.moveCanvas(geom.centroid().asPoint(), self.canvas.extent()) else: self.rb.reset(QGis.Point) self.eOutput.setCurrentItem(None) def crsChanged(self): self.proj = self.canvas.mapRenderer().destinationCrs() self.transform = QgsCoordinateTransform(self.wgs84, self.proj) def clearEdit(self): self.eOutput.clear() self.eText.clear() if hasattr(self, 'rb'): self.rb.reset(QGis.Point) def setCompleter(self): self.completer.model().setStringList(self.autocompleteList) def addSearchTerm(self, text): if not text in self.autocompleteList: self.autocompleteList.append(text) self.setCompleter() while len(self.autocompleteList) > self.searchCacheLimit: self.autocompleteList.pop(0) def autocenter(self, state): if state and self.rb.size(): self.moveCanvas(self.rb.asGeometry().centroid().asPoint(), self.canvas.extent()) def moveCanvas(self, newCenter, oldExtent): newExtent = QgsRectangle(oldExtent) newExtent.scale(1, newCenter) self.canvas.setExtent(newExtent) self.canvas.refresh()
class MapTool(QgsMapTool): MODE_NONE = 0 MODE_PAN = 1 MODE_ROTATE = 2 MODE_SCALE = 3 MODE_SCALE_X = 4 MODE_SCALE_Y = 5 MODE_PAN_RESULT = 6 MODE_NODE = 7 NODE_NAMES = ['A', 'B', 'C', 'D'] def __init__(self, widget): QgsMapTool.__init__(self, widget.canvas) self.widget = widget self.canvas = widget.canvas self.mode = self.MODE_NONE self.selected_node = None # clicked point self.p0 = None # centre rectangle self.pX = None # rectangle vertices (handles) self.pA = None # hg self.pB = None # hd self.pC = None # bd self.pD = None # bg self.zoneWidth = None self.zoneDepth = None # eye (rotation) self.pY = None # rectangle self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.rb.setStrokeColor(Qt.blue) self.rb.setWidth(3) self.rbFoc = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.rbFoc.setStrokeColor(Qt.blue) self.rbFoc.setWidth(1) # SCALE nodes self.rbPA = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry) self.rbPA.setColor(Qt.red) self.rbPA.setWidth(8) self.rbPB = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry) self.rbPB.setColor(Qt.red) self.rbPB.setWidth(8) self.rbPC = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry) self.rbPC.setColor(Qt.red) self.rbPC.setWidth(8) self.rbPD = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry) self.rbPD.setColor(QColor(255, 50, 150, 255)) self.rbPD.setWidth(8) # scale Y node self.rbPH = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry) self.rbPH.setColor(Qt.red) self.rbPH.setWidth(8) # scale X node self.rbPL = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry) self.rbPL.setColor(Qt.red) self.rbPL.setWidth(8) # final pan self.rbPan = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry) self.rbPan.setColor(QColor(0, 200, 50, 255)) self.rbPan.setWidth(8) # ROTATE node self.rbPY = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry) self.rbPY.setColor(Qt.blue) self.rbPY.setWidth(6) self.rotation = 0.0 # cutting lines self.rbLines = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.rbLines.setColor(QColor(40, 180, 30, 255)) self.rbLines.setWidth(1.5) # plots self.rbPlots = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.rbPlots.setStrokeColor(QColor(200, 120, 70, 150)) self.rbPlots.setWidth(0.8) self.rubbers = [ self.rb, self.rbPA, self.rbPB, self.rbPC, self.rbPD, self.rbPY, self.rbPH, self.rbPL, self.rbPan, self.rbLines, self.rbPlots, self.rbFoc, ] self.rowLines = None self.columnLines = None self.allLines = None def hide(self): for rb in self.rubbers: rb.reset() def updateRubberGeom(self): if self.pA is None: return self.zoneWidth = self.pA.distance(self.pB) self.zoneDepth = self.pA.distance(self.pD) self.pM = QgsPointXY((self.pC.x() + self.pD.x()) / 2, (self.pC.y() + self.pD.y()) / 2) self.d0 = self.pM.distance(self.pY) # self.widget.updateZ(self.pY) self.rb.setToGeometry( QgsGeometry.fromPolygonXY( [[self.pD, self.pA, self.pB, self.pC, self.pD]])) self.rbFoc.setToGeometry( QgsGeometry.fromPolylineXY([self.pD, self.pY, self.pC])) for p, rb in [ [self.pA, self.rbPA], [self.pB, self.rbPB], [self.pC, self.rbPC], [self.pD, self.rbPD], [self.pY, self.rbPY], [self.pH, self.rbPH], [self.pL, self.rbPL], ]: rb.setToGeometry(QgsGeometry.fromPointXY(p)) leftEdge = (QgsGeometry.fromPolylineXY([ self.pA, self.pD ]).densifyByCount(self.widget.rowCount.value() - 1).asPolyline()) rightEdge = (QgsGeometry.fromPolylineXY([ self.pB, self.pC ]).densifyByCount(self.widget.rowCount.value() - 1).asPolyline()) # Plot edges lines polyline = list(zip(leftEdge, rightEdge)) backSide = (QgsGeometry.fromPolylineXY([ self.pA, self.pB ]).densifyByCount(self.widget.columnCount.value() - 1).asPolyline()) frontSide = (QgsGeometry.fromPolylineXY([ self.pD, self.pC ]).densifyByCount(self.widget.columnCount.value() - 1).asPolyline()) polylineX = list(zip(frontSide[:], backSide[:])) self.finalWidth = self.zoneWidth self.rowLines = polyline self.columnLines = polylineX self.allLines = polyline + polylineX self.rbLines.setToGeometry( QgsGeometry.fromMultiPolylineXY( polylineX + polyline + polyline[::max(1, 1 + len(polyline))])) if self.widget.cbReverseRows.isChecked(): if self.widget.cbReverseColumns.isChecked(): self.rbPC.setColor(Qt.red) self.rbPD.setColor(Qt.red) self.rbPA.setColor(Qt.red) self.rbPB.setColor(QColor(0, 200, 150, 255)) else: self.rbPC.setColor(Qt.red) self.rbPD.setColor(Qt.red) self.rbPB.setColor(Qt.red) self.rbPA.setColor(QColor(0, 200, 150, 255)) else: if self.widget.cbReverseColumns.isChecked(): self.rbPA.setColor(Qt.red) self.rbPB.setColor(Qt.red) self.rbPD.setColor(Qt.red) self.rbPC.setColor(QColor(0, 200, 150, 255)) else: self.rbPA.setColor(Qt.red) self.rbPB.setColor(Qt.red) self.rbPC.setColor(Qt.red) self.rbPD.setColor(QColor(0, 200, 150, 255)) self.widget.alert.setText("Total plots: {}".format( self.widget.columnCount.value() * self.widget.rowCount.value())) def getLines(self): return QgsGeometry.fromMultiPolylineXY(self.rowLines) def getSampleLines(self): return ( [self.rowLines[0], self.rowLines[1]] + self.rowLines[2:-1][::max(1, 1 + int((len(self.rowLines) - 3) / 9))] + [self.rowLines[-1]]) def newRubber(self): if self.pX is not None: self.updateRubberGeom() return # default parameters h = 2 * self.widget.canvas.extent().height() / 3 / 20 # first bbox, according to current view h = self.canvas.extent().height() / 6 c = self.canvas.extent().center() rubberExtent = QgsRectangle(QgsPointXY(c.x() - h, c.y() - h), QgsPointXY(c.x() + h, c.y() + h)) self.rotation = 0.0 width = rubberExtent.xMaximum() - rubberExtent.xMinimum() height = rubberExtent.yMaximum() - rubberExtent.yMinimum() # centre rectangle self.pX = QgsPointXY(rubberExtent.xMinimum() + width / 2, rubberExtent.yMinimum() + height / 2) self.pA = QgsPointXY(rubberExtent.xMinimum(), rubberExtent.yMaximum()) self.pB = QgsPointXY(rubberExtent.xMaximum(), rubberExtent.yMaximum()) self.pC = QgsPointXY(rubberExtent.xMaximum(), rubberExtent.yMinimum()) self.pD = QgsPointXY(rubberExtent.xMinimum(), rubberExtent.yMinimum()) # handles H / L self.pH = QgsPointXY((self.pA.x() + self.pB.x()) / 2, (self.pA.y() + self.pB.y()) / 2) self.pL = QgsPointXY((self.pB.x() + self.pC.x()) / 2, (self.pB.y() + self.pC.y()) / 2) # eye (rotation) self.pY = QgsPointXY(self.pX.x(), self.pX.y() - 2 * height / 3) self.pM = QgsPointXY((self.pC.x() + self.pD.x()) / 2, (self.pC.y() + self.pD.y()) / 2) self.rotation_init = self.rotation self.pA_init = QgsPointXY(self.pA) self.pB_init = QgsPointXY(self.pB) self.pC_init = QgsPointXY(self.pC) self.pD_init = QgsPointXY(self.pD) self.pX_init = QgsPointXY(self.pX) self.pY_init = QgsPointXY(self.pY) self.pH_init = QgsPointXY(self.pH) self.pL_init = QgsPointXY(self.pL) self.updateRubberGeom() def canvasPressEvent(self, event): x = event.pos().x() y = event.pos().y() self.p0 = self.canvas.getCoordinateTransform().toMapCoordinates(x, y) distPA = self.p0.distance(self.pA) / self.canvas.mapUnitsPerPixel() distPB = self.p0.distance(self.pB) / self.canvas.mapUnitsPerPixel() distPC = self.p0.distance(self.pC) / self.canvas.mapUnitsPerPixel() distPD = self.p0.distance(self.pD) / self.canvas.mapUnitsPerPixel() distPY = self.p0.distance(self.pY) / self.canvas.mapUnitsPerPixel() distPH = self.p0.distance(self.pH) / self.canvas.mapUnitsPerPixel() distPL = self.p0.distance(self.pL) / self.canvas.mapUnitsPerPixel() edit_individual_node = self.widget.cbIndividualNode.isChecked() if distPA < 6 or distPB < 6 or distPC < 6 or distPD < 6: if edit_individual_node: self.mode = self.MODE_NODE val, idx = min( (val, idx) for (idx, val) in enumerate([distPA, distPB, distPC, distPD])) self.selected_node = self.NODE_NAMES[idx] else: self.mode = self.MODE_SCALE return if distPH < 6: self.mode = self.MODE_SCALE_Y return if distPL < 6: self.mode = self.MODE_SCALE_X return if distPY < 6: self.mode = self.MODE_ROTATE return if self.rb.asGeometry().contains(self.p0): self.mode = self.MODE_PAN return def canvasMoveEvent(self, event): if self.mode == self.MODE_NONE: return x = event.pos().x() y = event.pos().y() pt = self.canvas.getCoordinateTransform().toMapCoordinates(x, y) dx = pt.x() - self.p0.x() dy = pt.y() - self.p0.y() # node name if self.mode == self.MODE_NODE: if self.selected_node == 'A': self.pA.setX(self.pA_init.x() + dx) self.pA.setY(self.pA_init.y() + dy) elif self.selected_node == 'B': self.pB.setX(self.pB_init.x() + dx) self.pB.setY(self.pB_init.y() + dy) elif self.selected_node == 'C': self.pC.setX(self.pC_init.x() + dx) self.pC.setY(self.pC_init.y() + dy) elif self.selected_node == 'D': self.pD.setX(self.pD_init.x() + dx) self.pD.setY(self.pD_init.y() + dy) # pan mode if self.mode == self.MODE_PAN: for p, p_ini in [ [self.pA, self.pA_init], [self.pB, self.pB_init], [self.pC, self.pC_init], [self.pD, self.pD_init], [self.pX, self.pX_init], [self.pY, self.pY_init], [self.pH, self.pH_init], [self.pL, self.pL_init], ]: p.setX(p_ini.x() + dx) p.setY(p_ini.y() + dy) # horizontal + vertical sizing if self.mode == self.MODE_SCALE: d_old = self.pA_init.distance(self.pX_init) d_new = pt.distance(self.pX_init) dd = d_new / d_old for p, p_ini in [ [self.pA, self.pA_init], [self.pB, self.pB_init], [self.pC, self.pC_init], [self.pD, self.pD_init], [self.pY, self.pY_init], [self.pH, self.pH_init], [self.pL, self.pL_init], ]: dx = dd * (p_ini.x() - self.pX.x()) dy = dd * (p_ini.y() - self.pX.y()) p.setX(self.pX.x() + dx) p.setY(self.pX.y() + dy) # horizontal sizing if self.mode == self.MODE_SCALE_X: d_old = self.pL_init.distance(self.pX_init) d_new = pt.distance(self.pX_init) dd = d_new / d_old if dd < 0.001: dd = 0.001 dx = dd * (self.pL_init.x() - self.pX.x()) dy = dd * (self.pL_init.y() - self.pX.y()) self.pL.setX(self.pX.x() + dx) self.pL.setY(self.pX.y() + dy) centre = self.pH for p, p_ini in [[self.pA, self.pA_init], [self.pB, self.pB_init]]: dx = dd * (p_ini.x() - centre.x()) dy = dd * (p_ini.y() - centre.y()) p.setX(centre.x() + dx) p.setY(centre.y() + dy) centre = self.pM for p, p_ini in [[self.pC, self.pC_init], [self.pD, self.pD_init]]: dx = dd * (p_ini.x() - centre.x()) dy = dd * (p_ini.y() - centre.y()) p.setX(centre.x() + dx) p.setY(centre.y() + dy) # vertical sizing if self.mode == self.MODE_SCALE_Y: d_old = self.pH_init.distance(self.pX_init) d_new = pt.distance(self.pX_init) dd = d_new / d_old if dd < 0.001: dd = 0.001 dx = dd * (self.pH_init.x() - self.pX.x()) dy = dd * (self.pH_init.y() - self.pX.y()) self.pH.setX(self.pX.x() + dx) self.pH.setY(self.pX.y() + dy) centre = self.pL for p, p_ini in [[self.pB, self.pB_init], [self.pC, self.pC_init]]: dx = dd * (p_ini.x() - centre.x()) dy = dd * (p_ini.y() - centre.y()) p.setX(centre.x() + dx) p.setY(centre.y() + dy) centre = QgsPointXY((self.pA.x() + self.pD.x()) / 2, (self.pA.y() + self.pD.y()) / 2) for p, p_ini in [[self.pA, self.pA_init], [self.pD, self.pD_init]]: dx = dd * (p_ini.x() - centre.x()) dy = dd * (p_ini.y() - centre.y()) p.setX(centre.x() + dx) p.setY(centre.y() + dy) if self.mode == self.MODE_ROTATE: self.pY.setX(self.pY_init.x() + dx) self.pY.setY(self.pY_init.y() + dy) azimuth = self.pX.azimuth(pt) theta = azimuth - self.rotation_init + 180 self.rotation = self.rotation_init + theta for a, i in [ [self.pA, self.pA_init], [self.pB, self.pB_init], [self.pC, self.pC_init], [self.pD, self.pD_init], [self.pH, self.pH_init], [self.pL, self.pL_init], ]: A = QgsGeometry.fromPointXY(i) A.rotate(theta, self.pX) a.setX(A.asPoint().x()) a.setY(A.asPoint().y()) self.updateRubberGeom() def canvasReleaseEvent(self, event): self.pA_init = QgsPointXY(self.pA) self.pB_init = QgsPointXY(self.pB) self.pC_init = QgsPointXY(self.pC) self.pD_init = QgsPointXY(self.pD) self.pX_init = QgsPointXY(self.pX) self.pY_init = QgsPointXY(self.pY) self.pH_init = QgsPointXY(self.pH) self.pL_init = QgsPointXY(self.pL) self.rotation_init = self.rotation self.mode = self.MODE_NONE def activate(self): pass def deactivate(self): self.hide() def isZoomTool(self): return False def isTransient(self): return False def isEditTool(self): return True
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(), QGis.Line) 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 = self.canvas.getCoordinateTransform()\ .toMapCoordinates(event.pos().x(), event.pos().y()) 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 = QgsPoint(lp1.x() + width * (yd / length), lp1.y() - width * (xd / length)) pt2 = QgsPoint(lp1.x() - width * (yd / length), lp1.y() + width * (xd / length)) pt3 = QgsPoint(lp2.x() - width * (yd / length), lp2.y() + width * (xd / length)) pt4 = QgsPoint(lp2.x() + width * (yd / length), lp2.y() - width * (xd / length)) self.geometry = QgsGeometry.fromPolygon([[pt1, pt2, pt3, pt4, pt1]]) self.geometryDigitized.emit() self.firstPoint = mousepos
class ObstacleAreaJigCreateArea(QgsMapTool): def __init__(self, canvas, areaType): QgsMapTool.__init__(self, canvas) self.mCanvas = canvas self.areaType = areaType self.annotation = None 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) self.mRubberBand = None self.mRubberBand0 = QgsRubberBand( self.mCanvas, QGis.Polygon ) self.mCursor = Qt.ArrowCursor self.mFillColor = QColor( 254, 178, 76, 63 ) self.mBorderColour = QColor( 254, 58, 29, 100 ) self.mRubberBand0.setBorderColor( self.mBorderColour ) self.polygonGeom = None self.drawFlag = False self.mSnapper = QgsMapCanvasSnapper(canvas) self.resultPolylineArea = PolylineArea() # self.constructionLayer = constructionLayer self.menuString = "" self.isPrimaryPolylineStarted = False self.primaryPolyline = PolylineArea() def createContextMenu(self, areaType, isStarted = False): menu = QMenu() # h = QHBoxLayout(menu) # c = QCalendarWidget() # h.addWidget(c) if areaType == ProtectionAreaType.Primary: actionEnter = QgisHelper.createAction(menu, "Enter", self.menuEnterClick) actionCancel = QgisHelper.createAction(menu, "Cancel", self.menuCancelClick) actionArc = QgisHelper.createAction(menu, "Arc", self.menuArcClick) actionUndo = QgisHelper.createAction(menu, "Undo", self.menuUndoClick) menu.addAction( actionEnter ) menu.addAction( actionCancel ) menu.addAction( actionArc ) menu.addAction( actionUndo ) elif areaType == ProtectionAreaType.Secondary: if not isStarted: actionEnter = QgisHelper.createAction(menu, "Enter", self.menuEnterClick) actionCancel = QgisHelper.createAction(menu, "Cancel", self.menuCancelClick) actionUndo = QgisHelper.createAction(menu, "Undo", self.menuUndoClick) actionPrimatyPolylineStart = QgisHelper.createAction(menu, "Strat INNER edge of the secondary area", self.menuPrimaryStartClick) actionPrimatyPolylineEnd = QgisHelper.createAction(menu, "End INNER edge of the secondary area", self.menuPrimaryEndClick) menu.addAction( actionEnter ) menu.addAction( actionCancel ) menu.addAction( actionUndo ) menu.addAction( actionPrimatyPolylineStart ) menu.addAction( actionPrimatyPolylineEnd ) actionPrimatyPolylineStart.setEnabled(not self.isPrimaryPolylineStarted) actionPrimatyPolylineEnd.setEnabled(self.isPrimaryPolylineStarted) else: actionPrimatyPolylineStart = QgisHelper.createAction(menu, "Strat INNER edge of the secondary area", self.menuPrimaryStartClick) actionPrimatyPolylineEnd = QgisHelper.createAction(menu, "End INNER edge of the secondary area", self.menuPrimaryEndClick) menu.addAction( actionPrimatyPolylineStart ) menu.addAction( actionPrimatyPolylineEnd ) actionPrimatyPolylineStart.setEnabled(not self.isPrimaryPolylineStarted) actionPrimatyPolylineEnd.setEnabled(self.isPrimaryPolylineStarted) return menu def menuPrimaryStartClick(self): self.primaryPolyline = PolylineArea() self.isPrimaryPolylineStarted = True # self.menuString = "Enter" def menuPrimaryEndClick(self): self.isPrimaryPolylineStarted = False # self.menuString = "Enter" def menuEnterClick(self): self.menuString = "Enter" def menuCancelClick(self): self.menuString = "Cancel" def menuArcClick(self): self.menuString = "Arc" def menuUndoClick(self): self.menuString = "Undo" def reset(self): self.Point = None def canvasPressEvent( self, e ): define._messageLabel.setText("") self.menuString = "" 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 if ( self.mRubberBand == None ): self.resultPolylineArea = PolylineArea() self.mRubberBand0.reset( QGis.Polygon ) # define._canvas.clearCache () self.mRubberBand = QgsRubberBand( self.mCanvas, QGis.Polygon ) self.mRubberBand0 = QgsRubberBand( self.mCanvas, QGis.Polygon ) self.mRubberBand.setFillColor( self.mFillColor ) self.mRubberBand.setBorderColor( self.mBorderColour ) self.mRubberBand0.setFillColor( QColor(255, 255, 255, 100) ) self.mRubberBand0.setBorderColor( QColor(0, 0, 0) ) if ( e.button() == Qt.LeftButton ): if self.Point == None: self.mRubberBand.addPoint( self.toMapCoordinates( e.pos() ) ) self.resultPolylineArea.Add(PolylineAreaPoint(self.toMapCoordinates( e.pos() ))) if self.isPrimaryPolylineStarted: self.primaryPolyline.Add(PolylineAreaPoint(self.toMapCoordinates( e.pos() ))) else: self.mRubberBand.addPoint( self.Point ) self.resultPolylineArea.Add(PolylineAreaPoint(self.Point)) if self.isPrimaryPolylineStarted: self.primaryPolyline.Add(PolylineAreaPoint(self.toMapCoordinates( e.pos() ))) else: menu = None if self.areaType == ProtectionAreaType.Secondary and len(self.resultPolylineArea) == 0: menu = self.createContextMenu(self.areaType, True) menu.exec_( define._canvas.mapToGlobal(e.pos() )) return if ( self.mRubberBand.numberOfVertices() > 2 ): self.polygonGeom = self.mRubberBand.asGeometry() else: return # QgsMapToolSelectUtils.setSelectFeatures( self.mCanvas, polygonGeom, e ) menu = self.createContextMenu(self.areaType) menu.exec_( define._canvas.mapToGlobal(e.pos() )) if self.menuString == "Cancel" or self.menuString == "Arc": return elif self.menuString == "Undo": if ( self.mRubberBand.numberOfVertices() > 0 ): self.mRubberBand = None QgisHelper.ClearRubberBandInCanvas(define._canvas) self.mRubberBand = QgsRubberBand( self.mCanvas, QGis.Polygon ) self.mRubberBand.setFillColor( self.mFillColor ) self.mRubberBand.setBorderColor( self.mBorderColour ) self.resultPolylineArea[self.resultPolylineArea.Count - 2].bulge = 0.0 self.resultPolylineArea.pop(self.resultPolylineArea.Count - 1) if self.isPrimaryPolylineStarted and len(self.primaryPolyline) > 0: self.primaryPolyline.pop(self.primaryPolyline.Count - 1) for pt in self.resultPolylineArea.method_14(): self.mRubberBand.addPoint(pt) return elif self.menuString == "Enter": # if self.areaType == ProtectionAreaType.Secondary: # if self.resultPolylineArea.Count != 4: # define._messageLabel.setText("The count of point of Secondary Area must be 4.") # return self.mRubberBand.reset( QGis.Polygon ) self.mRubberBand0.reset( QGis.Polygon ) # define._canvas.clearCache () self.mRubberBand0 = QgsRubberBand( self.mCanvas, QGis.Polygon ) self.mRubberBand0.setFillColor( QColor(255, 255, 255, 100) ) self.mRubberBand0.setBorderColor( QColor(0, 0, 0) ) for pt in self.resultPolylineArea.method_14(): self.mRubberBand0.addPoint(pt) # self.mRubberBand0.addGeometry(self.polygonGeom, None) n = self.mRubberBand0.numberOfVertices() self.mRubberBand0.show() self.mRubberBand = None area = None if self.areaType == ProtectionAreaType.Primary: area = PrimaryObstacleArea(self.resultPolylineArea) elif self.areaType == ProtectionAreaType.Secondary: if len(self.resultPolylineArea) == 4: area = SecondaryObstacleArea(self.resultPolylineArea[0].Position, self.resultPolylineArea[1].Position, self.resultPolylineArea[3].Position, self.resultPolylineArea[2].Position, MathHelper.getBearing(self.resultPolylineArea[0].Position, self.resultPolylineArea[1].Position)) else: if self.primaryPolyline.Count < 2: define._messageLabel.setText("The PrimaryLine in Secondary Area must exist.") return if self.isPrimaryPolylineStarted: define._messageLabel.setText("You must finish the input of PrimaryLine.") return area = SecondaryObstacleAreaWithManyPoints(self.resultPolylineArea, self.primaryPolyline) self.emit(SIGNAL("outputResult"), area, self.mRubberBand0) n = 0 def canvasMoveEvent( self, e ): 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: self.rubberBand.addPoint(snapPoint) self.rubberBand.show() if ( self.mRubberBand == None ): return if ( self.mRubberBand.numberOfVertices() > 0 ): if self.menuString != "Undo": self.mRubberBand.removeLastPoint( 0 ) else: self.menuString = "" point2 = None if snapPoint != None: self.mRubberBand.addPoint( snapPoint) point2 = snapPoint else: self.mRubberBand.addPoint( self.toMapCoordinates( e.pos() ) ) point2 = self.toMapCoordinates( e.pos() ) if self.menuString == "Arc": point0 = self.resultPolylineArea[self.resultPolylineArea.Count - 2].Position point1 = self.resultPolylineArea[self.resultPolylineArea.Count - 1].Position # point2 = self.mRubberBand.getPoint(self.mRubberBand.numberOfVertices() - 1) bulge = MathHelper.smethod_60(point0, point1, point2) self.resultPolylineArea[self.resultPolylineArea.Count - 2].bulge = bulge self.mRubberBand = None QgisHelper.ClearRubberBandInCanvas(define._canvas) self.mRubberBand = QgsRubberBand( self.mCanvas, QGis.Polygon ) self.mRubberBand.setFillColor( self.mFillColor ) self.mRubberBand.setBorderColor( self.mBorderColour ) for pt in self.resultPolylineArea.method_14(): self.mRubberBand.addPoint(pt) self.mRubberBand.addPoint(point2) def snapPoint(self, p, bNone = False): if define._snapping == False: return (define._canvas.getCoordinateTransform().toMapCoordinates( p ), None, None) snappingResults = self.mSnapper.snapToBackgroundLayers( p ) 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 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(), QGis.Line) 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 = QgsPoint(lp1.x() + width * (yd / length), lp1.y() - width * (xd / length)) pt2 = QgsPoint(lp1.x() - width * (yd / length), lp1.y() + width * (xd / length)) pt3 = QgsPoint(lp2.x() - width * (yd / length), lp2.y() + width * (xd / length)) pt4 = QgsPoint(lp2.x() + width * (yd / length), lp2.y() - width * (xd / length)) self.geometry = QgsGeometry.fromPolygon([[pt1, pt2, pt3, pt4, pt1]]) self.geometryDigitized.emit() self.firstPoint = mousepos
class QgepMapToolAddFeature(QgsMapTool): """ Base class for adding features """ 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): """ When activating the map tool """ QgsMapTool.activate(self) self.canvas.setCursor(QCursor(Qt.CrossCursor)) def deactivate(self): """ On deactivating the map tool """ QgsMapTool.deactivate(self) self.canvas.unsetCursor() # pylint: disable=no-self-use def isZoomTool(self): """ This is no zoom tool """ return False # =========================================================================== # Events # =========================================================================== def canvasReleaseEvent(self, event): """ Called when a mouse button is :param event: :return: """ if event.button() == Qt.RightButton: self.rightClicked(event) else: self.leftClicked(event) def leftClicked(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.tempRubberband.reset() def rightClicked(self, _): """ On a right click we create a new feature from the existing rubberband and show the add dialog """ 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 canvasMoveEvent(self, event): """ When the mouse is moved the rubberband needs to be updated :param event: The coordinates etc. """ mousepos = self.canvas.getCoordinateTransform()\ .toMapCoordinates(event.pos().x(), event.pos().y()) self.tempRubberband.movePoint(mousepos)
class PlanetExtentMapTool(QgsMapTool): extentSelected = pyqtSignal(object) def __init__(self, canvas): QgsMapTool.__init__(self, canvas) self.canvas = canvas self.extent = None self.dragging = False self.rubber_band = None self.select_rect = QRect() def canvasPressEvent(self, event): self.select_rect.setRect(0, 0, 0, 0) self.rubber_band = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) self.rubber_band.setFillColor(RB_FILL) self.rubber_band.setStrokeColor(RB_STROKE) self.rubber_band.setWidth(1) def canvasMoveEvent(self, event): if event.buttons() != Qt.LeftButton: return if not self.dragging: self.dragging = True self.select_rect.setTopLeft(event.pos()) self.select_rect.setBottomRight(event.pos()) self._set_rubber_band() def canvasReleaseEvent(self, event): # If the user simply clicked without dragging ignore this if not self.dragging: return # Set valid values for rectangle's width and height if self.select_rect.width() == 1: self.select_rect.setLeft(self.select_rect.left() + 1) if self.select_rect.height() == 1: self.select_rect.setBottom(self.select_rect.bottom() + 1) if self.rubber_band: self._set_rubber_band() # noinspection PyUnusedLocal selectgeom = self.rubber_band.asGeometry() self.rubber_band.reset(QgsWkbTypes.PolygonGeometry) del self.rubber_band self.rubber_band = None self.dragging = False # noinspection PyUnresolvedReferences self.extentSelected.emit(self.extent) def _set_rubber_band(self): transform = self.canvas.getCoordinateTransform() ll = transform.toMapCoordinates(self.select_rect.left(), self.select_rect.bottom()) ur = transform.toMapCoordinates(self.select_rect.right(), self.select_rect.top()) if self.rubber_band: self.rubber_band.reset(QgsWkbTypes.PolygonGeometry) self.rubber_band.addPoint(ll, False) self.rubber_band.addPoint(QgsPointXY(ur.x(), ll.y()), False) self.rubber_band.addPoint(ur, False) self.rubber_band.addPoint(QgsPointXY(ll.x(), ur.y()), True) self.extent = QgsRectangle(ur, ll)
class PlanetMainFilters(MAIN_FILTERS_BASE, MAIN_FILTERS_WIDGET, PlanetFilterMixin): leAOI: QLineEdit filtersChanged = pyqtSignal() zoomToAOIRequested = pyqtSignal() def __init__(self, iface, parent=None, plugin=None): super().__init__(parent=parent) self._iface: QgisInterface = iface self._plugin = plugin self.setupUi(self) self._aoi_box = QgsRubberBand(self._iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self._aoi_box.setFillColor(QColor(0, 0, 0, 0)) self._aoi_box.setStrokeColor(MAIN_AOI_COLOR) self._aoi_box.setWidth(3) self._aoi_box.setLineStyle(Qt.DashLine) self._canvas: QgsMapCanvas = self._iface.mapCanvas() # This may later be a nullptr, if no active tool when queried self._cur_maptool = None # self._json_exporter = QgsJsonExporter() # self._json_exporter.setIncludeAttributes(False) # noinspection PyUnresolvedReferences self.leAOI.textChanged['QString'].connect(self.filters_changed) # noinspection PyUnresolvedReferences self.leAOI.textEdited['QString'].connect(self.validate_edited_aoi) self._setup_tool_buttons() # Extent line edit tools self.btnZoomToAOI.clicked.connect(self.zoom_to_aoi) self.btnCopyAOI.clicked.connect(self.copy_aoi_to_clipboard) self.btnLoadAOI.clicked.connect(self.load_aoi_from_file) def reset_aoi_box(self): if self._aoi_box: self._aoi_box.reset(QgsWkbTypes.PolygonGeometry) def filters(self): # return and_filter(geom_filter(self.leAOI.text), # date_range('acquired', gte=dateEditStart.text, # lte=dateEditEnd.text)) filters = [] if self.leAOI.text(): # TODO: Validate GeoJSON; try planet.api.utils.probably_geojson() # noinspection PyBroadException try: if qgsgeometry_from_geojson(self.leAOI.text()): aoi = json.loads(self.leAOI.text()) filters.append(geom_filter(aoi)) else: self._show_message("AOI not valid GeoJSON polygon", level=Qgis.Warning, duration=10) except: self._show_message("AOI not valid JSON", level=Qgis.Warning, duration=10) finally: return filters def filters_as_json(self): filters = [] if self.leAOI.text(): filters.append(self.leAOI.text()) return filters def load_filters(self, filter_json): pass def set_from_request(self, request): filters = self._filters_from_request(request, "geometry") if filters: geom = filters[0]["config"] txt = json.dumps(geom) self.leAOI.setText(txt) @pyqtSlot('QString') def filters_changed(self, value): # noinspection PyUnresolvedReferences self.filtersChanged.emit() @pyqtSlot() def clean_up(self): self.reset_aoi_box() def _setup_tool_buttons(self): extent_menu = QMenu(self) canvas_act = QAction('Current visible extent', extent_menu) # noinspection PyUnresolvedReferences canvas_act.triggered[bool].connect(self.aoi_from_current_extent) extent_menu.addAction(canvas_act) active_act = QAction('Active map layer extent', extent_menu) # noinspection PyUnresolvedReferences active_act.triggered[bool].connect(self.aoi_from_active_layer_extent) extent_menu.addAction(active_act) full_act = QAction('All map layers extent', extent_menu) # noinspection PyUnresolvedReferences full_act.triggered[bool].connect(self.aoi_from_full_extent) extent_menu.addAction(full_act) self.btnExtent.setMenu(extent_menu) # Also show menu on click, to keep disclosure triangle visible self.btnExtent.clicked.connect(self.btnExtent.showMenu) draw_menu = QMenu(self) box_act = QAction('Rectangle', draw_menu) # noinspection PyUnresolvedReferences box_act.triggered[bool].connect(self.aoi_from_box) draw_menu.addAction(box_act) circle_act = QAction('Circle', draw_menu) # noinspection PyUnresolvedReferences circle_act.triggered[bool].connect(self.aoi_from_circle) draw_menu.addAction(circle_act) polygon_act = QAction('Polygon', draw_menu) # noinspection PyUnresolvedReferences polygon_act.triggered[bool].connect(self.aoi_from_polygon) draw_menu.addAction(polygon_act) self.btnDraw.setMenu(draw_menu) # Also show menu on click, to keep disclosure triangle visible self.btnDraw.clicked.connect(self.btnDraw.showMenu) selection_menu = QMenu(self) self.single_select_act = QAction('Single feature', selection_menu) # noinspection PyUnresolvedReferences self.single_select_act.triggered[bool].connect(self.aoi_from_feature) selection_menu.addAction(self.single_select_act) self.bound_select_act = QAction('Multiple features (bounding box)', selection_menu) # noinspection PyUnresolvedReferences self.bound_select_act.triggered[bool].connect(self.aoi_from_bound) selection_menu.addAction(self.bound_select_act) self.btnSelection.setMenu(selection_menu) # Also show menu on click, to keep disclosure triangle visible self.btnSelection.clicked.connect(self._toggle_selection_tools) self.btnSelection.clicked.connect(self.btnSelection.showMenu) def _toggle_selection_tools(self): active_layer = self._iface.activeLayer() is_vector = isinstance(active_layer, QgsVectorLayer) if is_vector and active_layer.selectedFeatureCount(): if active_layer.selectedFeatureCount() > 1: self.single_select_act.setEnabled(False) self.bound_select_act.setEnabled(True) elif active_layer.selectedFeatureCount(): self.single_select_act.setEnabled(True) self.bound_select_act.setEnabled(False) else: self.single_select_act.setEnabled(False) self.bound_select_act.setEnabled(False) else: self.single_select_act.setEnabled(False) self.bound_select_act.setEnabled(False) @pyqtSlot() # noinspection PyArgumentList def aoi_from_current_extent(self): """Return current map extent as geojson transformed to EPSG:4326 """ if not self._iface: log.debug('No iface object, skipping AOI extent') return canvas = self._iface.mapCanvas() # noinspection PyArgumentList transform = QgsCoordinateTransform( QgsProject.instance().crs(), QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance()) canvas_extent: QgsRectangle = canvas.extent() transform_extent = transform.transformBoundingBox(canvas_extent) # noinspection PyArgumentList geom_extent = QgsGeometry.fromRect(transform_extent) extent_json = geom_extent.asJson() # noinspection PyArgumentList self._aoi_box.setToGeometry(QgsGeometry.fromRect(canvas.extent())) self.leAOI.setText(extent_json) log.debug('AOI set to canvas extent') self.zoom_to_aoi() @pyqtSlot() # noinspection PyArgumentList def aoi_from_active_layer_extent(self): """Return active map layer extent as geojson transformed to EPSG:4326 """ if not self._iface: log.debug('No iface object, skipping AOI extent') return map_layer: QgsMapLayer = self._iface.activeLayer() if map_layer is None: log.debug('No active layer selected, skipping AOI extent') return if not map_layer.isValid(): log.debug('Active map layer invalid, skipping AOI extent') return # noinspection PyArgumentList transform = QgsCoordinateTransform( map_layer.crs(), QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance()) ml_extent: QgsRectangle = map_layer.extent() transform_extent = transform.transformBoundingBox(ml_extent) # noinspection PyArgumentList geom_extent = QgsGeometry.fromRect(transform_extent) extent_json = geom_extent.asJson() # noinspection PyArgumentList,PyCallByClass self._aoi_box.setToGeometry(QgsGeometry.fromRect(ml_extent)) self.leAOI.setText(extent_json) log.debug('AOI set to active layer extent') self.zoom_to_aoi() @pyqtSlot() # noinspection PyArgumentList def aoi_from_full_extent(self): """Return full data map extent as geojson transformed to EPSG:4326 """ if not self._iface: log.debug('No iface object, skipping AOI extent') return canvas = self._iface.mapCanvas() # noinspection PyArgumentList transform = QgsCoordinateTransform( QgsProject.instance().crs(), QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance()) canvas_extent: QgsRectangle = canvas.fullExtent() transform_extent = transform.transformBoundingBox(canvas_extent) # noinspection PyArgumentList geom_extent = QgsGeometry.fromRect(transform_extent) extent_json = geom_extent.asJson() # noinspection PyArgumentList,PyCallByClass self._aoi_box.setToGeometry(QgsGeometry.fromRect(canvas_extent)) self.leAOI.setText(extent_json) log.debug('AOI set to full data extent') self.zoom_to_aoi() @pyqtSlot() def aoi_from_box(self): self._cur_maptool: QgsMapTool = self._canvas.mapTool() self._aoi_box.reset(QgsWkbTypes.PolygonGeometry) aoi_draw = PlanetExtentMapTool(self._iface.mapCanvas()) self._iface.mapCanvas().setMapTool(aoi_draw) aoi_draw.extentSelected.connect(self.set_draw_aoi) @pyqtSlot() def aoi_from_circle(self): self._cur_maptool: QgsMapTool = self._canvas.mapTool() self._aoi_box.reset(QgsWkbTypes.PolygonGeometry) aoi_draw = PlanetCircleMapTool(self._iface.mapCanvas()) self._iface.mapCanvas().setMapTool(aoi_draw) aoi_draw.circleSelected.connect(self.set_draw_aoi) @pyqtSlot() def aoi_from_polygon(self): self._cur_maptool: QgsMapTool = self._canvas.mapTool() self._aoi_box.reset(QgsWkbTypes.PolygonGeometry) aoi_draw = PlanetPolyMapTool(self._iface.mapCanvas()) self._iface.mapCanvas().setMapTool(aoi_draw) aoi_draw.polygonSelected.connect(self.set_draw_aoi) @pyqtSlot(object) def set_draw_aoi(self, aoi): # noinspection PyArgumentList transform = QgsCoordinateTransform( QgsProject.instance().crs(), QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance()) aoi_json = None if isinstance(aoi, QgsRectangle): aoi_geom = QgsGeometry().fromRect(aoi) self._aoi_box.setToGeometry(aoi_geom) aoi_geom.transform(transform) aoi_json = aoi_geom.asJson() if isinstance(aoi, QgsGeometry): self._aoi_box.setToGeometry(aoi) # TODO: validate geom is less than 500 vertices aoi.transform(transform) aoi_json = aoi.asJson() if aoi_json: self.leAOI.setText(aoi_json) # noinspection PyUnresolvedReferences self._show_message('AOI set to drawn figure') self.zoom_to_aoi() if self._cur_maptool is not None: # Restore previously used maptool self._canvas.setMapTool(self._cur_maptool) self._cur_maptool = None else: # Fallback to activating pan tool self._iface.actionPan().trigger() else: # noinspection PyUnresolvedReferences self._show_message('AOI unable to be set', level=Qgis.Warning, duration=10) @pyqtSlot() def aoi_from_feature(self): layer: QgsVectorLayer = self._iface.activeLayer() if layer.selectedFeatureCount() > 1: self._show_message('More than 1 feature. Searching by bbox.', level=Qgis.Warning, duration=10) self.aoi_from_bound() return elif layer.selectedFeatureCount() < 1: self._show_message('No features selected.', level=Qgis.Warning, duration=10) return selected: QgsFeature = layer.selectedFeatures()[0] if selected.geometry().isMultipart(): multi_geom = selected.geometry().asGeometryCollection() if len(multi_geom) > 1: self._show_message('More than 1 geometry. Searching by bbox.', level=Qgis.Warning, duration=10) self.aoi_from_bound() return elif len(multi_geom) < 1: self._show_message('No geometry selected.', level=Qgis.Warning, duration=10) return else: geom: QgsGeometry = multi_geom[0] else: geom: QgsGeometry = selected.geometry() if geom.constGet().vertexCount() > 500: self._show_message('More than 500 vertices. Searching by bbox.', level=Qgis.Warning, duration=10) self.aoi_from_bound() return # noinspection PyArgumentList trans_layer = QgsCoordinateTransform( layer.sourceCrs(), QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance()) # noinspection PyArgumentList trans_canvas = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance().crs(), QgsProject.instance()) # geom.transform(transform) geom.transform(trans_layer) geom_json = geom.asJson() self.leAOI.setText(geom_json) geom.transform(trans_canvas) self._aoi_box.setToGeometry(geom, QgsCoordinateReferenceSystem("EPSG:4326")) self.zoom_to_aoi() @pyqtSlot() def aoi_from_bound(self): layer: QgsVectorLayer = self._iface.activeLayer() if layer.selectedFeatureCount() < 1: self._show_message('No features selected.', level=Qgis.Warning, duration=10) return bbox = layer.boundingBoxOfSelected() # noinspection PyArgumentList trans_layer = QgsCoordinateTransform( layer.sourceCrs(), QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance()) # noinspection PyArgumentList trans_canvas = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance().crs(), QgsProject.instance()) transform_bbox = trans_layer.transformBoundingBox(bbox) # noinspection PyArgumentList geom_bbox = QgsGeometry.fromRect(transform_bbox) bbox_json = geom_bbox.asJson() self.leAOI.setText(bbox_json) bbox_canvas = trans_canvas.transformBoundingBox(transform_bbox) # noinspection PyArgumentList self._aoi_box.setToGeometry(QgsGeometry.fromRect(bbox_canvas)) self.zoom_to_aoi() def hide_aoi_if_matches_geom(self, geom): color = (QColor(0, 0, 0, 0) if self._aoi_box.asGeometry().equals(geom) else MAIN_AOI_COLOR) self._aoi_box.setStrokeColor(color) def show_aoi(self): if self._aoi_box is not None: self._aoi_box.setStrokeColor(MAIN_AOI_COLOR) def aoi_geom(self): if self._aoi_box is not None: return self._aoi_box.asGeometry() @pyqtSlot() def zoom_to_aoi(self): if not self._iface: log.debug('No iface object, skipping AOI extent') return if not self.leAOI.text(): log.debug('No AOI defined, skipping zoom to AOI') return geom: QgsGeometry = qgsgeometry_from_geojson(self.leAOI.text()) self._aoi_box.setToGeometry(geom, QgsCoordinateReferenceSystem("EPSG:4326")) self.show_aoi() zoom_canvas_to_aoi(self.leAOI.text(), iface_obj=self._iface) self.zoomToAOIRequested.emit() @pyqtSlot() def copy_aoi_to_clipboard(self): if not self.leAOI.text(): log.debug('No AOI defined, skipping zoom to AOI') return json_geom_txt = json.dumps(json.loads(self.leAOI.text()), indent=2) cb = QgsApplication.clipboard() cb.setText(json_geom_txt) # noinspection PyUnresolvedReferences self._show_message('AOI copied to clipboard') @pyqtSlot() def load_aoi_from_file(self): path, _ = QFileDialog.getOpenFileName(self, "Open GeoJSON AOI file", QDir.homePath(), "JSON (*.json);;All Files (*)") file = QFile(path) if not file.open(QFile.ReadOnly | QFile.Text): return inf = QTextStream(file) json_txt = inf.readAll() try: json_obj = json.loads(json_txt) except ValueError: # noinspection PyUnresolvedReferences self._show_message('GeoJSON from file invalid', level=Qgis.Warning, duration=10) return json_geom = geometry_from_json(json_obj) if not json_geom: # noinspection PyUnresolvedReferences self._show_message('GeoJSON geometry from file invalid', level=Qgis.Warning, duration=10) return geom: QgsGeometry = qgsgeometry_from_geojson(json_geom) self._aoi_box.setToGeometry(geom, QgsCoordinateReferenceSystem("EPSG:4326")) self.leAOI.setText(json.dumps(json_geom)) self.zoom_to_aoi() @pyqtSlot() def validate_aoi(self): # TODO:gather existing validation logic here # TODO: Check for valid json.loads # TODO: Check API verticie limit of 500 pass @pyqtSlot() def validate_edited_aoi(self): json_txt = self.leAOI.text() if not json_txt: self.reset_aoi_box() log.debug('No AOI defined, skipping validation') return try: json_obj = json.loads(json_txt) except ValueError: # noinspection PyUnresolvedReferences self._show_message('AOI GeoJSON is invalid', level=Qgis.Warning, duration=10) return json_geom = geometry_from_json(json_obj) if not json_geom: # noinspection PyUnresolvedReferences self._show_message('AOI GeoJSON geometry invalid', level=Qgis.Warning, duration=10) return geom: QgsGeometry = qgsgeometry_from_geojson(json_geom) self._aoi_box.setToGeometry(geom, QgsCoordinateReferenceSystem("EPSG:4326")) self.leAOI.blockSignals(True) self.leAOI.setText(json.dumps(json_geom)) self.leAOI.blockSignals(False) self.zoom_to_aoi()
class FinderBox(QComboBox): running = False to_finish = 0 search_started = pyqtSignal() search_finished = pyqtSignal() def __init__(self, finders, iface, parent=None): self.iface = iface self.mapCanvas = iface.mapCanvas() self.marker = None self.rubber = QgsRubberBand(self.mapCanvas) self.rubber.setColor(QColor(255, 255, 50, 200)) self.rubber.setIcon(self.rubber.ICON_CIRCLE) self.rubber.setIconSize(15) self.rubber.setWidth(4) self.rubber.setBrushStyle(Qt.NoBrush) QComboBox.__init__(self, parent) self.setEditable(True) self.setInsertPolicy(QComboBox.InsertAtTop) self.setMinimumHeight(27) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.insertSeparator(0) self.lineEdit().returnPressed.connect(self.search) self.result_view = QTreeView() self.result_view.setHeaderHidden(True) self.result_view.setMinimumHeight(300) self.result_view.activated.connect(self.itemActivated) self.result_view.pressed.connect(self.itemPressed) self.setView(self.result_view) self.result_model = ResultModel(self) self.setModel(self.result_model) self.finders = finders for finder in list(self.finders.values()): finder.result_found.connect(self.result_found) finder.limit_reached.connect(self.limit_reached) finder.finished.connect(self.finished) self.clearButton = QPushButton(self) self.clearButton.setIcon( QIcon(":/plugins/quickfinder/icons/draft.svg")) self.clearButton.setText('') self.clearButton.setFlat(True) self.clearButton.setCursor(QCursor(Qt.ArrowCursor)) self.clearButton.setStyleSheet('border: 0px; padding: 0px;') self.clearButton.clicked.connect(self.clear) layout = QHBoxLayout(self) self.setLayout(layout) layout.addStretch() layout.addWidget(self.clearButton) layout.addSpacing(20) button_size = self.clearButton.sizeHint() # frameWidth = self.lineEdit().style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth) padding = button_size.width() # + frameWidth + 1 self.lineEdit().setStyleSheet('QLineEdit {padding-right: %dpx; }' % padding) def __del__(self): if self.rubber: self.iface.mapCanvas().scene().removeItem(self.rubber) del self.rubber #clear marker that the lonlat seted def clearMarker(self): self.mapCanvas.scene().removeItem(self.marker) self.marker = None def clearSelection(self): self.result_model.setSelected(None, self.result_view.palette()) self.rubber.reset() #self.clearMarker() def clear(self): self.clearSelection() self.result_model.clearResults() self.lineEdit().setText('') def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.clearSelection() self.clearMarker() QComboBox.keyPressEvent(self, event) def lnglatFinder(self, to_find): import re m = re.match(r'(?P<lon>-?\d*(.\d+))\s+(?P<lat>-?\d*(.\d+))', to_find) if not m: return False x = float(m.group('lon')) y = float(m.group('lat')) return self.zoomLnglat(x, y) def zoomLnglat(self, lng, lat): x, y = lng, lat canvas = self.mapCanvas currExt = canvas.extent() canvasCenter = currExt.center() dx = float(x) - canvasCenter.x() dy = float(y) - canvasCenter.y() xMin = currExt.xMinimum() + dx xMax = currExt.xMaximum() + dx yMin = currExt.yMinimum() + dy yMax = currExt.yMaximum() + dy rect = QgsRectangle(xMin, yMin, xMax, yMax) canvas.setExtent(rect) pt = QgsPointXY(float(x), float(y)) self.marker = QgsVertexMarker(canvas) self.marker.setCenter(pt) self.marker.setIconSize(18) self.marker.setPenWidth(2) self.marker.setIconType(QgsVertexMarker.ICON_CROSS) canvas.refresh() return True # def geocodeFinder(self, to_finder): # print(to_finder[:2]) # if not to_finder[:2] == 'b:': # return False # # address = to_finder[2:] # url = MySettings().value("baiduUrl") # url = url + parse.quote(address) # # response = request.urlopen(url) # content = response.read() # data = json.loads(content) # print(data) # lng, lat = (data['result']['location']['lng'], data['result']['location']['lat']) # from .cood_trans import bd09_to_wgs84 # lng, lat = bd09_to_wgs84(lng, lat) # print(f'{lng}-{lat}') # return self.zoomLnglat(lng, lat) def search(self): # self.geocode() if self.running: return to_find = self.lineEdit().text() if not to_find or to_find == '': return # if not (self.lnglatFinder(to_find) or self.geocodeFinder(to_find)): if not self.lnglatFinder(to_find): self.showPopup() self.running = True self.search_started.emit() self.clearSelection() self.result_model.clearResults() self.result_model.truncateHistory(MySettings().value("historyLength")) self.result_model.setLoading(True) QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) self.finders_to_start = [] for finder in list(self.finders.values()): if finder.activated(): self.finders_to_start.append(finder) bbox = self.mapCanvas.fullExtent() while len(self.finders_to_start) > 0: finder = self.finders_to_start[0] self.finders_to_start.remove(finder) self.result_model.addResult(finder.name) finder.start(to_find, bbox=bbox) # For case there is no finder activated self.finished(None) def stop(self): self.finders_to_start = [] for finder in list(self.finders.values()): if finder.is_running(): finder.stop() self.finished(None) def result_found(self, finder, layername, value, geometry, srid): self.result_model.addResult(finder.name, layername, value, geometry, srid) self.result_view.expandAll() def limit_reached(self, finder, layername): self.result_model.addEllipsys(finder.name, layername) def finished(self, finder): if len(self.finders_to_start) > 0: return for finder in list(self.finders.values()): if finder.is_running(): return self.running = False self.search_finished.emit() self.result_model.setLoading(False) QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) def itemActivated(self, index): item = self.result_model.itemFromIndex(index) self.showItem(item) def itemPressed(self, index): item = self.result_model.itemFromIndex(index) if QApplication.mouseButtons() == Qt.LeftButton: self.showItem(item) def showItem(self, item): if isinstance(item, ResultItem): self.result_model.setSelected(item, self.result_view.palette()) geometry = self.transform_geom(item) self.rubber.reset(geometry.type()) self.rubber.setToGeometry(geometry, None) self.zoom_to_rubberband() return if isinstance(item, GroupItem): child = item.child(0) if isinstance(child, ResultItem): self.result_model.setSelected(item, self.result_view.palette()) self.rubber.reset(child.geometry.type()) for i in range(0, item.rowCount()): geometry = self.transform_geom(item.child(i)) self.rubber.addGeometry(geometry, None) self.zoom_to_rubberband() return if item.__class__.__name__ == 'QStandardItem': self.clearSelection() def transform_geom(self, item): src_crs = QgsCoordinateReferenceSystem() src_crs.createFromSrid(item.srid) dest_crs = self.mapCanvas.mapSettings().destinationCrs() geom = QgsGeometry(item.geometry) geom.transform( QgsCoordinateTransform(src_crs, dest_crs, QgsProject.instance())) return geom def zoom_to_rubberband(self): geom = self.rubber.asGeometry() if geom: rect = geom.boundingBox() rect.scale(1.5) self.mapCanvas.setExtent(rect) self.mapCanvas.refresh()
class PipelinePlanner: """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.canvas = self.iface.mapCanvas() self.plugin_dir = os.path.dirname(__file__) # initialize locale self.addPipelinePoint = QgsMapToolEmitPoint(self.canvas) self.rbPipeline = QgsRubberBand(self.canvas) self.rbPipeline.setColor(Qt.red) self.rbPipeline.setWidth(4) locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join( self.plugin_dir, 'i18n', 'PipelinePlanner_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) # Declare instance attributes self.actions = [] self.menu = self.tr(u'&Pipeline Planner') # Check if plugin was started the first time in current QGIS session # Must be set in initGui() to survive plugin reloads self.first_start = None self.dlg = PipelinePlannerDialog() self.dlg.tblImpacts.setColumnWidth(1, 50) self.dlg.tblImpacts.setColumnWidth(2, 225) self.dlg.tblImpacts.setColumnWidth(3, 75) # noinspection PyMethodMayBeStatic def tr(self, message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('PipelinePlanner', message) def add_action( self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): """Add a toolbar icon to the toolbar. :param icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :type icon_path: str :param text: Text that should be shown in menu items for this action. :type text: str :param callback: Function to be called when the action is triggered. :type callback: function :param enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :type enabled_flag: bool :param add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :type add_to_menu: bool :param add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :type add_to_toolbar: bool :param status_tip: Optional text to show in a popup when mouse pointer hovers over the action. :type status_tip: str :param parent: Parent widget for the new action. Defaults None. :type parent: QWidget :param whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.actions list. :rtype: QAction """ icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: # Adds plugin icon to Plugins toolbar self.iface.addToolBarIcon(action) if add_to_menu: self.iface.addPluginToVectorMenu( self.menu, action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/pipeline_planner/icon.png' self.add_action( icon_path, text=self.tr(u'Pipeline Planner'), callback=self.run, parent=self.iface.mainWindow()) # will be set False in run() self.first_start = True self.addPipelinePoint.canvasClicked.connect(self.evaluatePipeline) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for action in self.actions: self.iface.removePluginVectorMenu( self.tr(u'&Pipeline Planner'), action) self.iface.removeToolBarIcon(action) def run(self): """Run method that performs all the real work""" self.canvas.setMapTool(self.addPipelinePoint) def evaluatePipeline(self, point, button): if button == Qt.LeftButton: self.rbPipeline.addPoint(point) self.rbPipeline.show() elif button == Qt.RightButton: pipeline = self.rbPipeline.asGeometry() self.dlg.tblImpacts.setRowCount(0) lyrRaptor = QgsProject.instance().mapLayersByName("raptor_buffer")[0] lyrBaea = QgsProject.instance().mapLayersByName("baea_buffer")[0] lyrBuowl = QgsProject.instance().mapLayersByName("buowl_buffer")[0] raptors = lyrRaptor.getFeatures(pipeline.boundingBox()) baeas = lyrBaea.getFeatures(pipeline.boundingBox()) buowls = lyrBuowl.getFeatures(pipeline.boundingBox()) for raptor in raptors: valConstraint = raptor.attribute("recentspec") valID = raptor.attribute("Nest_ID") valStatus = raptor.attribute("recentstat") valDistance = pipeline.distance(raptor.geometry().centroid()) if raptor.geometry().intersects(pipeline): row = self.dlg.tblImpacts.rowCount() self.dlg.tblImpacts.insertRow(row) self.dlg.tblImpacts.setItem(row, 0, QTableWidgetItem(valConstraint)) self.dlg.tblImpacts.setItem(row, 1, QTableWidgetItem(str(valID))) self.dlg.tblImpacts.setItem(row, 2, QTableWidgetItem(valStatus)) self.dlg.tblImpacts.setItem(row, 3, QTableWidgetItem("{:4.5f}".format(valDistance))) for baea in baeas: # valConstraint = baea.attribute("recentspec") valID = baea.attribute("nest_id") valStatus = baea.attribute("status") valDistance = pipeline.distance(baea.geometry().centroid()) if baea.geometry().intersects(pipeline): row = self.dlg.tblImpacts.rowCount() self.dlg.tblImpacts.insertRow(row) # self.dlg.tblImpacts.setItem(row, 0, QTableWidgetItem(valConstraint)) self.dlg.tblImpacts.setItem(row, 1, QTableWidgetItem(str(valID))) self.dlg.tblImpacts.setItem(row, 2, QTableWidgetItem(valStatus)) self.dlg.tblImpacts.setItem(row, 3, QTableWidgetItem("{:4.5f}".format(valDistance))) for buowl in buowls: valConstraint = buowl.attribute("habitat") valID = buowl.attribute("habitat_id") valStatus = buowl.attribute("recentstat") valDistance = pipeline.distance(buowl.geometry()) # .centroid() if buowl.geometry().intersects(pipeline): row = self.dlg.tblImpacts.rowCount() self.dlg.tblImpacts.insertRow(row) self.dlg.tblImpacts.setItem(row, 0, QTableWidgetItem(valConstraint)) self.dlg.tblImpacts.setItem(row, 1, QTableWidgetItem(str(valID))) self.dlg.tblImpacts.setItem(row, 2, QTableWidgetItem(valStatus)) self.dlg.tblImpacts.setItem(row, 3, QTableWidgetItem("{:4.5f}".format(valDistance))) self.dlg.show() self.rbPipeline.reset()
class FinderBox(QComboBox): running = False toFinish = 0 searchStarted = pyqtSignal() searchFinished = pyqtSignal() def __init__(self, finders, iface, parent=None): self.iface = iface self.mapCanvas = iface.mapCanvas() self.rubber = QgsRubberBand(self.mapCanvas) self.rubber.setColor(QColor(255, 255, 50, 200)) self.rubber.setIcon(self.rubber.ICON_CIRCLE) self.rubber.setIconSize(15) self.rubber.setWidth(4) self.rubber.setBrushStyle(Qt.NoBrush) QComboBox.__init__(self, parent) self.setEditable(True) self.setInsertPolicy(QComboBox.InsertAtTop) self.setMinimumHeight(27) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.insertSeparator(0) self.lineEdit().returnPressed.connect(self.search) self.resultView = QTreeView() self.resultView.setHeaderHidden(True) self.resultView.setMinimumHeight(300) self.resultView.activated.connect(self.itemActivated) self.resultView.pressed.connect(self.itemPressed) self.setView(self.resultView) self.resultModel = ResultModel(self) self.setModel(self.resultModel) self.finders = finders for finder in self.finders.values(): finder.resultFound.connect(self.resultFound) finder.limitReached.connect(self.limitReached) finder.finished.connect(self.finished) self.clearButton = QPushButton(self) self.clearButton.setIcon(QIcon(":/plugins/quickfinder/icons/draft.svg")) self.clearButton.setText('') self.clearButton.setFlat(True) self.clearButton.setCursor(QCursor(Qt.ArrowCursor)) self.clearButton.setStyleSheet('border: 0px; padding: 0px;') self.clearButton.clicked.connect(self.clear) layout = QHBoxLayout(self) self.setLayout(layout) layout.addStretch() layout.addWidget(self.clearButton) layout.addSpacing(20) buttonSize = self.clearButton.sizeHint() # frameWidth = self.lineEdit().style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth) padding = buttonSize.width() # + frameWidth + 1 self.lineEdit().setStyleSheet('QLineEdit {padding-right: %dpx; }' % padding) def __del__(self): if self.rubber: self.iface.mapCanvas().scene().removeItem(self.rubber) del self.rubber def clearSelection(self): self.resultModel.setSelected(None, self.resultView.palette()) self.rubber.reset() def clear(self): self.clearSelection() self.resultModel.clearResults() self.lineEdit().setText('') def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.clearSelection() QComboBox.keyPressEvent(self, event) def search(self): if self.running: return toFind = self.lineEdit().text() if not toFind or toFind == '': return self.running = True self.searchStarted.emit() self.clearSelection() self.resultModel.clearResults() self.resultModel.truncateHistory(MySettings().value("historyLength")) self.resultModel.setLoading(True) self.showPopup() QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) self.findersToStart = [] for finder in self.finders.values(): if finder.activated(): self.findersToStart.append(finder) bbox = self.mapCanvas.fullExtent() while len(self.findersToStart) > 0: finder = self.findersToStart[0] self.findersToStart.remove(finder) self.resultModel.addResult(finder.name) finder.start(toFind, bbox=bbox) # For case there is no finder activated self.finished(None) def stop(self): self.findersToStart = [] for finder in self.finders.values(): if finder.isRunning(): finder.stop() self.finished(None) def resultFound(self, finder, layername, value, geometry, srid): self.resultModel.addResult(finder.name, layername, value, geometry, srid) self.resultView.expandAll() def limitReached(self, finder, layername): self.resultModel.addEllipsys(finder.name, layername) def finished(self, finder): if len(self.findersToStart) > 0: return for finder in self.finders.values(): if finder.isRunning(): return self.running = False self.searchFinished.emit() self.resultModel.setLoading(False) QCoreApplication.processEvents(QEventLoop.ExcludeUserInputEvents) def itemActivated(self, index): item = self.resultModel.itemFromIndex(index) self.showItem(item) def itemPressed(self, index): item = self.resultModel.itemFromIndex(index) if QApplication.mouseButtons() == Qt.LeftButton: self.showItem(item) def showItem(self, item): if isinstance(item, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) geometry = self.transformGeom(item) self.rubber.reset(geometry.type()) self.rubber.setToGeometry(geometry, None) self.zoomToRubberBand() return if isinstance(item, GroupItem): child = item.child(0) if isinstance(child, ResultItem): self.resultModel.setSelected(item, self.resultView.palette()) self.rubber.reset(child.geometry.type()) for i in xrange(0, item.rowCount()): geometry = self.transformGeom(item.child(i)) self.rubber.addGeometry(geometry, None) self.zoomToRubberBand() return if item.__class__.__name__ == 'QStandardItem': self.clearSelection() def transformGeom(self, item): src_crs = QgsCoordinateReferenceSystem() src_crs.createFromSrid(item.srid) dest_crs = self.mapCanvas.mapRenderer().destinationCrs() geom = QgsGeometry(item.geometry) geom.transform(QgsCoordinateTransform(src_crs, dest_crs)) return geom def zoomToRubberBand(self): geom = self.rubber.asGeometry() if geom: rect = geom.boundingBox() rect.scale(1.5) self.mapCanvas.setExtent(rect) self.mapCanvas.refresh()
class ObstacleAreaJigSelectArea(QgsMapTool): def __init__(self, canvas, areaType): self.mCanvas = canvas self.areaType = areaType QgsMapTool.__init__(self, canvas) self.mCursor = Qt.ArrowCursor self.mRubberBand = None self.mDragging = False self.mSelectRect = QRect() self.mRubberBandResult = None self.mSnapper = QgsMapCanvasSnapper(canvas) self.lineCount = 0 self.resultGeomList = [] self.geomList = [] self.area = None self.isFinished = False # QgsRubberBand* mRubberBand; # def reset(self): # self.startPoint = None # self.endPoint = None # self.isDrawing = False # SelectByRect.RubberRect.reset(QGis.Polygon) # self.layer = self.canvas.currentLayer() def canvasPressEvent(self, e): QgisHelper.ClearRubberBandInCanvas(define._canvas) self.mSelectRect.setRect( 0, 0, 0, 0 ) self.mRubberBand = QgsRubberBand( self.mCanvas, QGis.Polygon ) self.startPoint, self.pointID, self.layer= self.snapPoint(e.pos()) def canvasMoveEvent(self, e): if self.areaType == ProtectionAreaType.Secondary: if self.lineCount == 0: define._messageLabel.setText("Select a line or arc representing the INNER edge of the secondary area.") elif self.lineCount == 1: define._messageLabel.setText("Select a line representing the OUTER edge of the secondary area.") elif self.areaType == ProtectionAreaType.Primary: define._messageLabel.setText("") elif self.areaType == ProtectionAreaType.PrimaryAndSecondary: if self.lineCount == 0: define._messageLabel.setText("Select a line or arc representing the INNER edge of the FIRST secondary area.") elif self.lineCount == 1: define._messageLabel.setText("Select a line representing the OUTER edge of the FIRST secondary area.") elif self.lineCount == 2: define._messageLabel.setText("Select a line or arc representing the INNER edge of the SECOND secondary area.") elif self.lineCount == 3: define._messageLabel.setText("Select a line representing the OUTER edge of the SECOND secondary area.") else: define._messageLabel.setText("") if ( e.buttons() != Qt.LeftButton ): return if ( not self.mDragging ): self.mDragging = True self.mSelectRect.setTopLeft( e.pos() ) self.mSelectRect.setBottomRight( e.pos() ) QgsMapToolSelectUtils.setRubberBand( self.mCanvas, self.mSelectRect,self.mRubberBand ) def canvasReleaseEvent(self, e): self.endPoint, self.pointID, self.layer= self.snapPoint(e.pos()) vlayer = QgsMapToolSelectUtils.getCurrentVectorLayer( self.mCanvas ) if ( vlayer == None ): if ( self.mRubberBand != None): self.mRubberBand.reset( QGis.Polygon ) del self.mRubberBand self.mRubberBand = None self.mDragging = False return if (not self.mDragging ): QgsMapToolSelectUtils.expandSelectRectangle(self. mSelectRect, vlayer, e.pos() ) else: if ( self.mSelectRect.width() == 1 ): self.mSelectRect.setLeft( self.mSelectRect.left() + 1 ) if ( self.mSelectRect.height() == 1 ): self.mSelectRect.setBottom( self.mSelectRect.bottom() + 1 ) if ( self.mRubberBand != None ): QgsMapToolSelectUtils.setRubberBand( self.mCanvas, self.mSelectRect, self.mRubberBand ) selectGeom = self.mRubberBand.asGeometry() selectedFeatures = QgsMapToolSelectUtils.setSelectFeaturesOrRubberband_Tas_1( self.mCanvas, selectGeom, e ) if len(selectedFeatures) > 0: self.lineCount += 1 geom = selectedFeatures[0].geometry() resultArray = QgisHelper.findArcOrLineInLineGeometry(geom, selectGeom) # if resultArray != None: # bulge = MathHelper.smethod_60(resultArray[0], resultArray[int(len(resultArray)/2)], resultArray[len(resultArray)-1]) # bulge1 = MathHelper.smethod_60(resultArray[len(resultArray)-1], resultArray[int(len(resultArray)/2)], resultArray[0]) # n = 0 pointArray0 = geom.asPolyline() self.resultGeomList.append(resultArray) self.geomList.append(pointArray0) if self.lineCount == 2 and self.areaType != ProtectionAreaType.PrimaryAndSecondary and self.areaType != ProtectionAreaType.Complex: self.area = self.makeArea(self.resultGeomList, self.areaType) pointArray = self.getPointArray(self.resultGeomList).method_14_closed() self.mRubberBandResult = None self.mRubberBandResult = QgsRubberBand( self.mCanvas, QGis.Polygon ) self.mRubberBandResult.setFillColor(QColor(255, 255, 255, 100)) self.mRubberBandResult.setBorderColor(QColor(0, 0, 0)) for point in pointArray: self.mRubberBandResult.addPoint(point) self.mRubberBandResult.show() self.emit(SIGNAL("outputResult"), self.area, self.mRubberBandResult) self.lineCount = 0 self.resultGeomList = [] self.isFinished = True # self.rubberBandLine.reset(QGis.Line) elif self.lineCount == 4 and self.areaType == ProtectionAreaType.PrimaryAndSecondary: self.area = self.makeArea(self.resultGeomList, self.areaType) pointArray = self.getPointArray([self.resultGeomList[1], self.resultGeomList[3]]).method_14_closed() self.mRubberBandResult = None self.mRubberBandResult = QgsRubberBand( self.mCanvas, QGis.Polygon ) self.mRubberBandResult.setFillColor(QColor(255, 255, 255, 100)) self.mRubberBandResult.setBorderColor(QColor(0, 0, 0)) for point in pointArray: self.mRubberBandResult.addPoint(point) self.mRubberBandResult.show() self.emit(SIGNAL("outputResult"), self.area, self.mRubberBandResult) self.lineCount = 0 self.resultGeomList = [] # else: # return del selectGeom self.mRubberBand.reset( QGis.Polygon ) del self.mRubberBand self.mRubberBand = None self.mDragging = False def getPointArray(self, geomList): pointArrayInner = geomList[0] pointArray1Outer = geomList[1] innerStartPoint = pointArrayInner[0] innerEndPoint = pointArrayInner[1] innerBulge = pointArrayInner[2] outerStartPoint = pointArray1Outer[0] outerEndPoint = pointArray1Outer[1] outerBulge = pointArray1Outer[2] line0 = QgsGeometry.fromPolyline([innerStartPoint, outerStartPoint]) line1 = QgsGeometry.fromPolyline([innerEndPoint, outerEndPoint]) # for i in range(1, len(pointArray0)): if line0.intersects(line1): tempPoint = outerStartPoint outerStartPoint = outerEndPoint outerEndPoint = tempPoint outerBulge = -outerBulge polylineArea = PolylineArea() polylineArea.Add(PolylineAreaPoint(innerStartPoint, innerBulge)) polylineArea.Add(PolylineAreaPoint(innerEndPoint)) polylineArea.Add(PolylineAreaPoint(outerEndPoint, -outerBulge)) polylineArea.Add(PolylineAreaPoint(outerStartPoint)) return polylineArea def makeArea(self, geomList, areaType): if areaType == ProtectionAreaType.Primary or areaType == ProtectionAreaType.Secondary: return self.makePrimaryAreaOrSecondaryArea(geomList, areaType) elif areaType == ProtectionAreaType.PrimaryAndSecondary: pointArray0 = geomList[0] pointArray1 = geomList[1] pointArray2 = geomList[2] pointArray3 = geomList[3] primaryArea = self.makePrimaryAreaOrSecondaryArea([pointArray0, pointArray2], ProtectionAreaType.Primary) secondaryArea1 = self.makePrimaryAreaOrSecondaryArea([pointArray0, pointArray1], ProtectionAreaType.Secondary) secondaryArea2 = self.makePrimaryAreaOrSecondaryArea([pointArray2, pointArray3], ProtectionAreaType.Secondary) return PrimarySecondaryObstacleArea(primaryArea, secondaryArea1, secondaryArea2) # if len(geomList[0]) == 2 and len(geomList[1]) == 2 and len(geomList[2]) == 2 and len(geomList[3]) == 2: # for i in range(1, len(geomList)): # pointArray0 = geomList[0] # pointArray1 = geomList[i] # line0 = QgsGeometry.fromPolyline([pointArray0[0], pointArray1[0]]) # line1 = QgsGeometry.fromPolyline([pointArray0[len(pointArray0) - 1], pointArray1[len(pointArray1) - 1]]) # if line0.intersects(line1): # pointArray1.reverse() # pointArray0 = geomList[0] # pointArray1 = geomList[1] # pointArray2 = geomList[2] # pointArray3 = geomList[3] # area = PrimarySecondaryObstacleArea() # area.set_areas(pointArray0, pointArray1, pointArray2, pointArray3) # return area # return None return None def makePrimaryAreaOrSecondaryArea(self, geomList, areaType): pointArrayInner = geomList[0] pointArray1Outer = geomList[1] innerStartPoint = pointArrayInner[0] innerEndPoint = pointArrayInner[1] innerBulge = pointArrayInner[2] outerStartPoint = pointArray1Outer[0] outerEndPoint = pointArray1Outer[1] outerBulge = pointArray1Outer[2] line0 = QgsGeometry.fromPolyline([innerStartPoint, outerStartPoint]) line1 = QgsGeometry.fromPolyline([innerEndPoint, outerEndPoint]) # for i in range(1, len(pointArray0)): if line0.intersects(line1): tempPoint = Point3D(outerStartPoint.get_X(), outerStartPoint.get_Y()) outerStartPoint = Point3D(outerEndPoint.get_X(), outerEndPoint.get_Y()) outerEndPoint = Point3D(tempPoint.get_X(), tempPoint.get_Y()) outerBulge = -outerBulge if areaType == ProtectionAreaType.Primary: polylineArea = PolylineArea() polylineArea.Add(PolylineAreaPoint(innerStartPoint, innerBulge)) polylineArea.Add(PolylineAreaPoint(innerEndPoint)) polylineArea.Add(PolylineAreaPoint(outerEndPoint, -outerBulge)) polylineArea.Add(PolylineAreaPoint(outerStartPoint)) return PrimaryObstacleArea(polylineArea) elif areaType == ProtectionAreaType.Secondary: if innerBulge == 0 and outerBulge == 0: return SecondaryObstacleArea(innerStartPoint, innerEndPoint, outerStartPoint, outerEndPoint, MathHelper.getBearing(innerStartPoint, innerEndPoint)) elif innerBulge != 0 and outerBulge != 0: if round(innerBulge, 1) != round(outerBulge, 1): return None innerCenterPoint = MathHelper.smethod_71(innerStartPoint, innerEndPoint, innerBulge) outerCenterPoint = MathHelper.smethod_71(outerStartPoint, outerEndPoint, outerBulge) innerRadius = MathHelper.calcDistance(innerCenterPoint, innerStartPoint); outerRadius = MathHelper.calcDistance(outerCenterPoint, outerStartPoint); bearing = (MathHelper.getBearing(innerCenterPoint, innerStartPoint) + MathHelper.getBearing(innerCenterPoint, innerEndPoint)) / 2 innerMiddlePoint = MathHelper.distanceBearingPoint(innerCenterPoint, bearing, innerRadius) if round(MathHelper.smethod_60(innerStartPoint, innerMiddlePoint, innerEndPoint), 4) != round(outerBulge, 4): bearing += 3.14159265358979 innerMiddlePoint = MathHelper.distanceBearingPoint(innerCenterPoint, bearing, innerRadius) bearing = (MathHelper.getBearing(outerCenterPoint, outerStartPoint) + MathHelper.getBearing(outerCenterPoint, outerEndPoint)) / 2 outerMiddlePoint = MathHelper.distanceBearingPoint(outerCenterPoint, bearing, outerRadius) if round(MathHelper.smethod_60(outerStartPoint, outerMiddlePoint, outerEndPoint), 4) != round(outerBulge, 4): bearing += 3.14159265358979 outerMiddlePoint = MathHelper.distanceBearingPoint(outerCenterPoint, bearing, outerRadius) return SecondaryObstacleArea(innerStartPoint, innerMiddlePoint, innerEndPoint, outerStartPoint, None, outerMiddlePoint, outerEndPoint, innerBulge, innerBulge) return None def snapPoint(self, p, bNone = False): if define._snapping == False: return (define._canvas.getCoordinateTransform().toMapCoordinates( p ), None, None) snappingResults = self.mSnapper.snapToBackgroundLayers( p ) 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)
class PickerAOIPointTool(QgsMapTool): def __init__(self, cad): QgsMapTool.__init__(self, cad.render_widget.canvas) self.cad = cad # set rubber band style color = QColor("red") color.setAlpha(70) # create the main polygon rubber band self.rubber_band = QgsRubberBand(cad.render_widget.canvas, QgsWkbTypes.PolygonGeometry) self.rubber_band.setColor(color) self.rubber_band.setWidth(3) # create the mouse/tmp polygon rubber band, this is main rubber band + current mouse position self.tmp_rubber_band = QgsRubberBand(cad.render_widget.canvas, QgsWkbTypes.PolygonGeometry) self.tmp_rubber_band.setColor(color) self.tmp_rubber_band.setWidth(3) self.tmp_rubber_band.setLineStyle(Qt.DotLine) def finish_drawing(self): self.rubber_band = None self.tmp_rubber_band = None # restart point tool self.clean() self.cad.render_widget.canvas.unsetMapTool(self) self.cad.render_widget.canvas.setMapTool( self.cad.render_widget.pan_zoom_tool) def canvasMoveEvent(self, event): if self.tmp_rubber_band is None: return if self.tmp_rubber_band and self.tmp_rubber_band.numberOfVertices(): x = event.pos().x() y = event.pos().y() point = self.cad.render_widget.canvas.getCoordinateTransform( ).toMapCoordinates(x, y) self.tmp_rubber_band.removeLastPoint() self.tmp_rubber_band.addPoint(point) def keyPressEvent(self, event): if event.key() == Qt.Key_Backspace or event.key() == Qt.Key_Delete: self.rubber_band.removeLastPoint() self.tmp_rubber_band.removeLastPoint() if event.key() == Qt.Key_Escape: self.rubber_band.reset(QgsWkbTypes.PolygonGeometry) self.tmp_rubber_band.reset(QgsWkbTypes.PolygonGeometry) def canvasPressEvent(self, event): if self.rubber_band is None: self.finish_drawing() return # new point on polygon if event.button() == Qt.LeftButton: x = event.pos().x() y = event.pos().y() point = self.cad.render_widget.canvas.getCoordinateTransform( ).toMapCoordinates(x, y) self.rubber_band.addPoint(point) self.tmp_rubber_band.addPoint(point) # save polygon if event.button() == Qt.RightButton: if self.rubber_band and self.rubber_band.numberOfVertices(): if self.rubber_band.numberOfVertices() < 3: self.finish_drawing() return self.tmp_rubber_band.removeLastPoint() new_feature = QgsFeature() new_feature.setGeometry(self.rubber_band.asGeometry()) self.cad.rubber_bands.append(self.rubber_band) self.cad.tmp_rubber_band.append(self.tmp_rubber_band) self.rubber_band = None self.tmp_rubber_band = None self.finish_drawing() # add the new feature and update the statistics self.cad.aoi_changes(new_feature) def keyReleaseEvent(self, event): if event.key() in [ Qt.Key_Up, Qt.Key_Down, Qt.Key_Right, Qt.Key_Left, Qt.Key_PageUp, Qt.Key_PageDown ]: QTimer.singleShot( 10, self.cad.render_widget.parent_view.canvas_changed)
class DsgLineTool(QgsMapTool): lineCreated = pyqtSignal(QgsGeometry) def __init__(self, canvas): """ Constructor """ super(DsgLineTool, self).__init__(canvas) self.canvas = canvas self.rubberBand = None self.reset() def deactivate(self): """ Deativates this tool """ self.canvas.scene().removeItem(self.rubberBand) super(DsgLineTool, self).deactivate() def defineRubberBand(self): """ Defines the rubber band style """ settings = QSettings() myRed = int(settings.value("/qgis/default_measure_color_red", 222)) myGreen = int(settings.value("/qgis/default_measure_color_green", 155)) myBlue = int(settings.value("/qgis/default_measure_color_blue", 67)) self.rubberBand = QgsRubberBand(self.canvas) self.rubberBand.setColor(QColor(myRed, myGreen, myBlue, 100)) self.rubberBand.setWidth(3) def reset(self): """ Resets the tool """ if self.rubberBand: self.rubberBand.reset(QGis.Line) self.isEmittingPoint = False self.defineRubberBand() def canvasPressEvent(self, e): """ Reimplementation to add a point to the rubber band or reset it """ if self.isEmittingPoint: point = self.snapPoint(e.pos()) self.rubberBand.addPoint(point, True) else: self.reset() self.isEmittingPoint = True def canvasReleaseEvent(self, e): """ Reimplementation to add a vertex to the rubber band or to finish the rubber band according to the button used """ point = self.snapPoint(e.pos()) if e.button() == Qt.RightButton: geom = self.rubberBand.asGeometry() self.reset() self.lineCreated.emit(geom) elif e.button() == Qt.LeftButton: self.isEmittingPoint = True self.rubberBand.addPoint(point, True) def canvasMoveEvent(self, e): """ Reimplementation to move the rubber band """ if not self.isEmittingPoint: return point = self.snapPoint(e.pos()) self.rubberBand.movePoint(point) def snapPoint(self, p): """ Reimplementation to make use of the snap """ m = self.canvas.snappingUtils().snapToMap(p) if m.isValid(): return m.point() else: return self.canvas.getCoordinateTransform().toMapCoordinates(p)
class PolygonMapTool(QgsMapToolEmitPoint): """This class holds a map tool to create a polygon from points got by clicking on the map window. Points are stored in a list of point geometries, which is returned to the main plugin for use.""" def __init__(self, canvas): self.canvas = canvas QgsMapToolEmitPoint.__init__(self, self.canvas) # rubberband class gives the user visual feedback of the drawing self.rubberBand = QgsRubberBand(self.canvas, True) # setting up outline and fill color: both red self.rubberBand.setColor(QColor(235, 36, 21)) # RGB color values, last value indicates transparency (0-255) self.rubberBand.setFillColor(QColor(255, 79, 66, 140)) self.rubberBand.setWidth(3) self.points = [] # a flag indicating when a single polygon is finished self.finished = False self.poly_bbox = False self.double_click_flag = False self.reset() def reset(self): """Empties the canvas and the points gathered thus far""" self.rubberBand.reset(True) self.poly_bbox = False self.points.clear() def keyPressEvent(self, e): """Pressing ESC resets the canvas. Pressing enter connects the polygon""" if (e.key() == 16777216): self.reset() if (e.key() == 16777220): self.finishPolygon() def canvasDoubleClickEvent(self, e): self.double_click_flag = True self.finishPolygon() def canvasReleaseEvent(self, e): """Activated when user clicks on the canvas. Gets coordinates, draws them on the map and adds to the list of points.""" if self.double_click_flag: self.double_click_flag = False return # if the finished flag is activated, the canvas will be must be reset # for a new polygon if self.finished: self.reset() self.finished = False self.click_point = self.toMapCoordinates(e.pos()) self.rubberBand.addPoint(self.click_point, True) self.points.append(self.click_point) self.rubberBand.show() def finishPolygon(self): """Activated when by user or when the map window is closed without connecting the polygon. Makes the polygon valid by making first and last point the same. This is reflected visually. Up until now the user has been drawing a line: a polygon is created and shown on the map.""" # nothing will happen if the code below has already been ran if self.finished: return # connecting the polygon is valid if there's already at least 3 points elif len(self.points) > 2: first_point = self.points[0] self.points.append(first_point) self.rubberBand.closePoints() self.rubberBand.addPoint(first_point, True) self.finished = True # a polygon is created and added to the map for visual purposes map_polygon = QgsGeometry.fromPolygonXY([self.points]) self.rubberBand.setToGeometry(map_polygon) # get the bounding box of this new polygon self.poly_bbox = self.rubberBand.asGeometry().boundingBox() else: self.finished = True def getPoints(self): """Returns list of PointXY geometries, i.e. the polygon in list form""" self.rubberBand.reset(True) return self.points def getPolyBbox(self): return self.poly_bbox
class 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 PlanetAOIFilter(AOI_FILTER_BASE, AOI_FILTER_WIDGET, PlanetFilterMixin): filtersChanged = pyqtSignal() savedSearchSelected = pyqtSignal(object) zoomToAOIRequested = pyqtSignal() def __init__( self, parent=None, plugin=None, color=MAIN_AOI_COLOR, ): super().__init__(parent=parent) self._plugin = plugin self.setupUi(self) self.emitFiltersChanged = False self.color = color self._aoi_box = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self._aoi_box.setFillColor(QColor(0, 0, 0, 0)) self._aoi_box.setStrokeColor(color) self._aoi_box.setWidth(3) self._aoi_box.setLineStyle(Qt.DashLine) self._canvas: QgsMapCanvas = iface.mapCanvas() # This may later be a nullptr, if no active tool when queried self._cur_maptool = None self.leAOI.textChanged["QString"].connect(self.filters_changed) self.leAOI.textEdited["QString"].connect(self.validate_edited_aoi) self._setup_tool_buttons() # Extent line edit tools self.btnZoomToAOI.clicked.connect(self.zoom_to_aoi) self.btnCopyAOI.clicked.connect(self.copy_aoi_to_clipboard) self.p_client = PlanetClient.getInstance() def reset_aoi_box(self): self.leAOI.setText("") if self._aoi_box: self._aoi_box.reset(QgsWkbTypes.PolygonGeometry) def filters(self): filters = [] if self.leAOI.text(): try: qgsgeom = qgsgeometry_from_geojson(self.leAOI.text()) if not qgsgeom.isEmpty(): geom_json = json.loads(qgsgeom.asJson()) filters.append(geom_filter(geom_json)) else: self._show_message("AOI not valid GeoJSON polygon", level=Qgis.Warning, duration=10) except Exception: self._show_message("AOI not valid JSON", level=Qgis.Warning, duration=10) finally: return filters def filters_as_json(self): filters = [] if self.leAOI.text(): filters.append(self.leAOI.text()) return filters def set_from_request(self, request): self.emitFiltersChanged = False filters = filters_from_request(request, "geometry") if filters: geom = filters[0]["config"] txt = json.dumps(geom) self.leAOI.setText(txt) else: self.leAOI.setText("") self.emitFiltersChanged = True @pyqtSlot("QString") def filters_changed(self, value): if self.emitFiltersChanged: self.filtersChanged.emit() @pyqtSlot() def clean_up(self): self.reset_aoi_box() def _setup_tool_buttons(self): extent_menu = QMenu(self) canvas_act = QAction("Current visible extent", extent_menu) canvas_act.triggered[bool].connect(self.aoi_from_current_extent) extent_menu.addAction(canvas_act) active_act = QAction("Active map layer extent", extent_menu) active_act.triggered[bool].connect(self.aoi_from_active_layer_extent) extent_menu.addAction(active_act) full_act = QAction("All map layers extent", extent_menu) full_act.triggered[bool].connect(self.aoi_from_full_extent) extent_menu.addAction(full_act) self.btnExtent.setMenu(extent_menu) # Also show menu on click, to keep disclosure triangle visible self.btnExtent.clicked.connect(self.btnExtent.showMenu) draw_menu = QMenu(self) box_act = QAction("Rectangle", draw_menu) box_act.triggered[bool].connect(self.aoi_from_box) draw_menu.addAction(box_act) circle_act = QAction("Circle", draw_menu) circle_act.triggered[bool].connect(self.aoi_from_circle) draw_menu.addAction(circle_act) polygon_act = QAction("Polygon", draw_menu) polygon_act.triggered[bool].connect(self.aoi_from_polygon) draw_menu.addAction(polygon_act) self.btnDraw.setMenu(draw_menu) # Also show menu on click, to keep disclosure triangle visible self.btnDraw.clicked.connect(self.btnDraw.showMenu) selection_menu = QMenu(self) self.single_select_act = QAction("Single feature", selection_menu) self.single_select_act.triggered[bool].connect(self.aoi_from_feature) selection_menu.addAction(self.single_select_act) self.bound_select_act = QAction("Multiple features (bounding box)", selection_menu) self.bound_select_act.triggered[bool].connect(self.aoi_from_bound) selection_menu.addAction(self.bound_select_act) self.btnSelection.setMenu(selection_menu) # Also show menu on click, to keep disclosure triangle visible self.btnSelection.clicked.connect(self._toggle_selection_tools) self.btnSelection.clicked.connect(self.btnSelection.showMenu) upload_menu = QMenu(self) upload_act = QAction("Upload vector layer file", upload_menu) upload_act.triggered[bool].connect(self.upload_file) upload_menu.addAction(upload_act) self.btnUpload.setMenu(upload_menu) self.btnUpload.clicked.connect(self.btnUpload.showMenu) def upload_file(self): filename, _ = QFileDialog.getOpenFileName(self, "Select AOI file", "", "All files(*.*)") if filename: layer = QgsVectorLayer(filename, "") self.aoi_from_layer(layer) def aoi_from_layer(self, layer): if not layer.isValid(): self._show_message("Invalid layer", level=Qgis.Warning, duration=10) else: feature = next(layer.getFeatures(), None) if feature is None: self._show_message("Layer contains no features", level=Qgis.Warning, duration=10) else: geom = feature.geometry() transform = QgsCoordinateTransform( layer.crs(), QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance(), ) try: geom.transform(transform) except QgsCsException: self._show_message( "Could not convert AOI to EPSG:4326", level=Qgis.Warning, duration=10, ) return geom_json = geom.asJson(precision=6) self._aoi_box.setToGeometry(geom) self.leAOI.setText(geom_json) log.debug("AOI set to layer") self.zoom_to_aoi() def _toggle_selection_tools(self): active_layer = iface.activeLayer() is_vector = isinstance(active_layer, QgsVectorLayer) if is_vector and active_layer.selectedFeatureCount(): if active_layer.selectedFeatureCount() > 1: self.single_select_act.setEnabled(False) self.bound_select_act.setEnabled(True) elif active_layer.selectedFeatureCount(): self.single_select_act.setEnabled(True) self.bound_select_act.setEnabled(False) else: self.single_select_act.setEnabled(False) self.bound_select_act.setEnabled(False) else: self.single_select_act.setEnabled(False) self.bound_select_act.setEnabled(False) @pyqtSlot() def aoi_from_current_extent(self): """Return current map extent as geojson transformed to EPSG:4326""" canvas = iface.mapCanvas() transform = QgsCoordinateTransform( QgsProject.instance().crs(), QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance(), ) canvas_extent: QgsRectangle = canvas.extent() try: transform_extent = transform.transformBoundingBox(canvas_extent) except QgsCsException: self._show_message("Could not convert AOI to EPSG:4326", level=Qgis.Warning, duration=10) return geom_extent = QgsGeometry.fromRect(transform_extent) extent_json = geom_extent.asJson(precision=6) self._aoi_box.setToGeometry(QgsGeometry.fromRect(canvas.extent())) self.leAOI.setText(extent_json) log.debug("AOI set to canvas extent") self.zoom_to_aoi() @pyqtSlot() def aoi_from_active_layer_extent(self): """Return active map layer extent as geojson transformed to EPSG:4326""" map_layer: QgsMapLayer = iface.activeLayer() if map_layer is None: log.debug("No active layer selected, skipping AOI extent") return if not map_layer.isValid(): log.debug("Active map layer invalid, skipping AOI extent") return transform = QgsCoordinateTransform( map_layer.crs(), QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance(), ) ml_extent: QgsRectangle = map_layer.extent() try: transform_extent = transform.transformBoundingBox(ml_extent) except QgsCsException: self._show_message("Could not convert AOI to EPSG:4326", level=Qgis.Warning, duration=10) return geom_extent = QgsGeometry.fromRect(transform_extent) extent_json = geom_extent.asJson(precision=6) self.leAOI.setText(extent_json) log.debug("AOI set to active layer extent") self.zoom_to_aoi() @pyqtSlot() def aoi_from_full_extent(self): """Return full data map extent as geojson transformed to EPSG:4326""" canvas = iface.mapCanvas() transform = QgsCoordinateTransform( QgsProject.instance().crs(), QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance(), ) canvas_extent: QgsRectangle = canvas.fullExtent() if canvas_extent.isNull(): # Canvas not yet initialized return try: transform_extent = transform.transformBoundingBox(canvas_extent) except QgsCsException: self._show_message("Could not convert AOI to EPSG:4326", level=Qgis.Warning, duration=10) return geom_extent = QgsGeometry.fromRect(transform_extent) extent_json = geom_extent.asJson(precision=6) self._aoi_box.setToGeometry(QgsGeometry.fromRect(canvas_extent)) self.leAOI.setText(extent_json) log.debug("AOI set to full data extent") self.zoom_to_aoi() @pyqtSlot() def aoi_from_box(self): self._cur_maptool: QgsMapTool = self._canvas.mapTool() self._aoi_box.reset(QgsWkbTypes.PolygonGeometry) aoi_draw = PlanetExtentMapTool(iface.mapCanvas()) iface.mapCanvas().setMapTool(aoi_draw) aoi_draw.extentSelected.connect(self.set_draw_aoi) @pyqtSlot() def aoi_from_circle(self): self._cur_maptool: QgsMapTool = self._canvas.mapTool() self._aoi_box.reset(QgsWkbTypes.PolygonGeometry) aoi_draw = PlanetCircleMapTool(iface.mapCanvas()) iface.mapCanvas().setMapTool(aoi_draw) aoi_draw.circleSelected.connect(self.set_draw_aoi) @pyqtSlot() def aoi_from_polygon(self): self._cur_maptool: QgsMapTool = self._canvas.mapTool() self._aoi_box.reset(QgsWkbTypes.PolygonGeometry) aoi_draw = PlanetPolyMapTool(iface.mapCanvas()) iface.mapCanvas().setMapTool(aoi_draw) aoi_draw.polygonSelected.connect(self.set_draw_aoi) @pyqtSlot(object) def set_draw_aoi(self, aoi): transform = QgsCoordinateTransform( QgsProject.instance().crs(), QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance(), ) aoi_json = None if isinstance(aoi, QgsRectangle): aoi_geom = QgsGeometry().fromRect(aoi) self._aoi_box.setToGeometry(aoi_geom) aoi_geom.transform(transform) aoi_json = aoi_geom.asJson(precision=6) if isinstance(aoi, QgsGeometry): self._aoi_box.setToGeometry(aoi) # TODO: validate geom is less than 500 vertices aoi.transform(transform) aoi_json = aoi.asJson(precision=6) if aoi_json: self.leAOI.setText(aoi_json) self._show_message("AOI set to drawn figure") self.zoom_to_aoi() if self._cur_maptool is not None: # Restore previously used maptool self._canvas.setMapTool(self._cur_maptool) self._cur_maptool = None else: # Fallback to activating pan tool iface.actionPan().trigger() else: self._show_message("AOI unable to be set", level=Qgis.Warning, duration=10) @pyqtSlot() def aoi_from_feature(self): layer = iface.activeLayer() if not isinstance(layer, QgsVectorLayer): self._show_message("Active layer must be a vector layer.", level=Qgis.Warning, duration=10) return if layer.selectedFeatureCount() > 1: self._show_message( "More than 1 feature. Searching by bbox.", level=Qgis.Warning, duration=10, ) self.aoi_from_bound() return elif layer.selectedFeatureCount() < 1: self._show_message("No features selected.", level=Qgis.Warning, duration=10) return selected: QgsFeature = layer.selectedFeatures()[0] geom: QgsGeometry = selected.geometry() if geom.constGet().vertexCount() > 500: self._show_message( "More than 500 vertices. Searching by bbox.", level=Qgis.Warning, duration=10, ) self.aoi_from_bound() return trans_layer = QgsCoordinateTransform( layer.sourceCrs(), QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance(), ) trans_canvas = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance().crs(), QgsProject.instance(), ) # geom.transform(transform) geom.transform(trans_layer) geom_json = geom.asJson(precision=6) self.leAOI.setText(geom_json) geom.transform(trans_canvas) self._aoi_box.setToGeometry(geom, QgsCoordinateReferenceSystem("EPSG:4326")) self.zoom_to_aoi() @pyqtSlot() def aoi_from_bound(self): layer = iface.activeLayer() if not isinstance(layer, QgsVectorLayer): self._show_message("Active layer must be a vector layer.", level=Qgis.Warning, duration=10) return if layer.selectedFeatureCount() < 1: self._show_message("No features selected.", level=Qgis.Warning, duration=10) return bbox = layer.boundingBoxOfSelected() trans_layer = QgsCoordinateTransform( layer.sourceCrs(), QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance(), ) trans_canvas = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance().crs(), QgsProject.instance(), ) transform_bbox = trans_layer.transformBoundingBox(bbox) geom_bbox = QgsGeometry.fromRect(transform_bbox) bbox_json = geom_bbox.asJson(precision=6) self.leAOI.setText(bbox_json) bbox_canvas = trans_canvas.transformBoundingBox(transform_bbox) self._aoi_box.setToGeometry(QgsGeometry.fromRect(bbox_canvas)) self.zoom_to_aoi() def hide_aoi_if_matches_geom(self, geom): color = (QColor(0, 0, 0, 0) if self._aoi_box.asGeometry().equals(geom) else self.color) self._aoi_box.setStrokeColor(color) def show_aoi(self): if self._aoi_box is not None: self._aoi_box.setStrokeColor(self.color) def aoi_geom(self): if self._aoi_box is not None: return self._aoi_box.asGeometry() def aoi_as_4326_geom(self): transform = QgsCoordinateTransform( QgsProject.instance().crs(), QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance(), ) geom = self.aoi_geom() if geom is not None: geom.transform(transform) return geom @pyqtSlot() def zoom_to_aoi(self): if not self.leAOI.text(): log.debug("No AOI defined, skipping zoom to AOI") return geom: QgsGeometry = qgsgeometry_from_geojson(self.leAOI.text()) if geom.isEmpty(): self._show_message("AOI GeoJSON geometry invalid", level=Qgis.Warning, duration=10) return self._aoi_box.setToGeometry(geom, QgsCoordinateReferenceSystem("EPSG:4326")) self.show_aoi() zoom_canvas_to_aoi(self.leAOI.text()) self.zoomToAOIRequested.emit() @pyqtSlot() def copy_aoi_to_clipboard(self): if not self.leAOI.text(): log.debug("No AOI defined, skipping zoom to AOI") return try: json_obj = json.loads(self.leAOI.text()) except ValueError: return json_geom_txt = json.dumps(json_obj, indent=2) cb = QgsApplication.clipboard() cb.setText(json_geom_txt) self._show_message("AOI copied to clipboard") @pyqtSlot() def validate_edited_aoi(self): json_txt = self.leAOI.text() if not json_txt: self.reset_aoi_box() log.debug("No AOI defined, skipping validation") return try: json_obj = json.loads(json_txt) except ValueError: self._show_message("AOI GeoJSON is invalid", level=Qgis.Warning, duration=10) return try: json_geom = geometry_from_json(json_obj) except Exception: json_geom = None if not json_geom: self._show_message("AOI GeoJSON geometry invalid", level=Qgis.Warning, duration=10) return geom: QgsGeometry = qgsgeometry_from_geojson(json_geom) self._aoi_box.setToGeometry(geom, QgsCoordinateReferenceSystem("EPSG:4326")) self.leAOI.blockSignals(True) self.leAOI.setText(json.dumps(json_geom)) self.leAOI.blockSignals(False) self.zoom_to_aoi()
class Geo360Dialog(QDockWidget, Ui_orbitalDialog): """Geo360 Dialog Class""" def __init__(self, iface, parent=None, featuresId=None, layer=None): QDockWidget.__init__(self) self.setupUi(self) self.DEFAULT_URL = ("http://" + config.IP + ":" + str(config.PORT) + "/viewer.html") self.DEFAULT_EMPTY = ("http://" + config.IP + ":" + str(config.PORT) + "/none.html") self.DEFAULT_BLANK = ("http://" + config.IP + ":" + str(config.PORT) + "/blank.html") # Create Viewer self.CreateViewer() self.plugin_path = os.path.dirname(os.path.realpath(__file__)) self.iface = iface self.canvas = self.iface.mapCanvas() self.parent = parent # Orientation from image self.yaw = math.pi self.bearing = None self.layer = layer self.featuresId = featuresId self.actualPointDx = None self.actualPointSx = None self.actualPointOrientation = None self.selected_features = qgsutils.getToFeature(self.layer, self.featuresId) # Get image path self.current_image = self.GetImage() # Check if image exist if os.path.exists(self.current_image) is False: qgsutils.showUserAndLogMessage(u"Information: ", u"There is no associated image.") self.resetQgsRubberBand() self.ChangeUrlViewer(self.DEFAULT_EMPTY) return # Copy file to local server self.CopyFile(self.current_image) # Set RubberBand self.resetQgsRubberBand() self.setOrientation() self.setPosition() """Update data from Marzipano Viewer""" def onNewData(self, data): try: newYaw = float(data[0]) self.UpdateOrientation(yaw=newYaw) except: None def CreateViewer(self): """Create Viewer""" qgsutils.showUserAndLogMessage(u"Information: ", u"Create viewer", onlyLog=True) self.cef_widget = QWebView() self.cef_widget.setContextMenuPolicy(Qt.NoContextMenu) self.cef_widget.settings().setAttribute(QWebSettings.JavascriptEnabled, True) pano_view_settings = self.cef_widget.settings() pano_view_settings.setAttribute(QWebSettings.WebGLEnabled, True) # pano_view_settings.setAttribute(QWebSettings.DeveloperExtrasEnabled, True) pano_view_settings.setAttribute( QWebSettings.Accelerated2dCanvasEnabled, True) pano_view_settings.setAttribute(QWebSettings.JavascriptEnabled, True) self.page = _ViewerPage() self.page.newData.connect(self.onNewData) self.cef_widget.setPage(self.page) self.cef_widget.load(QUrl(self.DEFAULT_URL)) self.ViewerLayout.addWidget(self.cef_widget, 1, 0) # def SetInitialYaw(self): # """Set Initial Viewer Yaw""" # self.bearing = self.selected_features.attribute(config.column_yaw) # # self.view.browser.GetMainFrame().ExecuteFunction("InitialYaw", # # self.bearing) # return def RemoveImage(self): """Remove Image""" try: os.remove(self.plugin_path + "/viewer/image.jpg") except OSError: pass def CopyFile(self, src): """Copy Image File in Local Server""" qgsutils.showUserAndLogMessage(u"Information: ", u"Copying image", onlyLog=True) src_dir = src dst_dir = self.plugin_path + "/viewer" # Copy image in local folder img = Image.open(src_dir) rgb_im = img.convert("RGB") dst_dir = dst_dir + "/image.jpg" try: os.remove(dst_dir) except OSError: pass rgb_im.save(dst_dir) def GetImage(self): """Get Selected Image""" try: path = qgsutils.getAttributeFromFeature(self.selected_features, config.column_name) if not os.path.isabs(path): # Relative Path to Project path_project = QgsProject.instance().readPath("./") path = os.path.normpath(os.path.join(path_project, path)) except Exception: qgsutils.showUserAndLogMessage(u"Information: ", u"Column not found.") return qgsutils.showUserAndLogMessage(u"Information: ", str(path), onlyLog=True) return path def ChangeUrlViewer(self, new_url): """Change Url Viewer""" self.cef_widget.load(QUrl(new_url)) def ReloadView(self, newId): """Reaload Image viewer""" self.setWindowState(self.windowState() & ~Qt.WindowMinimized | Qt.WindowActive) # this will activate the window self.activateWindow() self.selected_features = qgsutils.getToFeature(self.layer, newId) self.current_image = self.GetImage() # Check if image exist if os.path.exists(self.current_image) is False: qgsutils.showUserAndLogMessage(u"Information: ", u"There is no associated image.") self.ChangeUrlViewer(self.DEFAULT_EMPTY) self.resetQgsRubberBand() return # Set RubberBand self.resetQgsRubberBand() self.setOrientation() self.setPosition() # Copy file to local server self.CopyFile(self.current_image) self.ChangeUrlViewer(self.DEFAULT_URL) def GetBackNextImage(self): """Get to Back Image""" sender = QObject.sender(self) lys = self.canvas.layers() # Check if mapa foto is loaded if len(lys) == 0: qgsutils.showUserAndLogMessage(u"Information: ", u"You need load the photo layer.") return for layer in lys: if layer.name() == config.layer_name: self.encontrado = True self.iface.setActiveLayer(layer) f = self.selected_features ac_lordem = f.attribute(config.column_order) if sender.objectName() == "btn_back": new_lordem = int(ac_lordem) - 1 else: new_lordem = int(ac_lordem) + 1 # Filter mapa foto layer ids = [ feat.id() for feat in layer.getFeatures(QgsFeatureRequest( ).setFilterExpression(config.column_order + " ='" + str(new_lordem) + "'")) ] if len(ids) == 0: qgsutils.showUserAndLogMessage( u"Information: ", u"There is no superiority that follows.") # Filter mapa foto layer ids = [ feat.id() for feat in layer.getFeatures(QgsFeatureRequest( ).setFilterExpression(config.column_order + " ='" + str(ac_lordem) + "'")) ] # Update selected feature self.ReloadView(ids[0]) if self.encontrado is False: qgsutils.showUserAndLogMessage( u"Information: ", u"You need a layer with images and set the name in the config.py file.", ) return def FullScreen(self, value): """FullScreen action button""" qgsutils.showUserAndLogMessage(u"Information: ", u"Fullscreen.", onlyLog=True) if value: self.showFullScreen() else: self.showNormal() def UpdateOrientation(self, yaw=None): """Update Orientation""" self.bearing = self.selected_features.attribute(config.column_yaw) try: self.actualPointOrientation.reset() except Exception: pass self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.LineGeometry) self.actualPointOrientation.setColor(Qt.blue) self.actualPointOrientation.setWidth(5) self.actualPointOrientation.addPoint(self.actualPointDx) # End Point CS = self.canvas.mapUnitsPerPixel() * 25 A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2) A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2) self.actualPointOrientation.addPoint(QgsPointXY( float(A1x), float(A1y))) # Vision Angle if yaw is not None: angle = float(self.bearing + yaw) * math.pi / -180 else: angle = float(self.bearing) * math.pi / -180 tmpGeom = self.actualPointOrientation.asGeometry() rotatePoint = self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle) self.actualPointOrientation.setToGeometry(rotatePoint, self.dumLayer) # Set Azimut value tmpGeom = rotatePoint.asPolyline() azim = tmpGeom[0].azimuth(tmpGeom[1]) if azim < 0: azim += 360 self.yawLbl.setText("Yaw : " + str(round(yaw, 2)) + " Azimut : " + str(round(azim, 2))) def setOrientation(self, yaw=None): """Set Orientation in the firt time""" self.bearing = self.selected_features.attribute(config.column_yaw) originalPoint = self.selected_features.geometry().asPoint() self.actualPointDx = qgsutils.convertProjection( originalPoint.x(), originalPoint.y(), self.layer.crs().authid(), self.canvas.mapSettings().destinationCrs().authid(), ) self.actualPointOrientation = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.LineGeometry) self.actualPointOrientation.setColor(Qt.blue) self.actualPointOrientation.setWidth(5) self.actualPointOrientation.addPoint(self.actualPointDx) # End Point CS = self.canvas.mapUnitsPerPixel() * 25 A1x = self.actualPointDx.x() - CS * math.cos(math.pi / 2) A1y = self.actualPointDx.y() + CS * math.sin(math.pi / 2) self.actualPointOrientation.addPoint(QgsPointXY( float(A1x), float(A1y))) # Vision Angle if yaw is not None: angle = float(self.bearing + yaw) * math.pi / -180 else: angle = float(self.bearing) * math.pi / -180 tmpGeom = self.actualPointOrientation.asGeometry() self.rotateTool = transformGeometry() epsg = self.canvas.mapSettings().destinationCrs().authid() self.dumLayer = QgsVectorLayer("Point?crs=" + epsg, "temporary_points", "memory") self.actualPointOrientation.setToGeometry( self.rotateTool.rotate(tmpGeom, self.actualPointDx, angle), self.dumLayer) def setPosition(self): """Set RubberBand Position""" # Transform Point originalPoint = self.selected_features.geometry().asPoint() self.actualPointDx = qgsutils.convertProjection( originalPoint.x(), originalPoint.y(), "EPSG:4326", self.canvas.mapSettings().destinationCrs().authid(), ) self.positionDx = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.positionDx.setWidth(6) self.positionDx.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionDx.setIconSize(6) self.positionDx.setColor(Qt.black) self.positionSx = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.positionSx.setWidth(5) self.positionSx.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionSx.setIconSize(4) self.positionSx.setColor(Qt.blue) self.positionInt = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PointGeometry) self.positionInt.setWidth(5) self.positionInt.setIcon(QgsRubberBand.ICON_CIRCLE) self.positionInt.setIconSize(3) self.positionInt.setColor(Qt.white) self.positionDx.addPoint(self.actualPointDx) self.positionSx.addPoint(self.actualPointDx) self.positionInt.addPoint(self.actualPointDx) def closeEvent(self, _): """Close dialog""" self.resetQgsRubberBand() self.canvas.refresh() self.iface.actionPan().trigger() self.parent.orbitalViewer = None self.RemoveImage() def resetQgsRubberBand(self): """Remove RubbeBand""" try: self.yawLbl.setText("") self.positionSx.reset() self.positionInt.reset() self.positionDx.reset() self.actualPointOrientation.reset() except Exception: None
class GPS(QObject): def __init__(self, gtomain): super(GPS, self).__init__() self.gtomain = gtomain self.debug = self.gtomain.debug self.helper = self.gtomain.helper self.iface = self.gtomain.iface self.info = self.gtomain.info self.prj = None self.canvas = self.iface.mapCanvas() self.gpsLog = Info(self) self.gpsLog.panel_name = "GTO-GPS" self.mouse = None self.LastMapTool = None try: # settings self.settings = None self.timer_intervall = 1000 self.port = None self.pdop = 0 self.wgs_crs = 'EPSG:4326' self.gps_streaming_distance = 10 # refs self.gpsCon = None self.gpsDetector = None self.gps_active = False self.dic_gpsinfo = {} self.prj_crs = None self.src_crs = None self.transformation = None self.marker = None self.prevPointXY = None self.prevTime = None self.lastGpsInfo = None self.center = False self.scale = 0 # actions mw = self.iface.mainWindow() self.actionGPStoggle = QAction("GTO-GPS", mw) self.actionGPStoggle.setObjectName('mActionGTOgpsToggle') self.actionGPStoggle.setToolTip('GTO GPS starten') self.actionGPStoggle.setIcon( self.gtomain.helper.getIcon('mActionGTOgpsToggle.png')) self.actionGPStoggle.setCheckable(True) self.actionGPStoggle.setChecked(False) self.actionGPStoggle.toggled.connect(self.activate) self.actionGPSaddPoint = QAction("GPS Punkt hinzufügen", mw) self.actionGPSaddPoint.setObjectName('mActionGTOgpsAddPoint') self.actionGPSaddPoint.setToolTip('GPS Punkt hinzufügen') self.actionGPSaddPoint.setIcon( self.gtomain.helper.getIcon('mActionGTOgpsAddPoint.png')) self.actionGPSaddPoint.triggered.connect(self.addPoint) self.actionGPSaddPoint.setEnabled(False) self.actionGPSclick = QAction("GPS Punkt hinzufügen", mw) self.actionGPSclick.setObjectName('mActionGTOgpsAddcPoint') self.actionGPSclick.setToolTip('GPS Punkt hinzufügen') self.actionGPSclick.setIcon( self.gtomain.helper.getIcon('mActionGTOgpsAddcPoint.png')) self.actionGPSclick.triggered.connect(self.gps_click) self.actionGPSclick.setEnabled(False) self.actionGPSstreaming = QAction("GPS streaming", mw) self.actionGPSstreaming.setObjectName('mActionGTOgpsStream') self.actionGPSstreaming.setToolTip('GPS Punkte aufzeichnen') self.actionGPSstreaming.setIcon( self.gtomain.helper.getIcon('mActionGTOgpsStream.png')) self.actionGPSstreaming.setCheckable(True) self.actionGPSstreaming.setEnabled(False) self.actionGPSstreaming.toggled.connect(self.streaming) self.actionGPSsave = QAction("GPS Geometrie speichern", mw) self.actionGPSsave.setObjectName('mActionGTOgpsSave') self.actionGPSsave.setToolTip('GPS Geometrie speichern') self.actionGPSsave.setIcon( self.gtomain.helper.getIcon('mActionGTOgpsSave.png')) self.actionGPSsave.triggered.connect(self.saveGeometry) self.actionGPSsave.setEnabled(False) self.actionGPSaddVertexTool = QAction("GPS AddVertexTool", mw) self.actionGPSaddVertexTool.setObjectName( 'mActionGTOgpsAddVertexTool') self.actionGPSaddVertexTool.setToolTip('GPS add vertex to stream') self.actionGPSaddVertexTool.setIcon( self.gtomain.helper.getIcon('mActionGTOgpsAddVertexTool.png')) self.actionGPSaddVertexTool.setCheckable(True) self.actionGPSaddVertexTool.toggled.connect( self.activateVertexTool) self.actionGPSaddVertexTool.setEnabled(False) # add vertex tool self.streamTool = VertexTool(self.iface, self.canvas, True) self.streamTool.canvasReleased.connect(self.addVertex) self.streamTool.isActive.connect(self.tool_isactive) self.actionGPSlog = QAction("GPS Log", mw) self.actionGPSlog.setObjectName('mActionGTOgpsLog') self.actionGPSlog.setToolTip('GPS events anzeigen') self.actionGPSlog.setIcon( self.gtomain.helper.getIcon('mActionGTOgpsLog.png')) self.actionGPSlog.setCheckable(True) self.actionGPScenter = QAction("GPS zentriere Karte", mw) self.actionGPScenter.setObjectName('mActionGTOgpsCenter') self.actionGPScenter.setToolTip('GPS zentriere Karte') self.actionGPScenter.setIcon( self.gtomain.helper.getIcon('mActionGTOgpsCenter.png')) self.actionGPScenter.setCheckable(True) self.actionGPScenter.toggled.connect(self.activateCenter) self.actionGPSport = GtoWidgetGpsPort(self, mw) self.actionGPSport.portChanged.connect(self.setPort) self.canvas.currentLayerChanged.connect(self.layer_changed) # streaming self.debugXoffset = 0 # debugging self.debugYoffset = 0 # rubberband # 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, 90)) self.rb.setFillColor(mycolor) self.rb.setLineStyle(Qt.PenStyle(Qt.SolidLine)) self.rb.setWidth(4) # watchdog self.watchdog = QTimer() self.watchdog.setInterval(2000) self.watchdog.timeout.connect(self.watch_dog) # layer self.streamLayer = None self.pointLayer = None self.gps_stream_mode = 0 # "0=rubber, 1=click, 2=both self.gps_debug = False except Exception as e: self.info.err(e) def watch_dog(self): try: self.watchdog.stop() self.gpsLog.log('Status:', self.gpsCon.status()) # doesnt work properly self.marker.setColor(QColor(255, 0, 0)) if self.actionGPSlog.isChecked(): self.gpsLog.log('No signal!') res = self.info.gtoQuestion("GPS deaktivieren? (Empfohlen)", title='Kein GPS Signal!', btns=QMessageBox.Yes | QMessageBox.No, parent=self.iface.mainWindow()) if res == QMessageBox.Yes: self.deactivate() self.actionGPStoggle.setChecked(False) except Exception as e: self.info.err(e) def init(self): try: if self.debug: self.gpsLog.log('gps init') self.actionGPStoggle.setChecked(False) # qgis self.prj = QgsProject().instance() self.canvas = self.iface.mapCanvas() # settings if "GPS" in self.gtomain.settings: # compatible self.settings = self.gtomain.settings["GPS"] else: self.settings = self.gtomain.settings # timer self.timer_intervall = self.settings.get("gps_timer_intervall", 5000) # gps self.port = self.settings.get("gps_port", None) if self.port is None: self.setPort(self.helper.getGlobalSetting('GpsPort')) self.pdop = self.settings.get("gps_pdop", 0) self.actionGPSlog.setChecked(self.settings.get("gps_log", False)) watchdog_interval = self.settings.get("gps_watchdog_interval", 3000) self.watchdog.setInterval(watchdog_interval) # streaming self.pointLayer = self.settings.get("gps_point_layer", None) try: if self.pointLayer is not None: self.pointLayer = self.prj.mapLayersByName( self.pointLayer)[0] geoType = self.pointLayer.geometryType() if geoType != QgsWkbTypes.GeometryType.PointGeometry: self.pointLayer = None except Exception as e: self.pointLayer = None self.info.err(e) self.gps_debug = self.settings.get("gps_debug", False) self.gps_stream_mode = self.settings.get("gps_stream_mode", 0) self.gps_streaming_distance = self.settings.get( "gps_streaming_distance", 1) # map self.center = self.settings.get("gps_center", True) self.actionGPScenter.setChecked(self.center) self.scale = self.settings.get("gps_scale", 0) # transformation self.prj_crs = self.prj.crs() self.wgs_crs = self.settings.get("gps_wgs_crs", 'EPSG:4326') self.init_transformation(self.wgs_crs) except Exception as e: self.info.err(e) def activateCenter(self): self.center = self.actionGPScenter.isChecked() def activate(self): try: self.deactivate() if self.actionGPStoggle.isChecked(): if self.port is None: self.info.msg("Kein GPS Port gesetzt!") return self.actionGPSport.setEnabled(False) if self.actionGPSlog.isChecked(): self.gpsLog.log('gps activate') self.gpsDetector = QgsGpsDetector(self.port) self.gpsDetector.detected[QgsGpsConnection].connect( self.connection_succeed) # self.gpsDetector.detected[QgsNmeaConnection].connect(self.connection_succeed) self.gpsDetector.detectionFailed.connect( self.connection_failed) self.gpsDetector.advance() self.init_marker() except Exception as e: self.info.err(e) def setPort(self, port): try: self.port = port self.actionGPStoggle.setToolTip('GPS on/off (Port:{0})'.format( self.port)) except Exception as e: self.info.err(e) def enableGPSfunctions(self, enabled): try: if self.iface.mainWindow() is None: return # dummy except: # prevent: ERROR: <class 'RuntimeError'> gto_gps.py | line: 240 | ('wrapped C/C++ object of type QgisInterface has been deleted',) # because QGIS is already closing return try: if self.iface.activeLayer() is not None: geoType = self.iface.activeLayer().geometryType() if geoType == QgsWkbTypes.GeometryType.PointGeometry: self.actionGPSaddPoint.setEnabled(enabled) else: self.actionGPSaddPoint.setEnabled(False) self.actionGPSclick.setEnabled(enabled) self.actionGPSstreaming.setEnabled(enabled) self.actionGPSport.setEnabled(not enabled) except Exception as e: self.info.err(e) def connection_succeed(self, connection): try: self.gps_active = True self.gpsCon = connection self.gpsCon.stateChanged.connect(self.status_changed) self.watchdog.start() except Exception as e: self.info.err(e) def connection_failed(self): if not self.gps_active: self.actionGPStoggle.setChecked(False) self.info.msg("GPS konnte nicht initialisiert werden!") self.info.log('GPS connection failed') self.enableGPSfunctions(False) def deactivate(self): try: if self.iface.mainWindow() is None: return # dummy except: # prevent: ERROR: <class 'RuntimeError'> gto_gps.py | line: 240 | ('wrapped C/C++ object of type QgisInterface has been deleted',) # because QGIS is already closing return try: if self.debug: self.info.log('gps deactivate') self.watchdog.stop() self.debugXoffset = 0 self.debugYoffset = 0 self.prevTime = None self.actionGPSstreaming.setChecked(False) self.enableGPSfunctions(False) self.prevPointXY = None if self.gpsCon is not None: if self.actionGPSlog.isChecked(): self.gpsLog.log('gps deactivate') self.gpsCon.close() if self.canvas is not None: self.canvas.scene().removeItem(self.marker) self.gps_active = False except Exception as e: self.info.err(e) def init_marker(self): try: if self.actionGPSlog.isChecked(): self.info.log('gps init_marker') self.marker = QgsVertexMarker(self.canvas) self.marker.setColor(QColor(255, 0, 0)) # (R,G,B) self.marker.setIconSize(10) self.circle = QgsVertexMarker.ICON_CIRCLE self.marker.setIconType(self.circle) # ICON_BOX # ICON_CIRCLE # ICON_CROSS # ICON_DOUBLE_TRIANGLE # ICON_NONE # ICON_X self.marker.setPenWidth(3) except Exception as e: self.info.err(e) def init_transformation(self, wgs_crs): try: self.src_crs = QgsCoordinateReferenceSystem(wgs_crs) self.transformation = QgsCoordinateTransform( self.src_crs, self.prj_crs, self.prj) except Exception as e: self.info.err(e) def status_changed(self, gpsInfo): try: if self.gpsCon.status() != 3: return # 3=data received self.watchdog.stop() self.watchdog.start() if gpsInfo.longitude == 0: return valid = False self.dic_gpsinfo = { "direction": gpsInfo.direction, "elevation": gpsInfo.elevation, "fixMode": gpsInfo.fixMode, "fixType": gpsInfo.fixType, "hacc": gpsInfo.hacc, "satInfoComplete": gpsInfo.satInfoComplete, "speed": gpsInfo.speed, "utcDateTime": gpsInfo.utcDateTime, "vacc": gpsInfo.vacc, "status": gpsInfo.status, "hdop": gpsInfo.hdop, "vdop": gpsInfo.vdop, "pdop": gpsInfo.pdop, "latitude": gpsInfo.latitude, "longitude": gpsInfo.longitude, "satellitesInView": gpsInfo.satellitesInView, "satellitesUsed": gpsInfo.satellitesUsed, "quality": gpsInfo.quality } if self.actionGPSlog.isChecked(): self.gpsLog.log('direction:', gpsInfo.direction) self.gpsLog.log('elevation:', gpsInfo.elevation) self.gpsLog.log('fixMode:', gpsInfo.fixMode) self.gpsLog.log('fixType:', gpsInfo.fixType) self.gpsLog.log('hacc:', gpsInfo.hacc) self.gpsLog.log('satInfoComplete:', gpsInfo.satInfoComplete) self.gpsLog.log('speed:', gpsInfo.speed) self.gpsLog.log('utcDateTime:', gpsInfo.utcDateTime.toString()) self.gpsLog.log('vacc:', gpsInfo.vacc) self.gpsLog.log('status:', gpsInfo.status) self.gpsLog.log('hdop:', gpsInfo.hdop) self.gpsLog.log('vdop:', gpsInfo.vdop) self.gpsLog.log('pdop:', gpsInfo.pdop) self.gpsLog.log('latitude:', gpsInfo.latitude) self.gpsLog.log('longitude:', gpsInfo.longitude) self.gpsLog.log('satellitesInView:', len(gpsInfo.satellitesInView)) self.gpsLog.log('satellitesUsed:', gpsInfo.satellitesUsed) self.gpsLog.log('quality:', gpsInfo.quality) self.gpsLog.log("---------------------") if gpsInfo.pdop >= self.pdop: # gps ok valid = True self.enableGPSfunctions(True) self.marker.setColor(QColor(0, 200, 0)) else: self.enableGPSfunctions(False) self.marker.setColor(QColor(255, 0, 0)) wgs84_pointXY = QgsPointXY(gpsInfo.longitude, gpsInfo.latitude) wgs84_point = QgsPoint(wgs84_pointXY) wgs84_point.transform(self.transformation) if self.gps_debug: self.debugXoffset = self.debugXoffset + random.randint( 0, int(self.gps_streaming_distance)) self.debugYoffset = self.debugYoffset + random.randint( 0, int(self.gps_streaming_distance)) x = wgs84_point.x() + self.debugXoffset y = wgs84_point.y() + self.debugYoffset else: x = wgs84_point.x() y = wgs84_point.y() if self.actionGPSlog.isChecked(): self.gpsLog.log("x:", x) self.gpsLog.log("y:", y) self.gpsLog.log("--------------------") mapPointXY = QgsPointXY(x, y) self.lastGpsInfo = gtoGPSinfo(gpsInfo, mapPointXY, valid) # map if self.center and valid: self.canvas.setCenter(mapPointXY) if self.scale > 0: self.canvas.zoomScale(self.scale) self.marker.setCenter(mapPointXY) self.marker.show() # streaming gpsDateTime = None diff = 0 if self.pointLayer is not None: self.actionGPSaddPoint.setEnabled(valid) if self.actionGPSstreaming.isChecked( ) and valid and not self.actionGPSaddVertexTool.isChecked(): if self.prevTime is None: self.prevTime = gpsInfo.utcDateTime.currentDateTime() else: gpsDateTime = gpsInfo.utcDateTime.currentDateTime() diff = self.prevTime.msecsTo(gpsDateTime) if diff < self.timer_intervall: return if self.prevPointXY is None: self.prevPointXY = mapPointXY self.prevTime = gpsDateTime if self.pointLayer is not None: self.addPoint() else: if self.gps_stream_mode == 1: self.gps_click() elif self.gps_stream_mode == 2: self.gps_click() self.addVertex(mapPointXY) else: self.addVertex(mapPointXY) else: qgsDistance = QgsDistanceArea() distance = qgsDistance.measureLine( [self.prevPointXY, mapPointXY]) if distance > self.gps_streaming_distance and diff > self.timer_intervall: self.prevTime = gpsDateTime self.prevPointXY = mapPointXY if self.pointLayer is not None: self.addPoint() else: if self.gps_stream_mode == 1: self.gps_click() elif self.gps_stream_mode == 2: self.gps_click() self.addVertex(mapPointXY) else: self.addVertex(mapPointXY) except Exception as e: self.info.err(e) def gps_click(self): from pynput.mouse import Button, Controller try: if self.gps_active: if self.debug: self.gpsLog.log('gps_click') actionAddFeature = self.iface.mainWindow().findChild( QAction, 'mActionAddFeature') gtoGpsInfo = self.lastGpsInfo if gtoGpsInfo.isValid and actionAddFeature.isChecked(): self.mouse = Controller() mapX = gtoGpsInfo.mapPointXY.x() mapY = gtoGpsInfo.mapPointXY.y() pointXY = self.canvas.getCoordinateTransform().transform( mapX, mapY) # map coords to device coords x = pointXY.x() y = pointXY.y() p = self.canvas.mapToGlobal(QPoint( x, y)) # device coords to screen coords x = p.x() y = p.y() prevX, prevY = self.mouse.position self.mouse.position = (x, y) if self.debug: self.gpsLog.log('addPoint', x, "/", y) self.mouse.click(Button.left, 1) self.mouse.position = (prevX, prevY) except Exception as e: self.info.err(e) def layer_changed(self): try: self.actionGPSstreaming.setChecked(False) if self.gps_active: geoType = self.iface.activeLayer().geometryType() if geoType == QgsWkbTypes.GeometryType.PointGeometry or self.pointLayer is not None: self.actionGPSaddPoint.setEnabled(True) else: self.actionGPSaddPoint.setEnabled(False) except Exception as e: self.info.err(e) def streaming(self): try: self.actionGPSsave.setEnabled(False) self.actionGPSaddVertexTool.setChecked(False) self.activateVertexTool() if self.pointLayer is not None: return if self.actionGPSstreaming.isChecked(): if self.streamLayer is not None: self.actionGPSstreaming.setChecked(False) res = self.saveGeometry() if res == QMessageBox.Cancel: return self.actionGPSstreaming.setChecked(True) geoType = self.iface.activeLayer().geometryType() if geoType == QgsWkbTypes.GeometryType.PolygonGeometry or geoType == QgsWkbTypes.GeometryType.LineGeometry: self.streamLayer = self.iface.activeLayer() self.actionGPSaddVertexTool.setEnabled(True) self.rb.reset(geoType) else: self.actionGPSstreaming.setChecked(False) self.actionGPSaddVertexTool.setEnabled(False) self.info.msg( "Aktiver Layer muss vom Typ Polgone oder Line sein!") else: self.actionGPSaddVertexTool.setEnabled(False) if self.streamLayer is not None: geoType = self.streamLayer.geometryType() tools = self.settings.get('gps_afterstream_tools', []) if geoType == QgsWkbTypes.GeometryType.PolygonGeometry: if self.rb.numberOfVertices() > 2: self.actionGPSsave.setEnabled(True) self.gtomain.runcmd(tools) if geoType == QgsWkbTypes.GeometryType.LineGeometry: if self.rb.numberOfVertices() > 1: self.actionGPSsave.setEnabled(True) self.gtomain.runcmd(tools) except Exception as e: self.info.err(e) def addPoint(self): try: if self.gps_active: if self.actionGPSlog.isChecked(): self.gpsLog.log('addPoint') gtoGpsInfo = self.lastGpsInfo if gtoGpsInfo.isValid: if self.pointLayer is not None: layer = self.pointLayer else: layer = self.iface.activeLayer() geoType = layer.geometryType() if geoType != QgsWkbTypes.GeometryType.PointGeometry: self.info.msg("Kein Punktlayer ausgewählt!") return # create feature feat = QgsVectorLayerUtils.createFeature(layer) tr = QgsCoordinateTransform(self.prj_crs, layer.crs(), self.prj) tr_point = tr.transform(gtoGpsInfo.mapPointXY) geo = QgsGeometry.fromPointXY(tr_point) feat.setGeometry(geo) # set attributes gps_addpoint_attributes = self.settings.get( "gps_addpoint_attributes", {}) for k, v in gps_addpoint_attributes.items(): feat[k] = layer.fields().field(k).convertCompatible( self.dic_gpsinfo[v]) # add to layer if self.pointLayer is not None: # add to provider (res, outFeats) = layer.dataProvider().addFeatures([feat]) layer.select(outFeats[0].id()) else: if not layer.isEditable(): layer.startEditing() layer.beginEditCommand('Add stream geometry') layer.addFeatures([feat]) layer.endEditCommand() self.helper.refreshLayer(layer) except Exception as e: self.info.err(e) def saveGeometry(self, force=False): try: if self.streamLayer is not None: if not force: res = self.info.gtoQuestion( "GPS Stream-Geometry in Layer \n{0}\nspeichern?". format(self.streamLayer.name()), title='GPS Streaming', btns=QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel, parent=self.iface.mainWindow()) if res == QMessageBox.Cancel: return res if res == QMessageBox.No: self.actionGPSsave.setEnabled(False) self.streamLayer = None self.rb.reset() return # create feature feat = QgsVectorLayerUtils.createFeature(self.streamLayer) geo = self.rb.asGeometry() feat.setGeometry(geo) # add to layer if not self.streamLayer.isEditable(): self.streamLayer.startEditing() self.streamLayer.beginEditCommand('Add stream geometry') self.streamLayer.addFeatures([feat]) self.streamLayer.endEditCommand() # add to provider # (res, outFeats) = self.streamLayer.dataProvider().addFeatures([feat]) # self.streamLayer.select(outFeats[0].id()) # reset streaming self.actionGPSsave.setEnabled(False) self.streamLayer = None self.rb.reset() except Exception as e: self.streamLayer.destroyEditCommand() self.info.err(e) def addVertex(self, point): try: self.rb.addPoint(point) except Exception as e: self.info.err(e) def activateVertexTool(self): try: if self.actionGPSaddVertexTool.isChecked(): if self.actionGPSlog.isChecked(): self.gpsLog.log('activated VertexTool: stream paused') self.LastMapTool = self.canvas.mapTool() self.canvas.setMapTool(self.streamTool) else: if self.actionGPSlog.isChecked(): self.gpsLog.log('deactivated VertexTool: stream resumed') self.canvas.setMapTool(self.LastMapTool) except Exception as e: self.info.err(e) def tool_isactive(self, active): try: pass except Exception as e: self.info.err(e)
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 self.rubber_band.size( ) == 0 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.', Qgis.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.', Qgis.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.', Qgis.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.', Qgis.Warning, 5) # TODO: softcode return # There's a rubber band: create new pipe if pipe_band_geom is not None: #XPSS ADDED - transform rubber band CRS canvas_crs = self.canvas().mapSettings().destinationCrs() #pipes_vlay = Parameters().pipes_vlay() #print(pipes_vlay) qepanet_crs = self.params.pipes_vlay.sourceCrs() crs_transform = QgsCoordinateTransform(canvas_crs, qepanet_crs, QgsProject.instance()) pipe_band_geom.transform(crs_transform) # Finalize line rubberband_pts = pipe_band_geom.asPolyline()[:-1] if len(rubberband_pts) == 0: self.iface.mapCanvas().refresh() return rubberband_pts = self.remove_duplicated_point(rubberband_pts) if len(rubberband_pts) < 2: self.rubber_band.reset() 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()) length_units = 'm' #TODO soft code diameter = float(self.data_dock.cbo_pipe_dia.\ currentText()) diameter_units = self.data_dock.cbo_pipe_dia_units.\ currentText() #loss = float(self.data_dock.txt_pipe_loss.text()) #status = self.data_dock.cbo_pipe_status.currentText() material = self.data_dock.cbo_pipe_mtl.currentText() roughness = float(self.data_dock.txt_roughness.text()) #pipe_desc = self.data_dock.txt_pipe_desc.text() #pipe_tag = self.data_dock.cbo_pipe_tag.currentText() num_edu = 1 zone_id = 0 velocity = 0 velocity_units = 'm/s' frictionloss = 0 frictionloss_units = 'm' pipe_ft = LinkHandler.create_new_pipe( self.params, pipe_eid, length_units, diameter, diameter_units, 0, roughness, " ", material, rubberband_pts[junct_nrs[np]:junct_nrs[np + 1] + 1], True, " ", " ", num_edu, zone_id, velocity, velocity_units, frictionloss, frictionloss_units) 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() zone_end = 0 pressure = 0 pressure_units = self.data_dock.cbo_rpt_units_pressure.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.', Qgis.Warning, 5) # TODO: softcode deltaz = float(0) #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, 0, deltaz, None, 0, " ", " ", zone_end, pressure, pressure_units) (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.', Qgis.Warning, 5) # TODO: softcode deltaz = float(0) # 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, 0, deltaz, None, 0, " ", " ", zone_end, pressure, pressure_units) # 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.fromPointXY(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.fromPointXY(new_end_junction)) < self.params.tolerance: LinkHandler.split_pipe(self.params, pipe_ft, new_end_junction) self.iface.mapCanvas().refresh() # 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(list(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: QgsSnappingConfig.Vertex, self.params.reservoirs_vlay: QgsSnappingConfig.Vertex, self.params.tanks_vlay: QgsSnappingConfig.Vertex, self.params.pipes_vlay: QgsSnappingConfig.VertexAndSegment } self.snapper = NetworkUtils.set_up_snapper(layers, self.iface.mapCanvas(), self.params.snap_tolerance) self.snapper.toggleEnabled() # Needed by Observable def update(self, observable): self.update_snapper()
class ConnecMapTool(ParentMapTool): """ Button 20. User select connections from layer 'connec' Execute SQL function: 'gw_fct_connect_to_network' """ def __init__(self, iface, settings, action, index_action): """ Class constructor """ # Call ParentMapTool constructor super(ConnecMapTool, self).__init__(iface, settings, action, index_action) self.dragging = False # Vertex marker self.vertexMarker = QgsVertexMarker(self.canvas) self.vertexMarker.setColor(QColor(255, 25, 25)) self.vertexMarker.setIconSize(11) self.vertexMarker.setIconType(QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X self.vertexMarker.setPenWidth(5) # Rubber band self.rubberBand = QgsRubberBand(self.canvas, True) mFillColor = QColor(100, 0, 0) self.rubberBand.setColor(mFillColor) self.rubberBand.setWidth(3) mBorderColor = QColor(254, 58, 29) self.rubberBand.setBorderColor(mBorderColor) # Select rectangle self.selectRect = QRect() def reset(self): """ Clear selected features """ layer = self.layer_connec if layer is not None: layer.removeSelection() # Graphic elements self.rubberBand.reset() """ QgsMapTools inherited event functions """ def canvasMoveEvent(self, event): """ With left click the digitizing is finished """ if event.buttons() == Qt.LeftButton: if not self.dragging: self.dragging = True self.selectRect.setTopLeft(event.pos()) self.selectRect.setBottomRight(event.pos()) self.set_rubber_band() else: # Hide highlight self.vertexMarker.hide() # Get the click x = event.pos().x() y = event.pos().y() eventPoint = QPoint(x, y) # Snapping (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint) # @UnusedVariable # That's the snapped point if result <> []: # Check Arc or Node for snapPoint in result: if snapPoint.layer == self.layer_connec: # Get the point point = QgsPoint(result[0].snappedVertex) # Add marker self.vertexMarker.setCenter(point) self.vertexMarker.show() break def canvasPressEvent(self, event): self.selectRect.setRect(0, 0, 0, 0) self.rubberBand.reset() def canvasReleaseEvent(self, event): """ With left click the digitizing is finished """ if event.button() == Qt.LeftButton: # Get the click x = event.pos().x() y = event.pos().y() eventPoint = QPoint(x, y) # Node layer layer = self.layer_connec # Not dragging, just simple selection if not self.dragging: # Snap to node (retval, result) = self.snapper.snapToBackgroundLayers(eventPoint) # @UnusedVariable # That's the snapped point if result <> [] and (result[0].layer.name() == self.layer_connec.name()): point = QgsPoint(result[0].snappedVertex) # @UnusedVariable layer.removeSelection() layer.select([result[0].snappedAtGeometry]) # Create link self.link_connec() # Hide highlight self.vertexMarker.hide() else: # Set valid values for rectangle's width and height if self.selectRect.width() == 1: self.selectRect.setLeft(self.selectRect.left() + 1) if self.selectRect.height() == 1: self.selectRect.setBottom(self.selectRect.bottom() + 1) self.set_rubber_band() selectGeom = self.rubberBand.asGeometry() # @UnusedVariable self.select_multiple_features(self.selectRectMapCoord) self.dragging = False # Create link self.link_connec() elif event.button() == Qt.RightButton: # Create link self.link_connec() def activate(self): # Check button self.action().setChecked(True) # Rubber band self.rubberBand.reset() # Store user snapping configuration self.snapperManager.storeSnappingOptions() # Clear snapping self.snapperManager.clearSnapping() # Set snapping to arc and node self.snapperManager.snapToConnec() # Change cursor self.canvas.setCursor(self.cursor) # Show help message when action is activated if self.show_help: message = ( "Right click to use current selection, select connec points by clicking or dragging (selection box)" ) self.controller.show_info(message, context_name="ui_message") # Control current layer (due to QGIS bug in snapping system) try: if self.canvas.currentLayer().type() == QgsMapLayer.VectorLayer: self.canvas.setCurrentLayer(self.layer_connec) except: self.canvas.setCurrentLayer(self.layer_connec) def deactivate(self): # Check button self.action().setChecked(False) # Rubber band self.rubberBand.reset() # Restore previous snapping self.snapperManager.recoverSnappingOptions() # Recover cursor self.canvas.setCursor(self.stdCursor) def link_connec(self): """ Link selected connec to the pipe """ # Get selected features (from layer 'connec') aux = "{" layer = self.layer_connec if layer.selectedFeatureCount() == 0: message = "You have to select at least one feature!" self.controller.show_warning(message, context_name="ui_message") return features = layer.selectedFeatures() for feature in features: connec_id = feature.attribute("connec_id") aux += str(connec_id) + ", " connec_array = aux[:-2] + "}" # Execute function function_name = "gw_fct_connect_to_network" sql = "SELECT " + self.schema_name + "." + function_name + "('" + connec_array + "');" self.controller.execute_sql(sql) # Refresh map canvas self.rubberBand.reset() self.iface.mapCanvas().refresh() def set_rubber_band(self): # Coordinates transform transform = self.canvas.getCoordinateTransform() # Coordinates ll = transform.toMapCoordinates(self.selectRect.left(), self.selectRect.bottom()) lr = transform.toMapCoordinates(self.selectRect.right(), self.selectRect.bottom()) ul = transform.toMapCoordinates(self.selectRect.left(), self.selectRect.top()) ur = transform.toMapCoordinates(self.selectRect.right(), self.selectRect.top()) # Rubber band self.rubberBand.reset() self.rubberBand.addPoint(ll, False) self.rubberBand.addPoint(lr, False) self.rubberBand.addPoint(ur, False) self.rubberBand.addPoint(ul, False) self.rubberBand.addPoint(ll, True) self.selectRectMapCoord = QgsRectangle(ll, ur) def select_multiple_features(self, selectGeometry): # Default choice behaviour = QgsVectorLayer.SetSelection # Modifiers modifiers = QApplication.keyboardModifiers() if modifiers == Qt.ControlModifier: behaviour = QgsVectorLayer.AddToSelection elif modifiers == Qt.ShiftModifier: behaviour = QgsVectorLayer.RemoveFromSelection if self.layer_connec is None: return # Change cursor QApplication.setOverrideCursor(Qt.WaitCursor) # Selection self.layer_connec.selectByRect(selectGeometry, behaviour) # Old cursor QApplication.restoreOverrideCursor()