Example #1
0
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
Example #3
0
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()
Example #5
0
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()
Example #7
0
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 )
Example #8
0
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
Example #11
0
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
Example #13
0
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()
Example #14
0
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
Example #15
0
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
Example #16
0
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)
Example #17
0
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
Example #19
0
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
Example #21
0
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
Example #22
0
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()
Example #24
0
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()
Example #26
0
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()
Example #27
0
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)
Example #32
0
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 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)
Example #34
0
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()
Example #35
0
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()
Example #36
0
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()
Example #37
0
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)
Example #39
0
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)
Example #40
0
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)  
Example #41
0
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
Example #42
0
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)
Example #43
0
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
Example #45
0
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)
Example #46
0
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()
Example #47
0
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()