Example #1
0
    def _draw_rubberband(self, extent, colour, width=2):
        """
        Draw a rubber band on the canvas.

        .. versionadded: 2.2.0

        :param extent: Extent that the rubber band should be drawn for.
        :type extent: QgsRectangle

        :param colour: Colour for the rubber band.
        :type colour: QColor

        :param width: The width for the rubber band pen stroke.
        :type width: int

        :returns: Rubber band that should be set to the extent.
        :rtype: QgsRubberBand
        """
        rubberband = QgsRubberBand(
            self.iface.mapCanvas(), geometryType=QGis.Line)
        rubberband.setColor(colour)
        rubberband.setWidth(width)
        update_display_flag = False
        point = QgsPoint(extent.xMinimum(), extent.yMinimum())
        rubberband.addPoint(point, update_display_flag)
        point = QgsPoint(extent.xMaximum(), extent.yMinimum())
        rubberband.addPoint(point, update_display_flag)
        point = QgsPoint(extent.xMaximum(), extent.yMaximum())
        rubberband.addPoint(point, update_display_flag)
        point = QgsPoint(extent.xMinimum(), extent.yMaximum())
        rubberband.addPoint(point, update_display_flag)
        point = QgsPoint(extent.xMinimum(), extent.yMinimum())
        update_display_flag = True
        rubberband.addPoint(point, update_display_flag)
        return rubberband
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 GetPointMapTool(QgsMapToolEmitPoint):

    coordCaptured = ""

    def __init__(self, canvas, iface, dockwidget, currentMapTool):
        self.canvas = canvas
        self.iface = iface
        self.currentMapTool = currentMapTool
        self.dockwidget = dockwidget
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.rubberBand = QgsRubberBand(self.canvas, QGis.Point)
        self.rubberBand.setColor(QColor(255,5,5))
        self.rubberBand.setWidth(1)
        self.reset()

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBand.reset(QGis.Polygon)

    def canvasPressEvent(self, e):
        self.point = self.toMapCoordinates(e.pos())
        self.isEmittingPoint = True
        self.showPoint(self.point)

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False
        self.coordCaptured = self.pointdef()
        if self.coordCaptured is not None:
            print "Point:", self.coordCaptured
            self.coordCaptured = str(self.coordCaptured).strip("(")
            self.coordCaptured = str(self.coordCaptured).strip(")")
            self.dockwidget.munLineEdit.setText(self.coordCaptured)


        self.iface.mapCanvas().setMapTool(self.currentMapTool)

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return

        self.endPoint = self.toMapCoordinates(e.pos())
       # self.showRect(self.startPoint, self.endPoint)

    def showPoint(self, point):
        self.rubberBand.reset(QGis.Polygon)


        point1 = QgsPoint(point.x(), point.y())


        self.rubberBand.addPoint(point1, False)

        self.rubberBand.show()

    def pointdef(self):

        return QgsPoint(self.point)
Example #4
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 #5
0
    def drawManyPaths(self, rows, columns, con, args, geomType, canvasItemList, mapCanvas):
        '''
            draws multi line string on the mapCanvas.
        '''
        resultPathsRubberBands = canvasItemList['paths']
        rubberBand = None
        cur_path_id = None
        for row in rows:
            cur2 = con.cursor()
            result_path_id = str(row[columns[0]])
            args['result_node_id'] = sql.Literal(row[columns[1]])
            args['result_edge_id'] = sql.Literal(row[columns[2]])

            if result_path_id != cur_path_id:
                cur_path_id = result_path_id
                if rubberBand:
                    resultPathsRubberBands.append(rubberBand)
                    rubberBand = None

                rubberBand = QgsRubberBand(mapCanvas, Utils.getRubberBandType(False))
                rubberBand.setColor(QColor(255, 0, 0, 128))
                rubberBand.setWidth(4)

            if row[columns[2]] != -1:
                query2 = sql.SQL("""
                    SELECT ST_AsText({transform_s}{geometry}{transform_e})
                    FROM {edge_schema}.{edge_table}
                    WHERE {source} = {result_node_id} AND {id} = {result_edge_id}

                    UNION

                    SELECT ST_AsText({transform_s}ST_Reverse({geometry}){transform_e})
                    FROM {edge_schema}.{edge_table}
                    WHERE {target} = {result_node_id} AND {id} = {result_edge_id}
                    """).format(**args).as_string(con)

                cur2.execute(query2)
                row2 = cur2.fetchone()

                geom = QgsGeometry().fromWkt(str(row2[0]))
                if geom.wkbType() == QgsWkbTypes.MultiLineString:
                    for line in geom.asMultiPolyline():
                        for pt in line:
                            rubberBand.addPoint(pt)
                elif geom.wkbType() == QgsWkbTypes.LineString:
                    for pt in geom.asPolyline():
                        rubberBand.addPoint(pt)

        if rubberBand:
            resultPathsRubberBands.append(rubberBand)
            rubberBand = None
Example #6
0
class DrawPolygon(QgsMapTool):
    '''Outil de sélection par polygone, tiré de selectPlusFr'''

    selectionDone = pyqtSignal()
    move = pyqtSignal()

    def __init__(self, iface, couleur):
        canvas = iface.mapCanvas()
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.iface = iface
        self.status = 0
        self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)
        self.rb.setColor(couleur)
        return None

    def keyPressEvent(self, e):
        if e.matches(QKeySequence.Undo):
            if self.rb.numberOfVertices() > 1:
                self.rb.removeLastPoint()

    def canvasPressEvent(self, e):
        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()
            else:
                self.reset()
        return None

    def canvasMoveEvent(self, e):
        if self.rb.numberOfVertices() > 0 and self.status == 1:
            self.rb.removeLastPoint(0)
            self.rb.addPoint(self.toMapCoordinates(e.pos()))
        self.move.emit()
        return None

    def reset(self):
        self.status = 0
        self.rb.reset(True)

    def deactivate(self):
        self.rb.reset(True)
        QgsMapTool.deactivate(self)
Example #7
0
class RubberBandResultRenderer():

    def __init__(self, iface, color = QColor('magenta'), size = 12):
        self.iface = iface
        self.rb = QgsRubberBand(self.iface.mapCanvas(), QGis.Point)
        self.rb.setColor(color)
        self.rb.setIconSize(size)

        self.srs_wgs84 = QgsCoordinateReferenceSystem(4326)
        self.transformation = QgsCoordinateTransform(self.srs_wgs84, self.srs_wgs84)

    def show_point(self, point, center=False):
        #check srs
        if self.need_transform():
            point = self.transform_point(point)

        self.rb.addPoint(point)
        if center:
            self.center_to_point(point)

    def clear(self):
        self.rb.reset(QGis.Point)

    def need_transform(self):
        return self.iface.mapCanvas().mapRenderer().destinationCrs().postgisSrid() != 4326

    def transform_point(self, point):
        dest_srs_id = self.iface.mapCanvas().mapRenderer().destinationCrs().srsid()
        self.transformation.setDestCRSID(dest_srs_id)
        try:
            return self.transformation.transform(point)
        except:
            print 'Error on transform!'  # DEBUG! need message???
            return

    def center_to_point(self, point):
        canvas = self.iface.mapCanvas()
        new_extent = QgsRectangle(canvas.extent())
        new_extent.scale(1, point)
        canvas.setExtent(new_extent)
        canvas.refresh()
class PlaceMarkerMapTool(QgsMapToolEmitPoint):
    '''
    classdocs
    '''

    def __init__(self, canvas):
        '''
        Constructor
        '''
        self.canvas = canvas
        super(PlaceMarkerMapTool, self).__init__(self.canvas)
        self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon)
        self.rubberBand.setColor(Qt.red)
        self.rubberBand.setWidth(1)
        self.reset()

    def reset(self):
        self.rubberBand.reset(QGis.Polygon)

    def canvasReleaseEvent(self, e):
        p1 = self.canvas.getCoordinateTransform().toMapCoordinates(e.x() - 2, e.y() - 2)
        p2 = self.canvas.getCoordinateTransform().toMapCoordinates(e.x() + 2, e.y() - 2)
        p3 = self.canvas.getCoordinateTransform().toMapCoordinates(e.x() + 2, e.y() + 2)
        p4 = self.canvas.getCoordinateTransform().toMapCoordinates(e.x() - 2, e.y() + 2)
        self.reset()

        self.rubberBand.addPoint(p1, False)
        self.rubberBand.addPoint(p2, False)
        self.rubberBand.addPoint(p3, False)
        self.rubberBand.addPoint(p4, True)
        self.rubberBand.show()

    def deactivate(self):
        self.reset()
        super(PlaceMarkerMapTool, self).deactivate()
class 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 #10
0
class DrawPoint(QgsMapTool):
    selectionDone = pyqtSignal()

    def __init__(self, iface, couleur):
        canvas = iface.mapCanvas()
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.iface = iface
        self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry)
        self.rb.setColor(couleur)
        self.rb.setWidth(3)

    def canvasReleaseEvent(self, e):
        if e.button() == Qt.LeftButton:
            self.rb.addPoint(self.toMapCoordinates(e.pos()))
            self.selectionDone.emit()

    def reset(self):
        self.rb.reset(QgsWkbTypes.PointGeometry)

    def deactivate(self):
        self.rb.reset(QgsWkbTypes.PointGeometry)
        QgsMapTool.deactivate(self)
Example #11
0
class SelectPoint(QgsMapTool):
    select = pyqtSignal()
    selectionDone = pyqtSignal()

    def __init__(self, iface, couleur):
        canvas = iface.mapCanvas()
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.iface = iface
        self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)
        self.rb.setColor(couleur)
        self.rbSelect = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)
        return None

    def canvasReleaseEvent(self, e):
        if e.button() == Qt.LeftButton:
            self.rbSelect.reset(QgsWkbTypes.PolygonGeometry)
            cp = self.toMapCoordinates(
                QPoint(e.pos().x() - 5, e.pos().y() - 5))
            self.rbSelect.addPoint(cp)
            cp = self.toMapCoordinates(
                QPoint(e.pos().x() + 5, e.pos().y() - 5))
            self.rbSelect.addPoint(cp)
            cp = self.toMapCoordinates(
                QPoint(e.pos().x() + 5, e.pos().y() + 5))
            self.rbSelect.addPoint(cp)
            cp = self.toMapCoordinates(
                QPoint(e.pos().x() - 5, e.pos().y() + 5))
            self.rbSelect.addPoint(cp)
            self.select.emit()
        else:
            self.selectionDone.emit()
        return None

    def reset(self):
        self.rb.reset(QgsWkbTypes.PolygonGeometry)
        self.rbSelect.reset(QgsWkbTypes.PolygonGeometry)

    def deactivate(self):
        self.rb.reset(QgsWkbTypes.PolygonGeometry)
        self.rbSelect.reset(QgsWkbTypes.PolygonGeometry)
        QgsMapTool.deactivate(self)
Example #12
0
class RectangleMapTool(QgsMapTool):
    def __init__(self, canvas, callback):
        self.canvas = canvas
        QgsMapTool.__init__(self, self.canvas)
        self.callback = callback
        self.rubberBand = QgsRubberBand(self.canvas, True)
        self.rubberBand.setColor(QColor(227, 26, 28, 255))
        self.rubberBand.setWidth(5)
        self.rubberBand.setLineStyle(Qt.PenStyle(Qt.DashLine))
        self.reset()

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBand.reset(True)

    def canvasPressEvent(self, e):
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True
        self.showRect(self.startPoint, self.endPoint)

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False
        r = self.rectangle()
        if r is not None:
            # print "Rectangle:", r.xMinimum(), r.yMinimum(), r.xMaximum(), r.yMaximum()
            self.rubberBand.hide()
            self.callback(r)
            # self.deactivate()
        return None

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return
        self.endPoint = self.toMapCoordinates(e.pos())
        self.showRect(self.startPoint, self.endPoint)

    def showRect(self, startPoint, endPoint):
        self.rubberBand.reset(True)
        if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
            return

        point1 = QgsPoint(startPoint.x(), startPoint.y())
        point2 = QgsPoint(startPoint.x(), endPoint.y())
        point3 = QgsPoint(endPoint.x(), endPoint.y())
        point4 = QgsPoint(endPoint.x(), startPoint.y())

        self.rubberBand.addPoint(point1, False)
        self.rubberBand.addPoint(point2, False)
        self.rubberBand.addPoint(point3, False)
        self.rubberBand.addPoint(point4, False)
        self.rubberBand.addPoint(point1, True)  # true to update canvas
        self.rubberBand.show()

    def rectangle(self):
        if self.startPoint is None or self.endPoint is None:
            return None
        elif self.startPoint.x() == self.endPoint.x() or self.startPoint.y() == self.endPoint.y():
            return None
        return QgsRectangle(self.startPoint, self.endPoint)

    def deactivate(self):
        super(RectangleMapTool, self).deactivate()
        self.emit(QtCore.SIGNAL("deactivated()"))
Example #13
0
    def drawCostPaths(self, rows, con, args, geomType, canvasItemList, mapCanvas):
        resultPathsRubberBands = canvasItemList['paths']
        rubberBand = None
        cur_path_id = -1
        for row in rows:
            cur2 = con.cursor()
            args['result_path_id'] = row[0]
            args['result_source_id'] = sql.Literal(row[1])
            args['result_target_id'] = sql.Literal(row[2])
            args['result_cost'] = row[3]
            if args['result_path_id'] != cur_path_id:
                cur_path_id = args['result_path_id']
                if rubberBand:
                    resultPathsRubberBands.append(rubberBand)
                    rubberBand = None

                rubberBand = QgsRubberBand(mapCanvas, Utils.getRubberBandType(False))
                rubberBand.setColor(QColor(255, 0, 0, 128))
                rubberBand.setWidth(4)
            if args['result_cost'] != -1:
                query2 = sql.SQL("""
                    SELECT ST_AsText( ST_MakeLine(
                        (SELECT {geometry_vt} FROM  {vertex_schema}.{vertex_table} WHERE id = {result_source_id}),
                        (SELECT {geometry_vt} FROM  {vertex_schema}.{vertex_table} WHERE id = {result_target_id})
                        ))
                    """).format(**args)
                # Utils.logMessage(query2)
                cur2.execute(query2)
                row2 = cur2.fetchone()
                # Utils.logMessage(str(row2[0]))

                geom = QgsGeometry().fromWkt(str(row2[0]))
                if geom.wkbType() == QgsWkbTypes.MultiLineString:
                    for line in geom.asMultiPolyline():
                        for pt in line:
                            rubberBand.addPoint(pt)
                elif geom.wkbType() == QgsWkbTypes.LineString:
                    for pt in geom.asPolyline():
                        rubberBand.addPoint(pt)

        # TODO label the edge instead of labeling the target points
        if rubberBand:
            resultPathsRubberBands.append(rubberBand)
            rubberBand = None
        resultNodesTextAnnotations = canvasItemList['annotations']
        for row in rows:
            cur2 = con.cursor()
            args['result_seq'] = row[0]
            args['result_source_id'] = sql.Literal(row[1])
            result_target_id = row[2]
            args['result_target_id'] = sql.Literal(result_target_id)
            result_cost = row[3]
            query2 = sql.SQL("""
                SELECT ST_AsText( ST_startPoint({geometry}) ) FROM {edge_schema}.{edge_table}
                    WHERE {source} = {result_target_id}
                UNION
                SELECT ST_AsText( ST_endPoint( {geometry} ) ) FROM {edge_schema}.{edge_table}
                    WHERE {target} = {result_target_id}
                """).format(**args)
            cur2.execute(query2)
            row2 = cur2.fetchone()

            geom = QgsGeometry().fromWkt(str(row2[0]))
            pt = geom.asPoint()
            textDocument = QTextDocument("{0!s}:{1}".format(result_target_id, result_cost))
            textAnnotation = QgsTextAnnotation()
            textAnnotation.setMapPosition(geom.asPoint())
            textAnnotation.setFrameSize(QSizeF(textDocument.idealWidth(), 20))
            textAnnotation.setFrameOffsetFromReferencePoint(QPointF(20, -40))
            textAnnotation.setDocument(textDocument)

            QgsMapCanvasAnnotationItem(textAnnotation, mapCanvas)
            resultNodesTextAnnotations.append(textAnnotation)
class QgepMapToolDigitizeDrainageChannel(QgsMapTool):
    '''
    This is used to digitize a drainage channel.

    It lets you digitize two points and then creates a polygon based on these two points
    by adding an orthogonal offset at each side.

    Input:

       x==============x

    Output:

       ----------------
       |              |
       ----------------

    Usage:
      Connect to the signals deactivated() and geometryDigitized()
      If geometryDigitized() is called you can use the member variable geometry
      which will contain a rectangle polygon
      deactivated() will be emited after a right click
    '''

    geometryDigitized = pyqtSignal()

    def __init__(self, iface, layer):
        QgsMapTool.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.layer = layer
        self.rubberband = QgsRubberBand(iface.mapCanvas(),
                                        QgsWkbTypes.LineGeometry)
        self.rubberband.setColor(QColor("#ee5555"))
        self.rubberband.setWidth(2)
        self.firstPoint = None
        self.messageBarItem = None
        self.geometry = None

    def activate(self):
        """
        Map tool is activated
        """
        QgsMapTool.activate(self)
        self.canvas.setCursor(QCursor(Qt.CrossCursor))
        msgtitle = self.tr('Digitizing Drainage Channel')
        msg = self.tr('Digitize start and end point. Rightclick to abort.')
        self.messageBarItem = QgsMessageBar.createMessage(msgtitle, msg)
        self.iface.messageBar().pushItem(self.messageBarItem)

    def deactivate(self):
        """
        Map tool is deactivated
        """
        QgsMapTool.deactivate(self)
        self.iface.messageBar().popWidget(self.messageBarItem)
        try:
            self.iface.mapCanvas().scene().removeItem(self.rubberband)
            del self.rubberband
        except AttributeError:
            # Called repeatedly... bail out
            pass
        self.canvas.unsetCursor()

    def canvasMoveEvent(self, event):
        """
        Mouse is moved: Update rubberband
        :param event: coordinates etc.
        """
        mousepos = event.mapPoint()
        self.rubberband.movePoint(mousepos)

    def canvasReleaseEvent(self, event):
        """
        Canvas is released. This means:
          * start digitizing
          * stop digitizing (create a rectangle
            * if the Ctrl-modifier is pressed, ask for the rectangle width
        :param event: coordinates etc.
        """
        if event.button() == Qt.RightButton:
            self.deactivate()
        else:
            mousepos = self.canvas.getCoordinateTransform()\
                .toMapCoordinates(event.pos().x(), event.pos().y())
            self.rubberband.addPoint(mousepos)
            if self.firstPoint:  # If the first point was set before, we are doing the second one
                lp1 = self.rubberband.asGeometry().asPolyline()[0]
                lp2 = self.rubberband.asGeometry().asPolyline()[1]
                width = 0.2
                if QApplication.keyboardModifiers() & Qt.ControlModifier:
                    dlg = QDialog()
                    dlg.setLayout(QGridLayout())
                    dlg.layout().addWidget(QLabel(self.tr('Enter width')))
                    txt = QLineEdit('0.2')
                    dlg.layout().addWidget(txt)
                    bb = QDialogButtonBox(QDialogButtonBox.Ok
                                          | QDialogButtonBox.Cancel)
                    dlg.layout().addWidget(bb)
                    bb.accepted.connect(dlg.accept)
                    bb.rejected.connect(dlg.reject)
                    if dlg.exec_():
                        try:
                            width = float(txt.text())
                        except ValueError:
                            width = 0.2

                length = math.sqrt(
                    math.pow(lp1.x() - lp2.x(), 2) +
                    math.pow(lp1.y() - lp2.y(), 2))
                xd = lp2.x() - lp1.x()
                yd = lp2.y() - lp1.y()

                pt1 = QgsPointXY(lp1.x() + width * (yd / length),
                                 lp1.y() - width * (xd / length))
                pt2 = QgsPointXY(lp1.x() - width * (yd / length),
                                 lp1.y() + width * (xd / length))
                pt3 = QgsPointXY(lp2.x() - width * (yd / length),
                                 lp2.y() + width * (xd / length))
                pt4 = QgsPointXY(lp2.x() + width * (yd / length),
                                 lp2.y() - width * (xd / length))

                self.geometry = QgsGeometry.fromPolygonXY(
                    [[pt1, pt2, pt3, pt4, pt1]])

                self.geometryDigitized.emit()

            self.firstPoint = mousepos
Example #15
0
class Qgis2threejsDialog(QDialog):

  def __init__(self, iface, objectTypeManager, pluginManager, exportSettings=None, lastTreeItemData=None):
    QDialog.__init__(self, iface.mainWindow())
    self.iface = iface
    self.objectTypeManager = objectTypeManager
    self.pluginManager = pluginManager
    self._settings = exportSettings or {}
    self.lastTreeItemData = lastTreeItemData
    self.localBrowsingMode = True

    self.rb_quads = self.rb_point = None

    self.templateType = None
    self.currentItem = None
    self.currentPage = None

    # Set up the user interface from Designer.
    self.ui = ui = Ui_Qgis2threejsDialog()
    ui.setupUi(self)

    self.setWindowFlags(self.windowFlags() | Qt.WindowMinimizeButtonHint)

    # output html filename
    ui.lineEdit_OutputFilename.setText(self._settings.get("OutputFilename", ""))
    ui.lineEdit_OutputFilename.setPlaceholderText("[Temporary file]")

    # settings button
    icon = QIcon(os.path.join(tools.pluginDir(), "icons", "settings.png"))
    ui.toolButton_Settings.setIcon(icon)

    # popup menu displayed when settings button is pressed
    items = [["Load Settings...", self.loadSettings],
             ["Save Settings As...", self.saveSettings],
             [None, None],
             ["Clear Settings", self.clearSettings],
             [None, None],
             ["Plugin Settings...", self.pluginSettings]]

    self.menu = QMenu()
    self.menu_actions = []
    for text, slot in items:
      if text:
        action = QAction(text, iface.mainWindow())
        action.triggered.connect(slot)
        self.menu.addAction(action)
        self.menu_actions.append(action)
      else:
        self.menu.addSeparator()

    ui.toolButton_Settings.setMenu(self.menu)
    ui.toolButton_Settings.setPopupMode(QToolButton.InstantPopup)

    # progress bar and message label
    ui.progressBar.setVisible(False)
    ui.label_MessageIcon.setVisible(False)

    # buttons
    ui.pushButton_Run.clicked.connect(self.run)
    ui.pushButton_Close.clicked.connect(self.reject)
    ui.pushButton_Help.clicked.connect(self.help)

    # set up map tool
    self.previousMapTool = None
    self.mapTool = RectangleMapTool(iface.mapCanvas())
    #self.mapTool = PointMapTool(iface.mapCanvas())

    # set up the template combo box
    self.initTemplateList()
    self.ui.comboBox_Template.currentIndexChanged.connect(self.currentTemplateChanged)

    # set up the properties pages
    self.pages = {}
    self.pages[ppages.PAGE_WORLD] = ppages.WorldPropertyPage(self)
    self.pages[ppages.PAGE_CONTROLS] = ppages.ControlsPropertyPage(self)
    self.pages[ppages.PAGE_DEM] = ppages.DEMPropertyPage(self)
    self.pages[ppages.PAGE_VECTOR] = ppages.VectorPropertyPage(self)
    container = ui.propertyPagesContainer
    for page in self.pages.itervalues():
      page.hide()
      container.addWidget(page)

    # build object tree
    self.topItemPages = {ObjectTreeItem.ITEM_WORLD: ppages.PAGE_WORLD, ObjectTreeItem.ITEM_CONTROLS: ppages.PAGE_CONTROLS, ObjectTreeItem.ITEM_DEM: ppages.PAGE_DEM}
    self.initObjectTree()
    self.ui.treeWidget.currentItemChanged.connect(self.currentObjectChanged)
    self.ui.treeWidget.itemChanged.connect(self.objectItemChanged)
    self.currentTemplateChanged()   # update item visibility

    ui.toolButton_Browse.clicked.connect(self.browseClicked)

    #iface.mapCanvas().mapToolSet.connect(self.mapToolSet)    # to show button to enable own map tool

  def settings(self, clean=False):
    # save settings of current panel
    item = self.ui.treeWidget.currentItem()
    if item and self.currentPage:
      self.saveProperties(item, self.currentPage)

    # plugin version
    self._settings["PluginVersion"] = plugin_version

    # template and output html file path
    self._settings["Template"] = self.ui.comboBox_Template.currentText()
    self._settings["OutputFilename"] = self.ui.lineEdit_OutputFilename.text()

    if not clean:
      return self._settings

    # clean up settings - remove layers that don't exist in the layer registry
    registry = QgsMapLayerRegistry.instance()
    for itemId in [ObjectTreeItem.ITEM_OPTDEM, ObjectTreeItem.ITEM_POINT, ObjectTreeItem.ITEM_LINE, ObjectTreeItem.ITEM_POLYGON]:
      parent = self._settings.get(itemId, {})
      for layerId in parent.keys():
        if registry.mapLayer(layerId) is None:
          del parent[layerId]

    return self._settings

  def setSettings(self, settings):
    self._settings = settings

    # template and output html file path
    templateName = settings.get("Template")
    if templateName:
      cbox = self.ui.comboBox_Template
      index = cbox.findText(templateName)
      if index != -1:
        cbox.setCurrentIndex(index)

    filename = settings.get("OutputFilename")
    if filename:
      self.ui.lineEdit_OutputFilename.setText(filename)

    # update object tree
    self.ui.treeWidget.blockSignals(True)
    self.initObjectTree()
    self.ui.treeWidget.blockSignals(False)

    # update tree item visibility
    self.templateType = None
    self.currentTemplateChanged()

  def loadSettings(self):
    # file open dialog
    directory = QgsProject.instance().homePath()
    if not directory:
      directory = os.path.split(self.ui.lineEdit_OutputFilename.text())[0]
    if not directory:
      directory = QDir.homePath()
    filterString = "Settings files (*.qto3settings);;All files (*.*)"
    filename = QFileDialog.getOpenFileName(self, "Load Export Settings", directory, filterString)
    if not filename:
      return

    # load settings from file (.qto3settings)
    import json
    with open(filename) as f:
      settings = json.load(f)

    self.setSettings(settings)

  def saveSettings(self, filename=None):
    if not filename:
      # file save dialog
      directory = QgsProject.instance().homePath()
      if not directory:
        directory = os.path.split(self.ui.lineEdit_OutputFilename.text())[0]
      if not directory:
        directory = QDir.homePath()
      filename = QFileDialog.getSaveFileName(self, "Save Export Settings", directory, "Settings files (*.qto3settings)")
      if not filename:
        return

      # append .qto3settings extension if filename doesn't have
      if os.path.splitext(filename)[1].lower() != ".qto3settings":
        filename += ".qto3settings"

    # save settings to file (.qto3settings)
    import codecs
    import json
    with codecs.open(filename, "w", "UTF-8") as f:
      json.dump(self.settings(True), f, ensure_ascii=False, indent=2, sort_keys=True)

    logMessage(u"Settings saved: {0}".format(filename))

  def clearSettings(self):
    if QMessageBox.question(self, "Qgis2threejs", "Are you sure to clear all export settings?", QMessageBox.Ok | QMessageBox.Cancel) == QMessageBox.Ok:
      self.setSettings({})

  def pluginSettings(self):
    from settingsdialog import SettingsDialog
    dialog = SettingsDialog(self)
    if dialog.exec_():
      self.pluginManager.reloadPlugins()
      self.pages[ppages.PAGE_DEM].initLayerComboBox()

  def showMessageBar(self, text, level=QgsMessageBar.INFO):
    # from src/gui/qgsmessagebaritem.cpp
    if level == QgsMessageBar.CRITICAL:
      msgIcon = "/mIconCritical.png"
      bgColor = "#d65253"
    elif level == QgsMessageBar.WARNING:
      msgIcon = "/mIconWarn.png"
      bgColor = "#ffc800"
    else:
      msgIcon = "/mIconInfo.png"
      bgColor = "#e7f5fe"
    stylesheet = "QLabel {{ background-color:{0}; }}".format(bgColor)

    label = self.ui.label_MessageIcon
    label.setPixmap(QgsApplication.getThemeIcon(msgIcon).pixmap(24))
    label.setStyleSheet(stylesheet)
    label.setVisible(True)

    label = self.ui.label_Status
    label.setText(text)
    label.setStyleSheet(stylesheet)

  def clearMessageBar(self):
    self.ui.label_MessageIcon.setVisible(False)
    self.ui.label_Status.setText("")
    self.ui.label_Status.setStyleSheet("QLabel { background-color: rgba(0, 0, 0, 0); }")

  def initTemplateList(self):
    cbox = self.ui.comboBox_Template
    cbox.clear()
    templateDir = QDir(tools.templateDir())
    for i, entry in enumerate(templateDir.entryList(["*.html", "*.htm"])):
      cbox.addItem(entry)

      config = tools.getTemplateConfig(entry)
      # get template type
      templateType = config.get("type", "plain")
      cbox.setItemData(i, templateType, Qt.UserRole)

      # set tool tip text
      desc = config.get("description", "")
      if desc:
        cbox.setItemData(i, desc, Qt.ToolTipRole)

    # select the template of the settings
    templatePath = self._settings.get("Template")

    # if no template setting, select the last used template
    if not templatePath:
      templatePath = QSettings().value("/Qgis2threejs/lastTemplate", def_vals.template, type=unicode)

    if templatePath:
      index = cbox.findText(templatePath)
      if index != -1:
        cbox.setCurrentIndex(index)
      return index
    return -1

  def initObjectTree(self):
    tree = self.ui.treeWidget
    tree.clear()

    # add vector and raster layers into tree widget
    topItems = {}
    for id, name in zip(ObjectTreeItem.topItemIds, ObjectTreeItem.topItemNames):
      item = QTreeWidgetItem(tree, [name])
      item.setData(0, Qt.UserRole, id)
      topItems[id] = item

    optDEMChecked = False
    for layer in self.iface.legendInterface().layers():
      parentId = ObjectTreeItem.parentIdByLayer(layer)
      if parentId is None:
        continue

      item = QTreeWidgetItem(topItems[parentId], [layer.name()])
      isVisible = self._settings.get(parentId, {}).get(layer.id(), {}).get("visible", False)   #self.iface.legendInterface().isLayerVisible(layer)
      check_state = Qt.Checked if isVisible else Qt.Unchecked
      item.setData(0, Qt.CheckStateRole, check_state)
      item.setData(0, Qt.UserRole, layer.id())
      if parentId == ObjectTreeItem.ITEM_OPTDEM and isVisible:
        optDEMChecked = True

    for id, item in topItems.iteritems():
      if id != ObjectTreeItem.ITEM_OPTDEM or optDEMChecked:
        tree.expandItem(item)

    # disable additional DEM item which is selected as main DEM
    layerId = self._settings.get(ObjectTreeItem.ITEM_DEM, {}).get("comboBox_DEMLayer")
    if layerId:
      self.primaryDEMChanged(layerId)

  def saveProperties(self, item, page):
    properties = page.properties()
    parent = item.parent()
    if parent is None:
      # top level item
      self._settings[item.data(0, Qt.UserRole)] = properties
    else:
      # layer item
      parentId = parent.data(0, Qt.UserRole)
      if parentId not in self._settings:
        self._settings[parentId] = {}
      self._settings[parentId][item.data(0, Qt.UserRole)] = properties

  def setCurrentTreeItemByData(self, data):
    it = QTreeWidgetItemIterator(self.ui.treeWidget)
    while it.value():
      if it.value().data(0, Qt.UserRole) == data:
        self.ui.treeWidget.setCurrentItem(it.value())
        return True
      it += 1
    return False

  def currentTemplateChanged(self, index=None):
    cbox = self.ui.comboBox_Template
    templateType = cbox.itemData(cbox.currentIndex(), Qt.UserRole)
    if templateType == self.templateType:
      return

    # hide items unsupported by template
    tree = self.ui.treeWidget
    for i, id in enumerate(ObjectTreeItem.topItemIds):
      hidden = (templateType == "sphere" and id != ObjectTreeItem.ITEM_CONTROLS)
      tree.topLevelItem(i).setHidden(hidden)

    # set current tree item
    if templateType == "sphere":
      tree.setCurrentItem(tree.topLevelItem(ObjectTreeItem.topItemIndex(ObjectTreeItem.ITEM_CONTROLS)))
    elif self.lastTreeItemData is None or not self.setCurrentTreeItemByData(self.lastTreeItemData):   # restore selection
      tree.setCurrentItem(tree.topLevelItem(ObjectTreeItem.topItemIndex(ObjectTreeItem.ITEM_DEM)))   # default selection for plain is DEM

    # display messages
    self.clearMessageBar()
    if templateType != "sphere":
      # show message if crs unit is degrees
      mapSettings = self.iface.mapCanvas().mapSettings() if QGis.QGIS_VERSION_INT >= 20300 else self.iface.mapCanvas().mapRenderer()
      if mapSettings.destinationCrs().mapUnits() in [QGis.Degrees]:
        self.showMessageBar("The unit of current CRS is degrees, so terrain may not appear well.", QgsMessageBar.WARNING)

    self.templateType = templateType

  def currentObjectChanged(self, currentItem, previousItem):
    # save properties of previous item
    if previousItem and self.currentPage:
      self.saveProperties(previousItem, self.currentPage)

    self.currentItem = currentItem
    self.currentPage = None

    # hide text browser and all pages
    self.ui.textBrowser.hide()
    for page in self.pages.itervalues():
      page.hide()

    parent = currentItem.parent()
    if parent is None:
      topItemIndex = currentItem.data(0, Qt.UserRole)
      pageType = self.topItemPages.get(topItemIndex, ppages.PAGE_NONE)
      page = self.pages.get(pageType, None)
      if page is None:
        self.showDescription(topItemIndex)
        return

      page.setup(self._settings.get(topItemIndex))
      page.show()

    else:
      parentId = parent.data(0, Qt.UserRole)
      layerId = currentItem.data(0, Qt.UserRole)
      layer = QgsMapLayerRegistry.instance().mapLayer(unicode(layerId))
      if layer is None:
        return

      layerType = layer.type()
      if layerType == QgsMapLayer.RasterLayer:
        page = self.pages[ppages.PAGE_DEM]
        page.setup(self._settings.get(parentId, {}).get(layerId, None), layer, False)
      elif layerType == QgsMapLayer.VectorLayer:
        page = self.pages[ppages.PAGE_VECTOR]
        page.setup(self._settings.get(parentId, {}).get(layerId, None), layer)
      else:
        return

      page.show()

    self.currentPage = page

  def objectItemChanged(self, item, column):
    parent = item.parent()
    if parent is None:
      return

    # checkbox of optional layer checked/unchecked
    if item == self.currentItem:
      if self.currentPage:
        # update enablement of property widgets
        self.currentPage.itemChanged(item)
    else:
      # select changed item
      self.ui.treeWidget.setCurrentItem(item)

      # set visible property
      #visible = item.data(0, Qt.CheckStateRole) == Qt.Checked
      #parentId = parent.data(0, Qt.UserRole)
      #layerId = item.data(0, Qt.UserRole)
      #self._settings.get(parentId, {}).get(layerId, {})["visible"] = visible

  def primaryDEMChanged(self, layerId):
    tree = self.ui.treeWidget
    parent = tree.topLevelItem(ObjectTreeItem.topItemIndex(ObjectTreeItem.ITEM_OPTDEM))
    tree.blockSignals(True)
    for i in range(parent.childCount()):
      item = parent.child(i)
      isPrimary = item.data(0, Qt.UserRole) == layerId
      item.setDisabled(isPrimary)
    tree.blockSignals(False)

  def showDescription(self, topItemIndex):
    fragment = {ObjectTreeItem.ITEM_OPTDEM: "additional-dem",
                ObjectTreeItem.ITEM_POINT: "point",
                ObjectTreeItem.ITEM_LINE: "line",
                ObjectTreeItem.ITEM_POLYGON: "polygon"}.get(topItemIndex)

    url = "http://qgis2threejs.readthedocs.org/en/docs-release/ExportSettings.html"
    if fragment:
      url += "#" + fragment

    html = '<a href="{0}">Online Help</a> about this item'.format(url)
    self.ui.textBrowser.setHtml(html)
    self.ui.textBrowser.show()

  def numericFields(self, layer):
    # get attributes of a sample feature and create numeric field name list
    numeric_fields = []
    f = QgsFeature()
    layer.getFeatures().nextFeature(f)
    for field in f.fields():
      isNumeric = False
      try:
        float(f.attribute(field.name()))
        isNumeric = True
      except ValueError:
        pass
      if isNumeric:
        numeric_fields.append(field.name())
    return numeric_fields

  def mapTo3d(self):
    canvas = self.iface.mapCanvas()
    mapSettings = canvas.mapSettings() if QGis.QGIS_VERSION_INT >= 20300 else canvas.mapRenderer()

    world = self._settings.get(ObjectTreeItem.ITEM_WORLD, {})
    bs = float(world.get("lineEdit_BaseSize", def_vals.baseSize))
    ve = float(world.get("lineEdit_zFactor", def_vals.zExaggeration))
    vs = float(world.get("lineEdit_zShift", def_vals.zShift))

    return MapTo3D(mapSettings, bs, ve, vs)

  def progress(self, percentage=None, statusMsg=None):
    ui = self.ui
    if percentage is not None:
      ui.progressBar.setValue(percentage)
      if percentage == 100:
        ui.progressBar.setVisible(False)
        ui.label_Status.setText("")
      else:
        ui.progressBar.setVisible(True)

    if statusMsg is not None:
      ui.label_Status.setText(statusMsg)
      ui.label_Status.repaint()
    QgsApplication.processEvents(QEventLoop.ExcludeUserInputEvents)

  def run(self):
    self.endPointSelection()

    ui = self.ui
    filename = ui.lineEdit_OutputFilename.text()   # ""=Temporary file
    if filename and os.path.exists(filename):
      if QMessageBox.question(self, "Qgis2threejs", "Output file already exists. Overwrite it?", QMessageBox.Ok | QMessageBox.Cancel) != QMessageBox.Ok:
        return

    # export to web (three.js)
    export_settings = ExportSettings(self.pluginManager, self.localBrowsingMode)
    export_settings.loadSettings(self.settings())
    export_settings.setMapCanvas(self.iface.mapCanvas())

    err_msg = export_settings.checkValidity()
    if err_msg is not None:
      QMessageBox.warning(self, "Qgis2threejs", err_msg or "Invalid settings")
      return

    ui.pushButton_Run.setEnabled(False)
    ui.toolButton_Settings.setVisible(False)
    self.clearMessageBar()
    self.progress(0)

    if export_settings.exportMode == ExportSettings.PLAIN_MULTI_RES:
      # update quads and point on map canvas
      self.createRubberBands(export_settings.baseExtent, export_settings.quadtree())

    # export
    ret = exportToThreeJS(export_settings, self.iface.legendInterface(), self.objectTypeManager, self.progress)

    self.progress(100)
    ui.pushButton_Run.setEnabled(True)

    if not ret:
      ui.toolButton_Settings.setVisible(True)
      return

    self.clearRubberBands()

    # store last selections
    settings = QSettings()
    settings.setValue("/Qgis2threejs/lastTemplate", export_settings.templatePath)
    settings.setValue("/Qgis2threejs/lastControls", export_settings.controls)

    # open web browser
    if not tools.openHTMLFile(export_settings.htmlfilename):
      ui.toolButton_Settings.setVisible(True)
      return

    # close dialog
    QDialog.accept(self)

  def reject(self):
    # save properties of current object
    item = self.ui.treeWidget.currentItem()
    if item and self.currentPage:
      self.saveProperties(item, self.currentPage)

    self.endPointSelection()
    self.clearRubberBands()
    QDialog.reject(self)

  def help(self):
    url = "http://qgis2threejs.readthedocs.org/"

    import webbrowser
    webbrowser.open(url, new=2)    # new=2: new tab if possible

  def startPointSelection(self):
    canvas = self.iface.mapCanvas()
    if self.previousMapTool != self.mapTool:
      self.previousMapTool = canvas.mapTool()
    canvas.setMapTool(self.mapTool)
    self.pages[ppages.PAGE_DEM].toolButton_PointTool.setVisible(False)

  def endPointSelection(self):
    self.mapTool.reset()
    if self.previousMapTool is not None:
      self.iface.mapCanvas().setMapTool(self.previousMapTool)

  def mapToolSet(self, mapTool):
    return
    #TODO: unstable
    if mapTool != self.mapTool and self.currentPage is not None:
      if self.currentPage.pageType == ppages.PAGE_DEM and self.currentPage.isPrimary:
        self.currentPage.toolButton_PointTool.setVisible(True)

  def createRubberBands(self, baseExtent, quadtree):
    self.clearRubberBands()
    # create quads with rubber band
    self.rb_quads = QgsRubberBand(self.iface.mapCanvas(), QGis.Line)
    self.rb_quads.setColor(Qt.blue)
    self.rb_quads.setWidth(1)

    quads = quadtree.quads()
    for quad in quads:
      geom = baseExtent.subrectangle(quad.rect).geometry()
      self.rb_quads.addGeometry(geom, None)
    self.log("Quad count: %d" % len(quads))

    if not quadtree.focusRect:
      return

    # create a point with rubber band
    if quadtree.focusRect.width() == 0 or quadtree.focusRect.height() == 0:
      npt = quadtree.focusRect.center()
      self.rb_point = QgsRubberBand(self.iface.mapCanvas(), QGis.Point)
      self.rb_point.setColor(Qt.red)
      self.rb_point.addPoint(baseExtent.point(npt))

  def clearRubberBands(self):
    # clear quads and point
    if self.rb_quads:
      self.iface.mapCanvas().scene().removeItem(self.rb_quads)
      self.rb_quads = None
    if self.rb_point:
      self.iface.mapCanvas().scene().removeItem(self.rb_point)
      self.rb_point = None

  def browseClicked(self):
    directory = os.path.split(self.ui.lineEdit_OutputFilename.text())[0]
    if not directory:
      directory = QDir.homePath()
    filename = QFileDialog.getSaveFileName(self, self.tr("Output filename"), directory, "HTML file (*.html *.htm)", options=QFileDialog.DontConfirmOverwrite)
    if not filename:
      return

    # append .html extension if filename doesn't have either .html or .htm
    if filename[-5:].lower() != ".html" and filename[-4:].lower() != ".htm":
      filename += ".html"

    self.ui.lineEdit_OutputFilename.setText(filename)

  def log(self, msg):
    if debug_mode:
      qDebug(msg)
Example #16
0
class QgepProfileMapTool( QgepMapTool ):
    '''
    The map tool used for PROFILE
    
    Allows to find the shortest path between several nodes.
    '''
    profileChanged = pyqtSignal( object )
    profile = QgepProfile()
    segmentOffset = 0

    selectedPathPoints = []
    pathPolyline = []
    
    def __init__( self, canvas, button, networkAnalyzer ):
        QgepMapTool.__init__(self, canvas, button)
        settings = QSettings()
        
        helperLineColor = settings.value( "/QGEP/HelperLineColor", u'#FFD900' )
        highlightColor  = settings.value( "/QGEP/HighlightColor",  u'#40FF40' )
        
        self.networkAnalyzer = networkAnalyzer
        
        # Init rubberband to visualize current status
        self.rbHelperLine = QgsRubberBand( self.canvas )
        self.rbHelperLine.setColor( QColor( helperLineColor ) )
        self.rbHelperLine.setWidth( 2 )
        
        self.rbHighlight = QgsRubberBand( self.canvas )
        self.rbHighlight.setColor( QColor( highlightColor ) )
        self.rbHighlight.setWidth( 5 )
        
        self.profile.setRubberband( self.rbHighlight )

    def setActive( self ):
        '''
        activates this map tool
        '''
        self.saveTool = self.canvas.mapTool()
        self.canvas.setMapTool( self )

    def deactivate(self):
        '''
        Called whenever this map tool is deactivated.
        Used to clean up code
        '''
        QgepMapTool.deactivate(self)
        self.rubberBand.reset()
        self.rbHelperLine.reset()
        self.selectedPathPoints = []
        self.pathPolyline = []
        
    def findPath( self, pStart, pEnd ):
        '''
        Tries to find the shortest path between pStart and pEnd.
        If it finds a path:
         * The path is visualized with a QgsRubberband
         * The profile plot is updated to represent the current path
    
        @param pStart: The id of the start point of the path 
        @param pEnd:   The id of the end point of the path
        '''
        backupCursor = self.canvas.cursor()
        self.canvas.setCursor(Qt.WaitCursor)
        #try:
        ( vertices, edges ) = self.networkAnalyzer.shortestPath( pStart, pEnd )
        self.appendProfile( vertices, edges )
#        except:
#            pass
        self.canvas.setCursor(backupCursor)
        if len( vertices ) > 0:
            return True
        else:
            return False
        
    def appendProfile( self, vertices, edges ):
        '''
        Appends to the current profile
        
        @param vertices: A collection of vertices to append
        @param edges:    A collection of edges which connect the vertices
        '''
        self.logger.debug( 'Append profile' )
        self.logger.info( ' * ' + `len( vertices )` + ' vertices' )
        for v in vertices:
            self.logger.debug( '   *' + `v`)
        self.logger.info( ' * ' + `len( edges )` + ' edges')
        for e in edges:
            self.logger.debug( '   *' + `e`)
            
        # Fetch all the needed edges in one batch
        edgeLayer = self.networkAnalyzer.getReachLayer()
        edgeAttrs = edgeLayer.dataProvider().attributeIndexes()
        edgeIds = [edge['feature'] for p1, p2, edge in edges]
        
        edgeFeatures = self.networkAnalyzer.getFeaturesById(edgeLayer, edgeAttrs, edgeIds, True)

        # We need some additional nodes, where we need to interpolate...
        interpolateNodesFrom = [edgeFeatures.attrAsUnicode( feat, u'from_obj_id_interpolate' ) for feat in edgeFeatures.asDict().values()]
        interpolateNodesTo   = [edgeFeatures.attrAsUnicode( feat, u'to_obj_id_interpolate' ) for feat in edgeFeatures.asDict().values()]
        additionalIds = [self.networkAnalyzer.vertexIds[node] for node in interpolateNodesFrom]
        additionalIds += [self.networkAnalyzer.vertexIds[node] for node in interpolateNodesTo]
        
        # Now, fetch the nodes we need
        nodeLayer = self.networkAnalyzer.getNodeLayer()
        nodeIds = vertices + additionalIds
        nodeAttrs = nodeLayer.dataProvider().attributeIndexes()
        nodeFeatures = self.networkAnalyzer.getFeaturesById(nodeLayer, nodeAttrs, nodeIds, False)
        
        if len( vertices ) > 1:
            self.rubberBand.reset()
            
            elem = QgepProfileNodeElement( vertices[0], nodeFeatures, 0 )
            self.profile.addElement( vertices[0], elem )
            
            for p1, p2, edge in edges:
                fromOffset = self.segmentOffset
                toOffset = self.segmentOffset + edge['weight']
                
                if 'reach' == edge['objType']:
                    if self.profile.hasElement( edge['baseFeature'] ):
                        self.profile[edge['baseFeature']].addSegment( p1, p2, edge['feature'], nodeFeatures, edgeFeatures, fromOffset, toOffset )
                    else:
                        elem = QgepProfileReachElement( p1, p2, edge['feature'], nodeFeatures, edgeFeatures, fromOffset, toOffset )
                        self.profile.addElement(elem.objId, elem)
                    
                elif 'special_structure' == edge['objType']:
                    if self.profile.hasElement( edge['baseFeature'] ):
                        self.profile[edge['baseFeature']].addSegment( p1, p2, edge['feature'], nodeFeatures, edgeFeatures, fromOffset, toOffset )
                    else:
                        elem = QgepProfileSpecialStructureElement( p1, p2, edge['feature'], nodeFeatures, edgeFeatures, fromOffset, toOffset )
                        self.profile.addElement(elem.objId, elem)
                
                elem = QgepProfileNodeElement( p2, nodeFeatures, toOffset )
                self.profile.addElement(p2, elem)
                
                self.segmentOffset = toOffset

            self.profileChanged.emit( self.profile )
            
            # Create rubberband geometry
            for featId in edgeIds:
                self.pathPolyline.extend( edgeFeatures[featId].geometry().asPolyline() )
            
            self.rubberBand.addGeometry( QgsGeometry.fromPolyline( self.pathPolyline ), nodeLayer )
            self.profileChanged.emit( self.profile )
            return True
        else:
            return False

    def mouseMoved( self, event ):
        '''
        Mouse moved: update helper line
        
        @param event: The mouse event with coordinates and all
        '''
        if len( self.selectedPathPoints ) > 0:
            self.rbHelperLine.reset()
            for point in self.selectedPathPoints:
                self.rbHelperLine.addPoint( point[1] )
            mousePos = self.canvas.getCoordinateTransform().toMapCoordinates( event.pos().x(), event.pos().y() )
            self.rbHelperLine.addPoint( mousePos )

    def rightClicked( self, event ):
        '''
        Cancel any ongoing path selection
        
        @param event: The mouse event with coordinates and all
        '''
        self.selectedPathPoints = []
        self.pathPolyline = []
        self.rbHelperLine.reset()
        self.profile.reset()
        self.segmentOffset = 0

    def leftClicked( self, event ):
        '''
        Select startpoint / intermediate point / endpoint
        
        @param event: The mouse event with coordinates and all
        '''
        snappedPoint = self.networkAnalyzer.snapPoint( event )
        
        if snappedPoint is not None:
            if len( self.selectedPathPoints ) > 0:
                pf = self.findPath( self.selectedPathPoints[-1][0], snappedPoint.snappedAtGeometry )
                if pf:
                    self.selectedPathPoints.append( ( snappedPoint.snappedAtGeometry, QgsPoint( snappedPoint.snappedVertex ) ) )
                else:
                    msg = self.msgBar.createMessage( 'No path found' )
                    self.msgBar.pushWidget( msg, QgsMessageBar.WARNING )
            else:
                self.selectedPathPoints.append( ( snappedPoint.snappedAtGeometry, QgsPoint( snappedPoint.snappedVertex ) ) )
class SplitMapTool(QgsMapToolEdit):
    def __init__(self, canvas, layer, actionMoveVertices, actionAddVertices,
                 actionRemoveVertices, actionMoveSegment, actionLineClose,
                 actionLineOpen, actionMoveLine):
        super(SplitMapTool, self).__init__(canvas)
        self.canvas = canvas
        self.scene = canvas.scene()
        self.layer = layer
        self.actionMoveVertices = actionMoveVertices
        self.actionAddVertices = actionAddVertices
        self.actionRemoveVertices = actionRemoveVertices
        self.actionMoveSegment = actionMoveSegment
        self.actionLineClose = actionLineClose
        self.actionLineOpen = actionLineOpen
        self.actionMoveLine = actionMoveLine
        self.initialize()

    def initialize(self):
        try:
            self.canvas.renderStarting.disconnect(self.mapCanvasChanged)
        except:
            pass
        self.canvas.renderStarting.connect(self.mapCanvasChanged)
        try:
            self.layer.editingStopped.disconnect(self.stopCapturing)
        except:
            pass
        self.layer.editingStopped.connect(self.stopCapturing)

        self.selectedFeatures = self.layer.selectedFeatures()
        self.rubberBand = None
        self.tempRubberBand = None
        self.capturedPoints = []
        self.capturing = False
        self.setCursor(Qt.CrossCursor)
        self.proj = QgsProject.instance()
        self.labels = []
        self.vertices = []
        self.calculator = QgsDistanceArea()
        self.calculator.setSourceCrs(self.layer.dataProvider().crs(),
                                     QgsProject.instance().transformContext())
        self.calculator.setEllipsoid(
            self.layer.dataProvider().crs().ellipsoidAcronym())
        self.drawingLine = False
        self.movingVertices = False
        self.addingVertices = False
        self.removingVertices = False
        self.movingSegment = False
        self.movingLine = False
        self.showingVertices = False
        self.movingVertex = -1
        self.movingSegm = -1
        self.movingLineInitialPoint = None
        self.lineClosed = False

    def restoreAction(self):
        self.addingVertices = False
        self.removingVertices = False
        self.movingVertices = False
        self.movingSegment = False
        self.movingLine = False
        self.showingVertices = False
        self.drawingLine = True
        self.movingVertex = -1
        self.movingLineInitialPoint = None
        self.deleteVertices()
        self.redrawRubberBand()
        self.redrawTempRubberBand()
        self.canvas.scene().addItem(self.tempRubberBand)
        self.redrawActions()

    def mapCanvasChanged(self):
        self.redrawAreas()
        if self.showingVertices:
            self.redrawVertices()

    def canvasMoveEvent(self, event):
        if self.drawingLine and not self.lineClosed:
            if self.tempRubberBand != None and self.capturing:
                mapPoint = self.toMapCoordinates(event.pos())
                self.tempRubberBand.movePoint(mapPoint)
                self.redrawAreas(event.pos())

        if self.movingVertices and self.movingVertex >= 0:
            layerPoint = self.toLayerCoordinates(self.layer, event.pos())
            self.capturedPoints[self.movingVertex] = layerPoint

            if self.lineClosed and self.movingVertex == 0:
                self.capturedPoints[len(self.capturedPoints) - 1] = layerPoint

            self.redrawRubberBand()
            self.redrawVertices()
            self.redrawAreas()

        if self.movingSegment and self.movingSegm >= 0:
            currentPoint = self.toLayerCoordinates(self.layer, event.pos())
            distance = self.distancePoint(currentPoint,
                                          self.movingLineInitialPoint)
            bearing = self.movingLineInitialPoint.azimuth(currentPoint)

            self.capturedPoints[self.movingSegm] = self.projectPoint(
                self.capturedPoints[self.movingSegm], distance, bearing)
            self.capturedPoints[self.movingSegm + 1] = self.projectPoint(
                self.capturedPoints[self.movingSegm + 1], distance, bearing)

            if self.lineClosed:
                if self.movingSegm == 0:
                    self.capturedPoints[
                        len(self.capturedPoints) - 1] = self.projectPoint(
                            self.capturedPoints[len(self.capturedPoints) - 1],
                            distance, bearing)
                elif self.movingSegm == len(self.capturedPoints) - 2:
                    self.capturedPoints[0] = self.projectPoint(
                        self.capturedPoints[0], distance, bearing)

            self.redrawRubberBand()
            self.redrawVertices()
            self.redrawAreas()
            self.movingLineInitialPoint = currentPoint

        if self.movingLine and self.movingLineInitialPoint != None:
            currentPoint = self.toLayerCoordinates(self.layer, event.pos())
            distance = self.distancePoint(currentPoint,
                                          self.movingLineInitialPoint)
            bearing = self.movingLineInitialPoint.azimuth(currentPoint)
            for i in range(len(self.capturedPoints)):
                self.capturedPoints[i] = self.projectPoint(
                    self.capturedPoints[i], distance, bearing)
            self.redrawRubberBand()
            self.redrawAreas()
            self.movingLineInitialPoint = currentPoint

    def projectPoint(self, point, distance, bearing):
        rads = bearing * pi / 180.0
        dx = distance * sin(rads)
        dy = distance * cos(rads)
        return QgsPointXY(point.x() + dx, point.y() + dy)

    def redrawAreas(self, mousePos=None):
        self.deleteLabels()

        if self.capturing and len(self.capturedPoints) > 0:
            for i in range(len(self.selectedFeatures)):
                geometry = QgsGeometry(self.selectedFeatures[i].geometry())
                movingPoints = list(self.capturedPoints)

                if mousePos != None:
                    movingPoints.append(
                        self.toLayerCoordinates(self.layer, mousePos))

                result, newGeometries, topoTestPoints = geometry.splitGeometry(
                    movingPoints, self.proj.topologicalEditing())

                self.addLabel(geometry)
                if newGeometries != None and len(newGeometries) > 0:
                    for i in range(len(newGeometries)):
                        self.addLabel(newGeometries[i])

    def addLabel(self, geometry):
        area = self.calculator.measureArea(geometry)
        labelPoint = geometry.pointOnSurface().vertexAt(0)
        label = QGraphicsTextItem("%.2f" % round(area, 2))
        label.setHtml(
            "<div style=\"color:#ffffff;background:#111111;padding:5px\">" +
            "%.2f" % round(area, 2) + " " +
            areaUnits[self.calculator.areaUnits()] + "</div>")
        point = self.toMapCoordinatesV2(self.layer, labelPoint)
        label.setPos(self.toCanvasCoordinates(QgsPointXY(point.x(),
                                                         point.y())))

        self.scene.addItem(label)
        self.labels.append(label)

    def deleteLabels(self):
        for i in range(len(self.labels)):
            self.scene.removeItem(self.labels[i])
        self.labels = []

    def canvasPressEvent(self, event):
        if self.movingVertices:
            for i in range(len(self.capturedPoints)):
                point = self.toMapCoordinates(self.layer,
                                              self.capturedPoints[i])
                currentVertex = self.toCanvasCoordinates(
                    QgsPointXY(point.x(), point.y()))
                if self.distancePoint(event.pos(),
                                      currentVertex) <= maxDistanceHitTest:
                    self.movingVertex = i
                    break

        if self.movingSegment:
            for i in range(len(self.capturedPoints) - 1):
                vertex1 = self.toMapCoordinates(self.layer,
                                                self.capturedPoints[i])
                currentVertex1 = self.toCanvasCoordinates(
                    QgsPointXY(vertex1.x(), vertex1.y()))
                vertex2 = self.toMapCoordinates(self.layer,
                                                self.capturedPoints[i + 1])
                currentVertex2 = self.toCanvasCoordinates(
                    QgsPointXY(vertex2.x(), vertex2.y()))
                if self.distancePointLine(
                        event.pos().x(),
                        event.pos().y(), currentVertex1.x(),
                        currentVertex1.y(), currentVertex2.x(),
                        currentVertex2.y()) <= maxDistanceHitTest:
                    self.movingSegm = i
                    break

        self.movingLineInitialPoint = self.toLayerCoordinates(
            self.layer, event.pos())

    def distancePoint(self, eventPos, vertexPos):
        return sqrt((eventPos.x() - vertexPos.x())**2 +
                    (eventPos.y() - vertexPos.y())**2)

    def canvasReleaseEvent(self, event):
        if self.movingVertices or self.movingSegment or self.movingLine:
            if event.button() == Qt.RightButton:
                self.finishOperation()
        elif self.addingVertices:
            if event.button() == Qt.LeftButton:
                self.addVertex(event.pos())
            elif event.button() == Qt.RightButton:
                self.finishOperation()
        elif self.removingVertices:
            if event.button() == Qt.LeftButton:
                self.removeVertex(event.pos())
            elif event.button() == Qt.RightButton:
                self.finishOperation()
        else:
            if event.button() == Qt.LeftButton:
                if not self.lineClosed:
                    if not self.capturing:
                        self.startCapturing()
                    self.addEndingVertex(event.pos())
            elif event.button() == Qt.RightButton:
                self.finishOperation()

        self.movingVertex = -1
        self.movingSegm = -1
        self.movingLineInitialPoint = None
        self.redrawActions()

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.stopCapturing()
        if event.key() == Qt.Key_Backspace or event.key() == Qt.Key_Delete:
            self.removeLastVertex()
        if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
            self.finishOperation()

        event.accept()
        self.redrawActions()

    def finishOperation(self):
        self.doSplit()
        self.stopCapturing()
        self.initialize()
        self.startCapturing()

    def doSplit(self):
        if self.capturedPoints != None:
            self.layer.splitFeatures(self.capturedPoints,
                                     self.proj.topologicalEditing())

    def startCapturing(self):
        self.prepareRubberBand()
        self.prepareTempRubberBand()

        self.drawingLine = True
        self.capturing = True

        self.redrawActions()

    def prepareRubberBand(self):
        color = QColor("red")
        color.setAlphaF(0.78)

        self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.rubberBand.setWidth(1)
        self.rubberBand.setColor(color)
        self.rubberBand.show()

    def prepareTempRubberBand(self):
        color = QColor("red")
        color.setAlphaF(0.78)

        self.tempRubberBand = QgsRubberBand(self.canvas,
                                            QgsWkbTypes.LineGeometry)
        self.tempRubberBand.setWidth(1)
        self.tempRubberBand.setColor(color)
        self.tempRubberBand.setLineStyle(Qt.DotLine)
        self.tempRubberBand.show()

    def redrawRubberBand(self):
        self.canvas.scene().removeItem(self.rubberBand)
        self.prepareRubberBand()
        for i in range(len(self.capturedPoints)):
            point = self.capturedPoints[i]
            if point.__class__ == QgsPoint:
                vertexCoord = self.toMapCoordinatesV2(self.layer,
                                                      self.capturedPoints[i])
                vertexCoord = QgsPointXY(vertexCoord.x(), vertexCoord.y())
            else:
                vertexCoord = self.toMapCoordinates(self.layer,
                                                    self.capturedPoints[i])

            self.rubberBand.addPoint(vertexCoord)

    def redrawTempRubberBand(self):
        if self.tempRubberBand != None:
            self.tempRubberBand.reset(QgsWkbTypes.LineGeometry)
            self.tempRubberBand.addPoint(
                self.toMapCoordinates(
                    self.layer,
                    self.capturedPoints[len(self.capturedPoints) - 1]))

    def stopCapturing(self):
        self.deleteLabels()
        self.deleteVertices()
        if self.rubberBand:
            self.canvas.scene().removeItem(self.rubberBand)
            self.rubberBand = None
        if self.tempRubberBand:
            self.canvas.scene().removeItem(self.tempRubberBand)
            self.tempRubberBand = None
        self.drawingLine = False
        self.movingVertices = False
        self.showingVertices = False
        self.capturing = False
        self.capturedPoints = []
        self.canvas.refresh()

        self.redrawActions()

    def addEndingVertex(self, canvasPoint):
        mapPoint = self.toMapCoordinates(canvasPoint)
        layerPoint = self.toLayerCoordinates(self.layer, canvasPoint)

        self.rubberBand.addPoint(mapPoint)
        self.capturedPoints.append(layerPoint)

        self.tempRubberBand.reset(QgsWkbTypes.LineGeometry)
        self.tempRubberBand.addPoint(mapPoint)

    def removeLastVertex(self):
        if not self.capturing: return

        rubberBandSize = self.rubberBand.numberOfVertices()
        tempRubberBandSize = self.tempRubberBand.numberOfVertices()
        numPoints = len(self.capturedPoints)

        if rubberBandSize < 1 or numPoints < 1:
            return

        self.rubberBand.removePoint(-1)

        if rubberBandSize > 1:
            if tempRubberBandSize > 1:
                point = self.rubberBand.getPoint(0, rubberBandSize - 2)
                self.tempRubberBand.movePoint(tempRubberBandSize - 2, point)
        else:
            self.tempRubberBand.reset(self.bandType())

        del self.capturedPoints[-1]

    def addVertex(self, pos):
        newCapturedPoints = []
        for i in range(len(self.capturedPoints) - 1):
            newCapturedPoints.append(self.capturedPoints[i])
            vertex1 = self.toMapCoordinates(self.layer, self.capturedPoints[i])
            currentVertex1 = self.toCanvasCoordinates(
                QgsPointXY(vertex1.x(), vertex1.y()))
            vertex2 = self.toMapCoordinates(self.layer,
                                            self.capturedPoints[i + 1])
            currentVertex2 = self.toCanvasCoordinates(
                QgsPointXY(vertex2.x(), vertex2.y()))

            distance = self.distancePointLine(pos.x(), pos.y(),
                                              currentVertex1.x(),
                                              currentVertex1.y(),
                                              currentVertex2.x(),
                                              currentVertex2.y())
            if distance <= maxDistanceHitTest:
                layerPoint = self.toLayerCoordinates(self.layer, pos)
                newCapturedPoints.append(layerPoint)

        newCapturedPoints.append(self.capturedPoints[len(self.capturedPoints) -
                                                     1])
        self.capturedPoints = newCapturedPoints

        self.redrawRubberBand()
        self.redrawVertices()
        self.redrawAreas()
        self.redrawActions()

    def removeVertex(self, pos):
        deletedFirst = False
        deletedLast = False
        newCapturedPoints = []
        for i in range(len(self.capturedPoints)):
            vertex = self.toMapCoordinates(self.layer, self.capturedPoints[i])
            currentVertex = self.toCanvasCoordinates(
                QgsPointXY(vertex.x(), vertex.y()))
            if not self.distancePoint(pos,
                                      currentVertex) <= maxDistanceHitTest:
                newCapturedPoints.append(self.capturedPoints[i])
            elif i == 0:
                deletedFirst = True
            elif i == len(self.capturedPoints) - 1:
                deletedLast = True

        self.capturedPoints = newCapturedPoints

        if deletedFirst and deletedLast:
            self.lineClosed = False

        self.redrawRubberBand()
        self.redrawVertices()
        self.redrawAreas()
        self.redrawActions()

        if len(self.capturedPoints) <= 2:
            self.stopRemovingVertices()

    def startMovingVertices(self):
        self.stopMovingLine()
        self.stopAddingVertices()
        self.stopRemovingVertices()
        self.stopMovingSegment()

        self.actionMoveVertices.setChecked(True)
        self.movingVertices = True
        self.showingVertices = True
        self.drawingLine = False
        self.canvas.scene().removeItem(self.tempRubberBand)
        self.redrawVertices()
        self.redrawAreas()
        self.redrawActions()

    def stopMovingVertices(self):
        self.movingVertices = False
        self.actionMoveVertices.setChecked(False)
        self.restoreAction()

    def startAddingVertices(self):
        self.stopMovingVertices()
        self.stopRemovingVertices()
        self.stopMovingLine()
        self.stopMovingSegment()

        self.actionAddVertices.setChecked(True)
        self.addingVertices = True
        self.showingVertices = True
        self.drawingLine = False
        self.canvas.scene().removeItem(self.tempRubberBand)
        self.redrawVertices()
        self.redrawAreas()
        self.redrawActions()

    def stopAddingVertices(self):
        self.addVertices = False
        self.actionAddVertices.setChecked(False)
        self.restoreAction()

    def startRemovingVertices(self):
        self.stopMovingVertices()
        self.stopAddingVertices()
        self.stopMovingLine()
        self.stopMovingSegment()

        self.actionRemoveVertices.setChecked(True)
        self.removingVertices = True
        self.showingVertices = True
        self.drawingLine = False
        self.canvas.scene().removeItem(self.tempRubberBand)
        self.redrawVertices()
        self.redrawAreas()
        self.redrawActions()

    def stopRemovingVertices(self):
        self.removingVertices = False
        self.actionRemoveVertices.setChecked(False)
        self.restoreAction()

    def startMovingSegment(self):
        self.stopMovingVertices()
        self.stopMovingLine()
        self.stopAddingVertices()
        self.stopRemovingVertices()

        self.actionMoveSegment.setChecked(True)
        self.movingSegment = True
        self.showingVertices = False
        self.drawingLine = False
        self.canvas.scene().removeItem(self.tempRubberBand)
        self.redrawVertices()
        self.redrawAreas()
        self.redrawActions()

    def stopMovingSegment(self):
        self.movingSegment = False
        self.actionMoveSegment.setChecked(False)
        self.restoreAction()

    def startMovingLine(self):
        self.stopMovingVertices()
        self.stopAddingVertices()
        self.stopRemovingVertices()
        self.stopMovingSegment()

        self.actionMoveLine.setChecked(True)
        self.movingLine = True
        self.showingVertices = False
        self.drawingLine = False
        self.canvas.scene().removeItem(self.tempRubberBand)
        self.redrawAreas()
        self.redrawActions()

    def stopMovingLine(self):
        self.actionMoveLine.setChecked(False)
        self.restoreAction()

    def lineClose(self):
        self.lineClosed = True
        self.capturedPoints.append(self.capturedPoints[0])
        self.redrawRubberBand()
        self.redrawTempRubberBand()
        self.redrawAreas()
        self.redrawActions()

    def lineOpen(self):
        self.lineClosed = False
        del self.capturedPoints[-1]
        self.redrawRubberBand()
        self.redrawTempRubberBand()
        self.redrawAreas()
        self.redrawActions()

    def showVertices(self):
        for i in range(len(self.capturedPoints)):
            vertexc = self.toMapCoordinates(self.layer, self.capturedPoints[i])
            vertexCoords = self.toCanvasCoordinates(
                QgsPointXY(vertexc.x(), vertexc.y()))
            if i == self.movingVertex:
                vertex = self.scene.addRect(vertexCoords.x() - 5,
                                            vertexCoords.y() - 5, 10, 10,
                                            QPen(QColor("green")),
                                            QBrush(QColor("green")))
                self.vertices.append(vertex)
            elif i == len(self.capturedPoints
                          ) - 1 and self.movingVertex == 0 and self.lineClosed:
                vertex = self.scene.addRect(vertexCoords.x() - 5,
                                            vertexCoords.y() - 5, 10, 10,
                                            QPen(QColor("green")),
                                            QBrush(QColor("green")))
                self.vertices.append(vertex)
            else:
                vertex = self.scene.addRect(vertexCoords.x() - 4,
                                            vertexCoords.y() - 4, 8, 8,
                                            QPen(QColor("red")),
                                            QBrush(QColor("red")))
                self.vertices.append(vertex)

    def deleteVertices(self):
        for i in range(len(self.vertices)):
            self.scene.removeItem(self.vertices[i])
        self.vertices = []

    def lineMagnitude(self, x1, y1, x2, y2):
        return sqrt(pow((x2 - x1), 2) + pow((y2 - y1), 2))

    def distancePointLine(self, px, py, x1, y1, x2, y2):
        magnitude = self.lineMagnitude(x1, y1, x2, y2)

        if magnitude < 0.00000001:
            distance = 9999
            return distance

        u1 = (((px - x1) * (x2 - x1)) + ((py - y1) * (y2 - y1)))
        u = u1 / (magnitude * magnitude)

        if (u < 0.00001) or (u > 1):
            ix = self.lineMagnitude(px, py, x1, y1)
            iy = self.lineMagnitude(px, py, x2, y2)
            if ix > iy:
                distance = iy
            else:
                distance = ix
        else:
            ix = x1 + u * (x2 - x1)
            iy = y1 + u * (y2 - y1)
            distance = self.lineMagnitude(px, py, ix, iy)

        return distance

    def redrawVertices(self):
        self.deleteVertices()
        self.showVertices()

    def redrawActions(self):
        self.redrawActionMoveVertices()
        self.redrawActionAddVertices()
        self.redrawActionRemoveVertices()
        self.redrawActionMoveSegment()
        self.redrawActionLineClose()
        self.redrawActionLineOpen()
        self.redrawActionMoveLine()

    def redrawActionMoveVertices(self):
        self.actionMoveVertices.setEnabled(False)
        if len(self.capturedPoints) > 0:
            self.actionMoveVertices.setEnabled(True)

    def redrawActionAddVertices(self):
        self.actionAddVertices.setEnabled(False)
        if len(self.capturedPoints) >= 2:
            self.actionAddVertices.setEnabled(True)

    def redrawActionRemoveVertices(self):
        self.actionRemoveVertices.setEnabled(False)
        if len(self.capturedPoints) > 2:
            self.actionRemoveVertices.setEnabled(True)

    def redrawActionMoveSegment(self):
        self.actionMoveSegment.setEnabled(False)
        if len(self.capturedPoints) > 2:
            self.actionMoveSegment.setEnabled(True)

    def redrawActionLineClose(self):
        self.actionLineClose.setEnabled(False)
        if not self.lineClosed and len(self.capturedPoints) >= 3:
            self.actionLineClose.setEnabled(True)

    def redrawActionLineOpen(self):
        self.actionLineOpen.setEnabled(False)
        if self.lineClosed:
            self.actionLineOpen.setEnabled(True)

    def redrawActionMoveLine(self):
        self.actionMoveLine.setEnabled(False)
        if len(self.capturedPoints) > 0:
            self.actionMoveLine.setEnabled(True)
Example #18
0
class GeodesicMeasureDialog(QDialog, FORM_CLASS):
    def __init__(self, iface, parent):
        super(GeodesicMeasureDialog, self).__init__(parent)
        self.setupUi(self)
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.pointDigitizerDialog = AddMeasurePointWidget(self, iface, parent)
        qset = QSettings()

        self.manualEntryButton.setIcon(
            QIcon(os.path.dirname(__file__) + "/images/manualpoint.png"))
        self.manualEntryButton.clicked.connect(self.showManualEntryDialog)

        self.restoreGeometry(
            qset.value("ShapeTools/MeasureDialogGeometry",
                       QByteArray(),
                       type=QByteArray))
        self.closeButton.clicked.connect(self.closeDialog)
        self.newButton.clicked.connect(self.newDialog)
        self.saveToLayerButton.clicked.connect(self.saveToLayer)
        self.saveToLayerButton.setEnabled(False)

        self.unitsComboBox.addItems(DISTANCE_LABELS)

        self.tableWidget.setColumnCount(3)
        self.tableWidget.setSortingEnabled(False)
        self.tableWidget.setHorizontalHeaderLabels(
            [tr('Heading To'),
             tr('Heading From'),
             tr('Distance')])

        self.unitsComboBox.activated.connect(self.unitsChanged)

        self.capturedPoints = []
        self.distances = []
        self.activeMeasuring = True
        self.lastMotionPt = None
        self.unitsChanged()
        self.currentDistance = 0.0

        self.pointRb = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry)
        self.pointRb.setColor(settings.rubberBandColor)
        self.pointRb.setIconSize(10)
        self.lineRb = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.lineRb.setColor(settings.rubberBandColor)
        self.lineRb.setWidth(3)
        self.tempRb = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.tempRb.setColor(settings.rubberBandColor)
        self.tempRb.setWidth(3)

    def showManualEntryDialog(self):
        self.pointDigitizerDialog.show()

    def ready(self):
        return self.activeMeasuring

    def stop(self):
        self.activeMeasuring = False
        self.lastMotionPt = None

    def closeEvent(self, event):
        self.closeDialog()

    def closeDialog(self):
        self.clear()
        QSettings().setValue("ShapeTools/MeasureDialogGeometry",
                             self.saveGeometry())
        self.close()
        self.pointDigitizerDialog.closeDialog()

    def newDialog(self):
        self.clear()
        self.initGeodLabel()

    def initGeodLabel(self):
        label = tr('Ellipsoid: ') + settings.ellipseDescription
        self.geodLabel.setText(label)

    def keyPressed(self, key):
        index = len(self.capturedPoints)
        if index <= 0:
            return
        if key == Qt.Key_Escape:
            self.endRubberband()
        if self.motionReady():
            if self.lastMotionPt is None:
                return
            (distance, startAngle,
             endAngle) = self.calcParameters(self.capturedPoints[index - 1],
                                             self.lastMotionPt)
        else:
            if index < 2:
                return
            (distance, startAngle,
             endAngle) = self.calcParameters(self.capturedPoints[index - 2],
                                             self.capturedPoints[index - 1])

        distance = self.unitDistance(distance)
        clipboard = QApplication.clipboard()
        if key == Qt.Key_1 or key == Qt.Key_F:
            s = '{:.{prec}f}'.format(startAngle,
                                     prec=settings.measureSignificantDigits)
            clipboard.setText(s)
            self.iface.messageBar().pushMessage(
                "",
                "Heading to {} copied to the clipboard".format(s),
                level=Qgis.Info,
                duration=3)
        elif key == Qt.Key_2 or key == Qt.Key_T:
            s = '{:.{prec}f}'.format(endAngle,
                                     prec=settings.measureSignificantDigits)
            clipboard.setText(s)
            self.iface.messageBar().pushMessage(
                "",
                "Heading from {} copied to the clipboard".format(s),
                level=Qgis.Info,
                duration=3)
        elif key == Qt.Key_3 or key == Qt.Key_D:
            s = '{:.{prec}f}'.format(distance,
                                     prec=settings.measureSignificantDigits)
            clipboard.setText(s)
            self.iface.messageBar().pushMessage(
                "",
                "Distance {} copied to the clipboard".format(s),
                level=Qgis.Info,
                duration=3)
        elif key == Qt.Key_4 or key == Qt.Key_A:
            total = 0.0
            num = len(self.capturedPoints)
            for i in range(1, num):
                (d, startA,
                 endA) = self.calcParameters(self.capturedPoints[i - 1],
                                             self.capturedPoints[i])
                total += d
            total = self.unitDistance(total)
            # Add in the motion distance
            if self.motionReady():
                total += distance
            s = '{:.{prec}f}'.format(total,
                                     prec=settings.measureSignificantDigits)
            clipboard.setText(s)
            self.iface.messageBar().pushMessage(
                "",
                "Total distance {} copied to the clipboard".format(s),
                level=Qgis.Info,
                duration=3)
        else:
            return

    def unitsChanged(self):
        label = "Distance [{}]".format(
            DISTANCE_LABELS[self.unitsComboBox.currentIndex()])
        item = QTableWidgetItem(label)
        self.tableWidget.setHorizontalHeaderItem(2, item)
        ptcnt = len(self.capturedPoints)
        if ptcnt >= 2:
            i = 0
            while i < ptcnt - 1:
                item = QTableWidgetItem('{:.4f}'.format(
                    self.unitDistance(self.distances[i])))
                self.tableWidget.setItem(i, 2, item)
                i += 1
            self.formatTotal()

    def motionReady(self):
        if len(self.capturedPoints) > 0 and self.activeMeasuring:
            return True
        return False

    def addPoint(self, pt, button):
        self.currentDistance = 0
        index = len(self.capturedPoints)
        if index > 0 and pt == self.capturedPoints[index - 1]:
            # the clicked point is the same as the previous so just ignore it
            return
        self.capturedPoints.append(pt)
        # Add rubber band points
        canvasCrs = self.canvas.mapSettings().destinationCrs()
        transform = QgsCoordinateTransform(epsg4326, canvasCrs,
                                           QgsProject.instance())
        ptCanvas = transform.transform(pt.x(), pt.y())
        self.pointRb.addPoint(ptCanvas, True)
        # If there is more than 1 captured point add it to the table
        if index > 0:
            self.saveToLayerButton.setEnabled(True)
            (distance, startAngle,
             endAngle) = self.calcParameters(self.capturedPoints[index - 1],
                                             self.capturedPoints[index])
            self.distances.append(distance)
            self.insertParams(index, distance, startAngle, endAngle)
            # Add Rubber Band Line
            linePts = self.getLinePts(distance, self.capturedPoints[index - 1],
                                      self.capturedPoints[index])
            self.lineRb.addGeometry(QgsGeometry.fromPolylineXY(linePts), None)
        self.formatTotal()

    def endRubberband(self):
        index = len(self.capturedPoints)
        if index <= 0:
            return
        if index == 1:
            self.newDialog()
            return
        if self.motionReady():
            if self.lastMotionPt is not None:
                self.lastMotionPt = None
                self.tempRb.reset(QgsWkbTypes.LineGeometry)
                self.tableWidget.setRowCount(self.tableWidget.rowCount() - 1)
        self.stop()
        self.currentDistance = 0
        self.formatTotal()

    def inMotion(self, pt):
        index = len(self.capturedPoints)
        if index <= 0:
            return
        (self.currentDistance, startAngle,
         endAngle) = self.calcParameters(self.capturedPoints[index - 1], pt)
        self.insertParams(index, self.currentDistance, startAngle, endAngle)
        self.formatTotal()
        linePts = self.getLinePts(self.currentDistance,
                                  self.capturedPoints[index - 1], pt)
        self.lastMotionPt = pt
        self.tempRb.setToGeometry(QgsGeometry.fromPolylineXY(linePts), None)

    def calcParameters(self, pt1, pt2):
        gline = geod.Inverse(pt1.y(), pt1.x(), pt2.y(), pt2.x())
        az2 = (gline['azi2'] + 180) % 360.0
        if az2 > 180:
            az2 = az2 - 360.0
        az1 = gline['azi1']

        # Check to see if the azimuth values should be in the range or 0 to 360
        # The default is -180 to 180
        if settings.mtAzMode:
            if az1 < 0:
                az1 += 360.0
            if az2 < 0:
                az2 += 360
        return (gline['s12'], az1, az2)

    def getLinePts(self, distance, pt1, pt2):
        canvasCrs = self.canvas.mapSettings().destinationCrs()
        transform = QgsCoordinateTransform(epsg4326, canvasCrs,
                                           QgsProject.instance())
        pt1c = transform.transform(pt1.x(), pt1.y())
        pt2c = transform.transform(pt2.x(), pt2.y())
        if distance < 10000:
            return [pt1c, pt2c]
        gline = geod.InverseLine(pt1.y(), pt1.x(), pt2.y(), pt2.x())
        n = int(math.ceil(distance / 10000.0))
        if n > 20:
            n = 20
        seglen = distance / n
        pts = [pt1c]
        for i in range(1, n):
            s = seglen * i
            g = gline.Position(
                s,
                Geodesic.LATITUDE | Geodesic.LONGITUDE | Geodesic.LONG_UNROLL)
            ptc = transform.transform(g['lon2'], g['lat2'])
            pts.append(ptc)
        pts.append(pt2c)
        return pts

    def saveToLayer(self):
        units = self.unitDesignator()
        canvasCrs = self.canvas.mapSettings().destinationCrs()
        fields = QgsFields()
        fields.append(QgsField("label", QVariant.String))
        fields.append(QgsField("value", QVariant.Double))
        fields.append(QgsField("units", QVariant.String))
        fields.append(QgsField("heading_to", QVariant.Double))
        fields.append(QgsField("heading_from", QVariant.Double))
        fields.append(QgsField("total_dist", QVariant.Double))

        layer = QgsVectorLayer("LineString?crs={}".format(canvasCrs.authid()),
                               "Measurements", "memory")
        dp = layer.dataProvider()
        dp.addAttributes(fields)
        layer.updateFields()

        num = len(self.capturedPoints)
        total = 0.0
        for i in range(1, num):
            (distance, startA,
             endA) = self.calcParameters(self.capturedPoints[i - 1],
                                         self.capturedPoints[i])
            total += distance
        total = self.unitDistance(total)
        for i in range(1, num):
            (distance, startA,
             endA) = self.calcParameters(self.capturedPoints[i - 1],
                                         self.capturedPoints[i])
            pts = self.getLinePts(distance, self.capturedPoints[i - 1],
                                  self.capturedPoints[i])
            distance = self.unitDistance(distance)
            feat = QgsFeature(layer.fields())
            feat.setAttribute(
                0, "{:.{prec}f} {}".format(
                    distance,
                    units,
                    prec=settings.saveToLayerSignificantDigits))
            feat.setAttribute(1, distance)
            feat.setAttribute(2, units)
            feat.setAttribute(3, startA)
            feat.setAttribute(4, endA)
            feat.setAttribute(5, total)
            feat.setGeometry(QgsGeometry.fromPolylineXY(pts))
            dp.addFeatures([feat])

        label = QgsPalLayerSettings()
        label.fieldName = 'label'
        try:
            label.placement = QgsPalLayerSettings.Line
        except Exception:
            label.placement = QgsPalLayerSettings.AboveLine
        format = label.format()
        format.setColor(settings.measureTextColor)
        format.setNamedStyle('Bold')
        label.setFormat(format)
        labeling = QgsVectorLayerSimpleLabeling(label)
        layer.setLabeling(labeling)
        layer.setLabelsEnabled(True)
        renderer = layer.renderer()
        renderer.symbol().setColor(settings.measureLineColor)
        renderer.symbol().setWidth(0.5)

        layer.updateExtents()
        QgsProject.instance().addMapLayer(layer)

    def insertParams(self, position, distance, startAngle, endAngle):
        if position > self.tableWidget.rowCount():
            self.tableWidget.insertRow(position - 1)
        item = QTableWidgetItem('{:.4f}'.format(self.unitDistance(distance)))
        item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        self.tableWidget.setItem(position - 1, 2, item)
        item = QTableWidgetItem('{:.4f}'.format(startAngle))
        item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        self.tableWidget.setItem(position - 1, 0, item)
        item = QTableWidgetItem('{:.4f}'.format(endAngle))
        item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        self.tableWidget.setItem(position - 1, 1, item)

    def formatTotal(self):
        total = self.currentDistance
        ptcnt = len(self.capturedPoints)
        if ptcnt >= 2:
            i = 0
            while i < ptcnt - 1:
                total += self.distances[i]
                i += 1
        self.distanceLineEdit.setText('{:.2f}'.format(
            self.unitDistance(total)))

    def updateRBColor(self):
        self.pointRb.setColor(settings.rubberBandColor)
        self.lineRb.setColor(settings.rubberBandColor)
        self.tempRb.setColor(settings.rubberBandColor)

    def clear(self):
        self.tableWidget.setRowCount(0)
        self.capturedPoints = []
        self.distances = []
        self.activeMeasuring = True
        self.currentDistance = 0.0
        self.distanceLineEdit.setText('')
        self.pointRb.reset(QgsWkbTypes.PointGeometry)
        self.lineRb.reset(QgsWkbTypes.LineGeometry)
        self.tempRb.reset(QgsWkbTypes.LineGeometry)
        self.saveToLayerButton.setEnabled(False)
        self.updateRBColor()

    def unitDistance(self, distance):
        units = self.unitsComboBox.currentIndex()
        if units == 0:  # kilometers
            return distance / 1000.0
        elif units == 1:  # meters
            return distance
        elif units == 2:  # centimeters
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceCentimeters)
        elif units == 3:  # miles
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceMiles)
        elif units == 4:  # yards
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceYards)
        elif units == 5:  # feet
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceFeet)
        elif units == 6:  # inches
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceFeet) * 12
        elif units == 7:  # nautical miles
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters,
                QgsUnitTypes.DistanceNauticalMiles)

    def unitDesignator(self):
        units = self.unitsComboBox.currentIndex()
        return unitsAbbr[units]
class SimpleIntersectionMapTool(QgsMapTool):
    def __init__(self, iface):
        self.iface = iface
        self.mapCanvas = iface.mapCanvas()
        QgsMapTool.__init__(self, self.mapCanvas)
        self.settings = MySettings()
        self.rubber = QgsRubberBand(self.mapCanvas, QGis.Point)

    def deactivate(self):
        self.rubber.reset()
        QgsMapTool.deactivate(self)

    def activate(self):
        QgsMapTool.activate(self)
        self.rubber.setWidth(self.settings.value("rubberWidth"))
        self.rubber.setColor(self.settings.value("rubberColor"))
        self.checkLayer()

    def canvasMoveEvent(self, mouseEvent):
        # put the observations within tolerance in the rubber band
        self.rubber.reset(QGis.Point)
        match = self.snap_to_intersection(mouseEvent.pos())
        if match.type() == QgsPointLocator.Vertex and match.layer() is None:
            self.rubber.addPoint(match.point())

    def canvasPressEvent(self, mouseEvent):
        self.rubber.reset()
        match = self.snap_to_intersection(mouseEvent.pos())
        if match.type() != QgsPointLocator.Vertex or match.layer() is not None:
            return

        layer = self.checkLayer()
        if layer is None:
            return
        f = QgsFeature()
        initFields = layer.dataProvider().fields()
        f.setFields(initFields)
        f.initAttributes(initFields.size())
        f.setGeometry(QgsGeometry().fromPoint(match.point()))
        layer.editBuffer().addFeature(f)
        layer.triggerRepaint()

    def snap_to_intersection(self, pos):
        """ Temporarily override snapping config and snap to vertices and edges
         of any editable vector layer, to allow selection of node for editing
         (if snapped to edge, it would offer creation of a new vertex there).
        """
        map_point = self.toMapCoordinates(pos)
        tol = QgsTolerance.vertexSearchRadius(self.canvas().mapSettings())
        snap_type = QgsPointLocator.Type(QgsPointLocator.Edge)

        snap_layers = []
        for layer in self.canvas().layers():
            if not isinstance(layer, QgsVectorLayer):
                continue
            snap_layers.append(QgsSnappingUtils.LayerConfig(
                layer, snap_type, tol, QgsTolerance.ProjectUnits))

        snap_util = self.canvas().snappingUtils()
        old_layers = snap_util.layers()
        old_mode = snap_util.snapToMapMode()
        old_inter = snap_util.snapOnIntersections()
        snap_util.setLayers(snap_layers)
        snap_util.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced)
        snap_util.setSnapOnIntersections(True)
        m = snap_util.snapToMap(map_point)
        snap_util.setLayers(old_layers)
        snap_util.setSnapToMapMode(old_mode)
        snap_util.setSnapOnIntersections(old_inter)
        return m

    def checkLayer(self):
        # check output layer is defined
        layerid = self.settings.value("simpleIntersectionLayer")
        layer = QgsMapLayerRegistry.instance().mapLayer(layerid)
        if not self.settings.value("simpleIntersectionWritePoint") or layer is None:
            self.iface.messageBar().pushMessage("Intersect It",
                                                "You must define an output layer for simple intersections",
                                                QgsMessageBar.WARNING, 3)
            self.mapCanvas.unsetMapTool(self)
            return None
        if not layer.isEditable():
            self.iface.messageBar().pushMessage("Intersect It",
                                                "The output layer <b>%s must be editable</b>" % layer.name(),
                                                QgsMessageBar.WARNING, 3)
            self.mapCanvas.unsetMapTool(self)
            return None
        return layer
Example #20
0
class DrawRect(QgsMapTool):
    '''Classe de sélection avec un Rectangle'''

    selectionDone = pyqtSignal()
    move = pyqtSignal()

    def __init__(self, iface, couleur):
        self.canvas = iface.mapCanvas()
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.iface = iface
        self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)
        self.rb.setColor(couleur)
        self.reset()
        return None

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rb.reset(True)  # true, its a polygon

    def canvasPressEvent(self, e):
        if not e.button() == Qt.LeftButton:
            return
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False
        if not e.button() == Qt.LeftButton:
            return None
        if self.rb.numberOfVertices() > 3:
            self.selectionDone.emit()
        else:
            width, height, ok = RectangleDialog().getSize()
            if width > 0 and height > 0 and ok:
                self.rb.addPoint(
                    QgsPointXY(self.startPoint.x() + width,
                               self.startPoint.y() - height))
                self.showRect(
                    self.startPoint,
                    QgsPointXY(self.startPoint.x() + width,
                               self.startPoint.y() - height))
                self.selectionDone.emit()

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return
        self.move.emit()
        self.endPoint = self.toMapCoordinates(e.pos())
        self.showRect(self.startPoint, self.endPoint)

    def showRect(self, startPoint, endPoint):
        self.rb.reset(QgsWkbTypes.PolygonGeometry)  # true, it's a polygon
        if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
            return

        point1 = QgsPointXY(startPoint.x(), startPoint.y())
        point2 = QgsPointXY(startPoint.x(), endPoint.y())
        point3 = QgsPointXY(endPoint.x(), endPoint.y())
        point4 = QgsPointXY(endPoint.x(), startPoint.y())

        self.rb.addPoint(point1, False)
        self.rb.addPoint(point2, False)
        self.rb.addPoint(point3, False)
        self.rb.addPoint(point4, True)  # true to update canvas
        self.rb.show()

    def deactivate(self):
        self.rb.reset(True)
        QgsMapTool.deactivate(self)
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
        #create reference to map.Canvas
        self.canvas = self.iface.mapCanvas()

        # initialize plugins directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        #Initialize QgsMapToolEmitPoint class, and pass map canvas where we will emit the point
        self.addPipelinePoint = QgsMapToolEmitPoint(self.canvas)
        #create instance of rubberband class
        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')

        #create instance of results dialog
        self.dlg = PipelinePlannerDialog()

        # 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

        #connect to mapCanvas click event
        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"""
        # set the canvas maptool
        self.canvas.setMapTool(self.addPipelinePoint)

    #method to control drawning proces
    def evaluatePipeline(self, point, button):
        if button == Qt.LeftButton:
            self.rbPipeline.addPoint(point)
            self.rbPipeline.show()
        elif button == Qt.RightButton:
            pipeline = self.rbPipeline.asGeometry()
            #             QMessageBox.information(None, "Pipeline", pipeline.asWkt())
            self.dlg.tblImpacts.setRowCount(0)
            #create reference to raptor_buffer layer

            lyrRaptor = QgsProject.instance().mapLayersByName(
                "Raptor Buffer")[0]

            raptors = lyrRaptor.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())
                row = self.dlg.tblImpacts.rowCount()
                if raptor.geometry().intersects(pipeline):
                    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 #22
0
class ShapeTool(QgsMapTool):
    #signal emitted when the mouse is clicked. This indicates that the tool finished its job
    toolFinished = pyqtSignal()
    def __init__(self, canvas, geometryType, param, type, color = QColor( 254, 178, 76, 63 )):
        '''
        Constructor
        '''
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.active = False
        self.geometryType=geometryType
        self.param=param
        self.type=type       
        self.cursor=None
        self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon)    
        self.setColor(color)
        self.reset()
        
    def setColor(self, mFillColor):
        '''
        Adjusting the color to create the rubber band
        '''
    
        self.rubberBand.setColor(mFillColor)
        self.rubberBand.setWidth(1)
    
    def reset(self):
        '''
        Resetting the rubber band
        '''
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        try:
            self.rubberBand.reset(QGis.Polygon)
        except:
            pass

    def canvasPressEvent(self, e):
        '''
        When the canvas is pressed the tool finishes its job
        '''
        self.canvas.unsetMapTool(self)
        self.toolFinished.emit()

    def canvasMoveEvent(self, e):
        '''
        Deals with mouse move event to update the rubber band position in the canvas
        '''
        self.endPoint = self.toMapCoordinates( e.pos() )
        if self.geometryType == self.tr(u"Circle"):
            self.showCircle(self.endPoint)
        elif self.geometryType == self.tr(u"Square"):
            self.showRect(self.endPoint, sqrt(self.param)/2)

    def showCircle(self, startPoint):
        '''
        Draws a circle in the canvas
        '''
        nPoints = 50
        x = startPoint.x()
        y = startPoint.y()
        if self.type == self.tr('distance'):
            r = self.param
            self.rubberBand.reset(QGis.Polygon)
            for itheta in range(nPoints+1):
                theta = itheta*(2.0*pi/nPoints)
                self.rubberBand.addPoint(QgsPoint(x+r*cos(theta), y+r*sin(theta)))
            self.rubberBand.show()
        else:
            r = sqrt(self.param/pi)
            self.rubberBand.reset(QGis.Polygon)
            for itheta in range(nPoints+1):
                theta = itheta*(2.0*pi/nPoints)
                self.rubberBand.addPoint(QgsPoint(x+r*cos(theta), y+r*sin(theta)))
            self.rubberBand.show()

    def showRect(self, startPoint, param):   
        '''
        Draws a rectangle in the canvas
        '''  
        self.rubberBand.reset(QGis.Polygon)
        x = startPoint.x()
        y = startPoint.y()
        point1 = QgsPoint(x - param, y - param)
        point2 = QgsPoint(x - param, y + param)
        point3 = QgsPoint(x + param, y + param)
        point4 = QgsPoint(x + param, y - param)
        self.rubberBand.addPoint(point1, False)
        self.rubberBand.addPoint(point2, False)
        self.rubberBand.addPoint(point3, False)
        self.rubberBand.addPoint(point4, True)
        self.rubberBand.show()
    
    def deactivate(self):
        '''
        Deactivates the tool and hides the rubber band
        '''
        self.rubberBand.hide()
        QgsMapTool.deactivate(self)
        
    def activate(self):
        '''
        Activates the tool
        '''
        QgsMapTool.activate(self)
    
    def reproject(self, geom, canvasCrs):
        '''
        Reprojects geom from the canvas crs to the reference crs
        geom: geometry to be reprojected
        canvasCrs: canvas crs (from crs)
        '''
        destCrs = self.reference.crs()
        if canvasCrs.authid() != destCrs.authid():
            coordinateTransformer = QgsCoordinateTransform(canvasCrs, destCrs)
            geom.transform(coordinateTransformer)
Example #23
0
class MapWidget(Ui_CanvasWidget, QMainWindow):
    def __init__(self, parent=None):
        super(MapWidget, self).__init__(parent)
        self.setupUi(self)
        self.snapping = True

        icon = roam_style.iconsize()
        self.projecttoolbar.setIconSize(QSize(icon, icon))

        self.defaultextent = None
        self.current_form = None
        self.last_form = None
        self.layerbuttons = []
        self.editfeaturestack = []
        self.lastgpsposition = None
        self.project = None
        self.gps = None
        self.gpslogging = None
        self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas))

        self.bridge = QgsLayerTreeMapCanvasBridge(
            QgsProject.instance().layerTreeRoot(), self.canvas)
        self.bridge.setAutoSetupOnFirstLayer(False)

        self.canvas.setCanvasColor(Qt.white)
        self.canvas.enableAntiAliasing(True)

        self.snappingutils = SnappingUtils(self.canvas, self)
        self.canvas.setSnappingUtils(self.snappingutils)

        threadcount = QThread.idealThreadCount()
        threadcount = 2 if threadcount > 2 else 1
        QgsApplication.setMaxThreads(threadcount)
        self.canvas.setParallelRenderingEnabled(True)

        self.canvas.setFrameStyle(QFrame.NoFrame)

        self.editgroup = QActionGroup(self)
        self.editgroup.setExclusive(True)
        self.editgroup.addAction(self.actionPan)
        self.editgroup.addAction(self.actionZoom_In)
        self.editgroup.addAction(self.actionZoom_Out)
        self.editgroup.addAction(self.actionInfo)

        self.actionGPS = GPSAction(self.canvas, self)
        self.projecttoolbar.addAction(self.actionGPS)

        if roam.config.settings.get('north_arrow', False):
            self.northarrow = NorthArrow(":/icons/north", self.canvas)
            self.northarrow.setPos(10, 10)
            self.canvas.scene().addItem(self.northarrow)

        smallmode = roam.config.settings.get("smallmode", False)
        self.projecttoolbar.setSmallMode(smallmode)

        self.projecttoolbar.setContextMenuPolicy(Qt.CustomContextMenu)

        gpsspacewidget = QWidget()
        gpsspacewidget.setMinimumWidth(30)
        gpsspacewidget.setSizePolicy(QSizePolicy.Expanding,
                                     QSizePolicy.Expanding)

        self.topspaceraction = self.projecttoolbar.insertWidget(
            self.actionGPS, gpsspacewidget)

        self.dataentryselection = QAction(self.projecttoolbar)
        self.dataentryaction = self.projecttoolbar.insertAction(
            self.topspaceraction, self.dataentryselection)
        self.dataentryselection.triggered.connect(self.select_data_entry)

        self.gpsMarker = GPSMarker(self.canvas)
        self.gpsMarker.hide()

        self.currentfeatureband = CurrentSelection(self.canvas)
        self.currentfeatureband.setIconSize(30)
        self.currentfeatureband.setWidth(10)
        self.currentfeatureband.setColor(QColor(88, 64, 173, 50))
        self.currentfeatureband.setOutlineColour(QColor(88, 64, 173))

        self.gpsband = QgsRubberBand(self.canvas)
        self.gpsband.setColor(QColor(165, 111, 212, 75))
        self.gpsband.setWidth(5)

        RoamEvents.refresh_map.connect(self.refresh_map)
        RoamEvents.editgeometry.connect(self.queue_feature_for_edit)
        RoamEvents.selectioncleared.connect(self.clear_selection)
        RoamEvents.selectionchanged.connect(self.highlight_selection)
        RoamEvents.openfeatureform.connect(self.feature_form_loaded)
        RoamEvents.sync_complete.connect(self.refresh_map)
        RoamEvents.snappingChanged.connect(self.snapping_changed)

        self.snappingbutton = QToolButton()
        self.snappingbutton.setText("Snapping: On")
        self.snappingbutton.setAutoRaise(True)
        self.snappingbutton.pressed.connect(self.toggle_snapping)

        spacer = QWidget()
        spacer2 = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)

        self.scalewidget = QgsScaleComboBox()

        self.scalebutton = QToolButton()
        self.scalebutton.setAutoRaise(True)
        self.scalebutton.setMaximumHeight(self.statusbar.height())
        self.scalebutton.pressed.connect(self.selectscale)
        self.scalebutton.setText("Scale")

        self.scalelist = BigList(parent=self.canvas,
                                 centeronparent=True,
                                 showsave=False)
        self.scalelist.hide()
        self.scalelist.setlabel("Map Scale")
        self.scalelist.setmodel(self.scalewidget.model())
        self.scalelist.closewidget.connect(self.scalelist.close)
        self.scalelist.itemselected.connect(self.update_scale_from_item)
        self.scalelist.itemselected.connect(self.scalelist.close)

        self.positionlabel = QLabel('')
        self.gpslabel = QLabel("GPS: Not active")
        self.gpslabelposition = QLabel("")
        self.gpslabelaveraging = QLabel('')  # averaging

        self.statusbar.addWidget(self.snappingbutton)
        self.statusbar.addWidget(spacer2)
        self.statusbar.addWidget(self.gpslabel)
        self.statusbar.addWidget(self.gpslabelposition)
        self.statusbar.addWidget(self.gpslabelaveraging)  # averaging
        self.statusbar.addPermanentWidget(self.scalebutton)

        self.canvas.extentsChanged.connect(self.update_status_label)
        self.canvas.scaleChanged.connect(self.update_status_label)

        self.connectButtons()

        scalebar_enabled = roam.config.settings.get('scale_bar', False)
        self.scalebar_enabled = False
        if scalebar_enabled:
            roam.utils.warning(
                "Unsupported feature: Scale bar support not ported to QGIS 3 API yet."
            )
            RoamEvents.raisemessage(
                "Unsupported feature",
                "Scale bar support not ported to QGIS 3 API yet",
                level=RoamEvents.CRITICAL)
            self.scalebar_enabled = False
            # self.scalebar = ScaleBarItem(self.canvas)
            # self.canvas.scene().addItem(self.scalebar)

    def clear_plugins(self) -> None:
        """
        Clear all the plugin added toolbars from the map interface.
        """
        toolbars = self.findChildren(QToolBar)
        for toolbar in toolbars:
            if toolbar.property("plugin_toolbar"):
                toolbar.unload()
                self.removeToolBar(toolbar)
                toolbar.deleteLater()

    def add_plugins(self, pluginnames) -> None:
        """
        Add the given plugins to to the mapping interface.

        Adds the toolbars the plugin exposes as new toolbars for the user.
        :param pluginnames: The names of the plugins to load.  Must already be loaded
                            by the plugin loader
        """
        for name in pluginnames:
            # Get the plugin
            try:
                plugin_mod = plugins.loaded_plugins[name]
            except KeyError:
                continue

            if not hasattr(plugin_mod, 'toolbars'):
                roam.utils.warning(
                    "No toolbars() function found in {}".format(name))
                continue

            toolbars = plugin_mod.toolbars()
            self.load_plugin_toolbars(toolbars)

    def load_plugin_toolbars(self, toolbars):
        """
        Load the plugin toolbars into the mapping interface.
        :param toolbars: The list of toolbars class objects to load.
        :return:
        """
        for ToolBarClass in toolbars:
            toolbar = ToolBarClass(plugins.api, self)
            self.addToolBar(Qt.BottomToolBarArea, toolbar)
            toolbar.setProperty("plugin_toolbar", True)

    def snapping_changed(self, snapping):
        """
        Called when the snapping settings have changed. Updates the label in the status bar.
        :param snapping:
        """
        self.snapping = snapping
        if snapping:
            self.snappingbutton.setText("Snapping: On")
        else:
            self.snappingbutton.setText("Snapping: Off")

    def toggle_snapping(self):
        """
        Toggle snapping on or off.
        """
        self.snapping = not self.snapping
        try:
            self.canvas.mapTool().toggle_snapping()
        except AttributeError:
            pass

        RoamEvents.snappingChanged.emit(self.snapping)

    def selectscale(self):
        """
        Show the select scale widget.
        :return:
        """
        self.scalelist.show()

    def update_scale_from_item(self, index):
        """
        Update the canvas scale from the selected scale item.
        :param index: The index of the selected item.
        """
        scale, _ = self.scalewidget.toDouble(index.data(Qt.DisplayRole))
        self.canvas.zoomScale(1.0 / scale)

    def update_gps_fixed_label(self, fixed, gpsinfo):
        if not fixed:
            self.gpslabel.setText("GPS: Acquiring fix")
            self.gpslabelposition.setText("")
            self.gpslabelaveraging.setText('')  # averaging

    quality_mappings = {
        0: "invalid",
        1: "GPS",
        2: "DGPS",
        3: "PPS",
        4: "Real Time Kinematic",
        5: "Float RTK",
        6: "Estimated",
        7: "Manual input mode",
        8: "Simulation mode"
    }

    def update_gps_label(self, position, gpsinfo):
        """
        Update the GPS label in the status bar with the GPS status.
        :param position: The current GPS position.
        :param gpsinfo: The current extra GPS information.
        """
        if not self.gps.connected:
            return

        fixtype = self.quality_mappings.get(gpsinfo.quality, "")
        self.gpslabel.setText(
            "DOP P:<b>{0:.2f}</b> H:<b>{1:.2f}</b> V:<b>{2:.2f}</b> "
            "Fix: <b>{3}</b> "
            "Sats: <b>{4}</b> ".format(gpsinfo.pdop, gpsinfo.hdop,
                                       gpsinfo.vdop, fixtype,
                                       gpsinfo.satellitesUsed))

        places = roam.config.settings.get("gpsplaces", 8)

        # if averaging, don't show this
        if not roam.config.settings.get('gps_averaging', True):
            self.gpslabelposition.setText("X: <b>{x:.{places}f}</b> "
                                          "Y: <b>{y:.{places}f}</b> "
                                          "Z: <b>{z}m</b> ".format(
                                              x=position.x(),
                                              y=position.y(),
                                              z=position.z(),
                                              places=places))
        else:
            self.gpslabelposition.setText('')
        # --- averaging -------------------------------------------------------
        # if turned on
        if roam.config.settings.get('gps_averaging', True):
            time = roam.config.settings.get('gps_averaging_start_time', '')
            # if currently happening
            if roam.config.settings.get('gps_averaging_in_action', True):
                time = datetime.now().replace(microsecond=0) - time.replace(
                    microsecond=0)
            count = roam.config.settings.get('gps_averaging_measurements', int)
            avglabel = 'AVG: <b>%s / %s</b>' % (time, count)
        else:
            avglabel = ''
        self.gpslabelaveraging.setText(avglabel)
        # ---------------------------------------------------------------------

    def gps_disconnected(self):
        self.gpslabel.setText("GPS: Not Active")
        self.gpslabelposition.setText("")
        self.gpslabelaveraging.setText("")
        self.gpsMarker.hide()

    def zoom_to_feature(self, feature):
        """
        Zoom to the given feature in the map.
        :param feature:
        :return:
        """
        box = feature.geometry().boundingBox()
        xmin, xmax, ymin, ymax = box.xMinimum(), box.xMaximum(), box.yMinimum(
        ), box.yMaximum()
        xmin -= 5
        xmax += 5
        ymin -= 5
        ymax += 5
        box = QgsRectangle(xmin, ymin, xmax, ymax)
        self.canvas.setExtent(box)
        self.canvas.refresh()

    def update_status_label(self, *args) -> None:
        """
        Update the status bar labels when the information has changed.
        """
        extent = self.canvas.extent()
        self.positionlabel.setText("Map Center: {}".format(
            extent.center().toString()))
        scale = 1.0 / self.canvas.scale()
        scale = self.scalewidget.toString(scale)
        self.scalebutton.setText(scale)

    def refresh_map(self) -> None:
        """
        Refresh the map
        """
        self.canvas.refresh()

    def updatescale(self) -> None:
        """
        Update the scale of the map with the current scale from the scale widget
        :return:
        """
        self.canvas.zoomScale(1.0 / self.scalewidget.scale())

    @property
    def crs(self) -> QgsCoordinateReferenceSystem:
        """
        Get the CRS used that is being used in the canvas
        :return: The QgsCoordinateReferenceSystem that is used by the canvas
        """
        return self.canvas.mapSettings().destinationCrs()

    def feature_form_loaded(self, form, feature, *args):
        """
        Called when the feature form is loaded.
        :param form: The Form object. Holds a reference to the forms layer.
        :param feature: The current capture feature
        """
        self.currentfeatureband.setToGeometry(feature.geometry(),
                                              form.QGISLayer)

    def highlight_selection(self, results):
        """
        Highlight the selection on the canvas.  This updates all selected objects based on the result set.
        :param results: A dict-of-list of layer-features.
        """
        self.clear_selection()
        for layer, features in results.items():
            band = self.selectionbands[layer]
            band.setColor(QColor(255, 0, 0))
            band.setIconSize(25)
            band.setWidth(5)
            band.setBrushStyle(Qt.NoBrush)
            band.reset(layer.geometryType())
            band.setZValue(self.currentfeatureband.zValue() - 1)
            for feature in features:
                band.addGeometry(feature.geometry(), layer)
        self.canvas.update()

    def highlight_active_selection(self, layer, feature, features):
        """
        Update the current active selected feature.
        :param layer: The layer of the active feature.
        :param feature: The active feature.
        :param features: The other features in the set to show as non active selection.
        :return:
        """
        self.clear_selection()
        self.highlight_selection({layer: features})
        self.currentfeatureband.setToGeometry(feature.geometry(), layer)
        self.canvas.update()

    def clear_selection(self):
        """
        Clear the selection from the canvas. Resets all selection rubber bands.
        :return:
        """
        # Clear the main selection rubber band
        self.canvas.scene().update()
        self.currentfeatureband.reset()
        # Clear the rest
        for band in self.selectionbands.values():
            band.reset()

        self.canvas.update()
        self.editfeaturestack = []

    def queue_feature_for_edit(self, form, feature):
        """
        Push a feature on the edit stack so the feature can have the geometry edited.
        :note: This is a big hack and I don't like it!
        :param form: The form for the current feature
        :param feature: The active feature.
        """
        def trigger_default_action():
            for action in self.projecttoolbar.actions():
                if action.property('dataentry') and action.isdefault:
                    action.trigger()
                    self.canvas.currentLayer().startEditing()
                    self.canvas.mapTool().setEditMode(True, feature.geometry(),
                                                      feature)
                    break

        self.editfeaturestack.append((form, feature))
        self.save_current_form()
        self.load_form(form)
        trigger_default_action()

    def save_current_form(self):
        self.last_form = self.current_form

    def restore_last_form(self):
        self.load_form(self.last_form)

    def clear_temp_objects(self):
        """
        Clear all temp objects from the canvas.
        :return:
        """
        def clear_tool_band():
            """
            Clear the rubber band of the active tool if it has one
            """
            tool = self.canvas.mapTool()
            if hasattr(tool, "clearBand"):
                tool.clearBand()

        self.currentfeatureband.reset()
        clear_tool_band()

    def settings_updated(self, settings):
        """
        Called when the settings have been updated in the Roam config.
        :param settings: A dict of the settings.
        """
        self.actionGPS.updateGPSPort()
        gpslogging = settings.get('gpslogging', True)
        if self.gpslogging:
            self.gpslogging.logging = gpslogging
        smallmode = settings.get("smallmode", False)
        self.projecttoolbar.setSmallMode(smallmode)

    def set_gps(self, gps, logging):
        """
        Set the GPS for the map widget.  Connects GPS signals
        """
        self.gps = gps
        self.gpslogging = logging
        self.gps.gpsfixed.connect(self.update_gps_fixed_label)
        self.gps.gpsposition.connect(self.update_gps_label)
        self.gps.gpsposition.connect(self.gps_update_canvas)
        self.gps.firstfix.connect(self.gps_first_fix)
        self.gps.gpsdisconnected.connect(self.gps_disconnected)

        self.gpsMarker.setgps(self.gps)
        self.actionGPS.setgps(gps)

    def gps_update_canvas(self, position, gpsinfo):
        """
        Updates the map canvas based on the GPS position.  By default if the GPS is outside the canvas
        extent the canvas will move to center on the GPS.  Can be turned off in settings.
        :param postion: The current GPS position.
        :param gpsinfo: The extra GPS information
        """
        # Recenter map if we go outside of the 95% of the area
        if self.gpslogging.logging:
            self.gpsband.addPoint(position)
            self.gpsband.show()

        if roam.config.settings.get('gpscenter', True):
            if not self.lastgpsposition == position:
                self.lastgpsposition = position.clone()
                rect = QgsRectangle(QgsPointXY(position), QgsPointXY(position))
                extentlimt = QgsRectangle(self.canvas.extent())
                extentlimt.scale(0.95)

                if not extentlimt.contains(QgsPointXY(position)):
                    self.zoom_to_location(position)

        self.gpsMarker.show()
        self.gpsMarker.setCenter(position, gpsinfo)

    def gps_first_fix(self, postion, gpsinfo):
        """
        Called the first time the GPS gets a fix.  If set this will zoom to the GPS after the first fix
        :param postion: The current GPS position.
        :param gpsinfo: The extra GPS information
        """
        zoomtolocation = roam.config.settings.get('gpszoomonfix', True)
        if zoomtolocation:
            self.canvas.zoomScale(1000)
            self.zoom_to_location(postion)

    def zoom_to_location(self, position):
        """
        Zoom to ta given position on the map..
        """
        rect = QgsRectangle(QgsPointXY(position), QgsPointXY(position))
        self.canvas.setExtent(rect)
        self.canvas.refresh()

    def select_data_entry(self):
        """
        Open the form selection widget to allow the user to pick the active capture form.
        """
        def showformerror(form):
            pass

        def actions():
            for form in self.project.forms:
                if not self.form_valid_for_capture(form):
                    continue

                action = form.createuiaction()
                valid, failreasons = form.valid
                if not valid:
                    roam.utils.warning("Form {} failed to load".format(
                        form.label))
                    roam.utils.warning("Reasons {}".format(failreasons))
                    action.triggered.connect(partial(showformerror, form))
                else:
                    action.triggered.connect(partial(self.load_form, form))
                yield action

        formpicker = PickActionDialog(msg="Select data entry form", wrap=5)
        formpicker.addactions(actions())
        formpicker.exec_()

    def project_loaded(self, project):
        """
        Called when the project is loaded. Main entry point for a loade project.
        :param project: The Roam project that has been loaded.
        """
        self.snappingutils.setConfig(QgsProject.instance().snappingConfig())
        self.project = project
        self.actionPan.trigger()
        firstform = self.first_capture_form()
        if firstform:
            self.load_form(firstform)
            self.dataentryselection.setVisible(True)
        else:
            self.dataentryselection.setVisible(False)

        # Enable the raster layers button only if the project contains a raster layer.
        layers = roam.api.utils.layers()
        hasrasters = any(layer.type() == QgsMapLayer.RasterLayer
                         for layer in layers)
        self.actionRaster.setEnabled(hasrasters)
        self.defaultextent = self.canvas.extent()
        roam.utils.info("Extent: {}".format(self.defaultextent.toString()))

        self.infoTool.selectionlayers = project.selectlayersmapping()

        self.canvas.refresh()

        projectscales, _ = QgsProject.instance().readBoolEntry(
            "Scales", "/useProjectScales")
        if projectscales:
            projectscales, _ = QgsProject.instance().readListEntry(
                "Scales", "/ScalesList")

            self.scalewidget.updateScales(projectscales)
        else:
            scales = [
                "1:50000", "1:25000", "1:10000", "1:5000", "1:2500", "1:1000",
                "1:500", "1:250", "1:200", "1:100"
            ]
            scales = roam.config.settings.get('scales', scales)
            self.scalewidget.updateScales(scales)

        if self.scalebar_enabled:
            self.scalebar.update()

        red = QgsProject.instance().readNumEntry("Gui", "/CanvasColorRedPart",
                                                 255)[0]
        green = QgsProject.instance().readNumEntry("Gui",
                                                   "/CanvasColorGreenPart",
                                                   255)[0]
        blue = QgsProject.instance().readNumEntry("Gui",
                                                  "/CanvasColorBluePart",
                                                  255)[0]
        myColor = QColor(red, green, blue)
        self.canvas.setCanvasColor(myColor)

        self.actionPan.toggle()
        self.clear_plugins()
        self.add_plugins(project.enabled_plugins)

    def setMapTool(self, tool, *args):
        """
        Set the active map tool in the canvas.
        :param tool: The QgsMapTool to set.
        """
        if tool == self.canvas.mapTool():
            return

        if hasattr(tool, "setSnapping"):
            tool.setSnapping(self.snapping)
        self.canvas.setMapTool(tool)

    def connectButtons(self):
        """
        Connect the default buttons in the interface. Zoom, pan, etc
        """
        def connectAction(action, tool):
            action.toggled.connect(partial(self.setMapTool, tool))

        def cursor(name):
            pix = QPixmap(name)
            pix = pix.scaled(QSize(24, 24))
            return QCursor(pix)

        self.zoomInTool = QgsMapToolZoom(self.canvas, False)
        self.zoomOutTool = QgsMapToolZoom(self.canvas, True)
        self.panTool = QgsMapToolPan(self.canvas)
        self.infoTool = InfoTool(self.canvas)

        self.infoTool.setAction(self.actionInfo)
        self.zoomInTool.setAction(self.actionZoom_In)
        self.zoomOutTool.setAction(self.actionZoom_Out)
        self.panTool.setAction(self.actionPan)

        connectAction(self.actionZoom_In, self.zoomInTool)
        connectAction(self.actionZoom_Out, self.zoomOutTool)
        connectAction(self.actionPan, self.panTool)
        connectAction(self.actionInfo, self.infoTool)

        self.zoomInTool.setCursor(cursor(':/icons/in'))
        self.zoomOutTool.setCursor(cursor(':/icons/out'))
        self.infoTool.setCursor(cursor(':/icons/select'))

        self.actionRaster.triggered.connect(self.toggle_raster_layers)
        self.actionHome.triggered.connect(self.homeview)

    def homeview(self):
        """
        Zoom the mapview canvas to the extents the project was opened at i.e. the
        default extent.
        """
        if self.defaultextent:
            self.canvas.setExtent(self.defaultextent)
            self.canvas.refresh()

    def form_valid_for_capture(self, form):
        """
        Check if the given form is valid for capture.
        :param form: The form to check.
        :return: True if valid form for capture
        """
        return form.has_geometry and self.project.layer_can_capture(
            form.QGISLayer)

    def first_capture_form(self):
        """
        Return the first valid form for capture.
        """
        for form in self.project.forms:
            if self.form_valid_for_capture(form):
                return form

    def load_form(self, form):
        """
        Load the given form so it's the active one for capture
        :param form: The form to load
        """
        self.clear_capture_tools()
        self.dataentryselection.setIcon(QIcon(form.icon))
        self.dataentryselection.setText(form.icontext)
        self.create_capture_buttons(form)
        self.current_form = form

    def create_capture_buttons(self, form):
        """
        Create the capture buttons in the toolbar for the given form.
        :param form: The active form.
        """
        tool = form.getMaptool()(self.canvas, form.settings)
        for action in tool.actions:
            # Create the action here.
            if action.ismaptool:
                action.toggled.connect(partial(self.setMapTool, tool))

            # Set the action as a data entry button so we can remove it later.
            action.setProperty("dataentry", True)
            self.editgroup.addAction(action)
            self.layerbuttons.append(action)
            self.projecttoolbar.insertAction(self.topspaceraction, action)
            action.setChecked(action.isdefault)

        if hasattr(tool, 'geometryComplete'):
            add = partial(self.add_new_feature, form)
            tool.geometryComplete.connect(add)
        else:
            tool.finished.connect(self.openForm)

        tool.error.connect(self.show_invalid_geometry_message)

    def show_invalid_geometry_message(self, message) -> None:
        """
        Shows the message to the user if the there is a invalid geometry capture.
        :param message: The message to show the user.
        """
        RoamEvents.raisemessage("Invalid geometry capture",
                                message,
                                level=RoamEvents.CRITICAL)
        if self.canvas.currentLayer() is not None:
            self.canvas.currentLayer().rollBack()
        RoamEvents.editgeometry_invalid.emit()

    def add_new_feature(self, form, geometry: QgsGeometry):
        """
        Add a new new feature to the given layer
        :param form:  The form to use for the new feature.
        :param geometry: The new geometry to create the feature for.
        """
        # NOTE This function is doing too much, acts as add and also edit.
        layer = form.QGISLayer
        if geometry.isMultipart():
            geometry.convertToMultiType()

        # Transform the new geometry back into the map layers geometry if it's needed
        transform = self.canvas.mapSettings().layerTransform(layer)
        if transform.isValid():
            geometry.transform(transform,
                               QgsCoordinateTransform.ReverseTransform)

        try:
            form, feature = self.editfeaturestack.pop()
            self.editfeaturegeometry(form, feature, newgeometry=geometry)
            return
        except IndexError:
            pass

        feature = form.new_feature(geometry=geometry)
        RoamEvents.load_feature_form(form, feature, editmode=False)

    def editfeaturegeometry(self, form, feature, newgeometry):
        # TODO Extract into function.
        layer = form.QGISLayer
        layer.startEditing()
        feature.setGeometry(newgeometry)
        layer.updateFeature(feature)
        saved = layer.commitChanges()
        if not saved:
            map(roam.utils.error, layer.commitErrors())
        self.canvas.refresh()
        self.currentfeatureband.setToGeometry(feature.geometry(), layer)
        RoamEvents.editgeometry_complete.emit(form, feature)
        self.canvas.mapTool().setEditMode(False, None, None)
        self.restore_last_form()

    def clear_capture_tools(self):
        """
        Clear the capture tools from the toolbar.
        :return: True if the capture button was active at the time of clearing.
        """
        captureselected = False
        for action in self.projecttoolbar.actions():
            if action.objectName() == "capture" and action.isChecked():
                captureselected = True

            if action.property('dataentry'):
                self.projecttoolbar.removeAction(action)
        return captureselected

    def toggle_raster_layers(self) -> None:
        """
        Toggle all raster layers on or off.
        """
        # Freeze the canvas to save on UI refresh
        dlg = PickActionDialog(msg="Raster visibility")
        actions = [
            (":/icons/raster_0", "Off", partial(self._set_basemaps_opacity,
                                                0), "photo_off"),
            (":/icons/raster_25", "25%",
             partial(self._set_basemaps_opacity, .25), "photo_25"),
            (":/icons/raster_50", "50%",
             partial(self._set_basemaps_opacity, .50), "photo_50"),
            (":/icons/raster_75", "75%",
             partial(self._set_basemaps_opacity, .75), "photo_75"),
            (":/icons/raster_100", "100%",
             partial(self._set_basemaps_opacity, 1), "photo_100"),
        ]

        # ":/icons/raster_100"), "100%", self, triggered=partial(self._set_raster_layer_value, 1),
        #                                                objectName="photo_100")
        dialog_actions = []
        for action in actions:
            icon = QIcon(action[0])
            qaction = QAction(icon,
                              action[1],
                              self,
                              triggered=action[2],
                              objectName=action[3])
            dialog_actions.append(qaction)

        dlg.addactions(dialog_actions)
        dlg.exec_()

    def _set_basemaps_opacity(self, value=0) -> None:
        """
        Set the opacity for all basemap raster layers.
        :param value: The opacity value betwen 0 and 1
        """
        tree = QgsProject.instance().layerTreeRoot()
        for node in tree.findLayers():
            layer = node.layer()
            if node.layer().type() == QgsMapLayer.RasterLayer:
                if value > 0:
                    node.setItemVisibilityChecked(Qt.Checked)
                    renderer = layer.renderer()
                    renderer.setOpacity(value)
                if value == 0:
                    node.setItemVisibilityChecked(Qt.Unchecked)

        self.canvas.refresh()

    def cleanup(self):
        """
        Clean up when the project has changed.
        :return:
        """
        # TODO Review cleanup
        # self.bridge.clear()
        self.gpsband.reset()
        self.gpsband.hide()
        self.clear_selection()
        self.clear_temp_objects()
        self.clear_capture_tools()
        for action in self.layerbuttons:
            self.editgroup.removeAction(action)
Example #24
0
class MapWidget(Ui_CanvasWidget, QMainWindow):
    def __init__(self, parent=None):
        super(MapWidget, self).__init__(parent)
        self.setupUi(self)

        self.firstshow = True
        self.layerbuttons = []
        self.editfeaturestack = []
        self.lastgpsposition = None
        self.project = None
        self.gps = None
        self.gpslogging = None
        self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas))

        self.canvas.setCanvasColor(Qt.white)
        self.canvas.enableAntiAliasing(True)
        self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor)

        if hasattr(self.canvas, 'setParallelRenderingEnabled'):
            self.canvas.setParallelRenderingEnabled(True)

        pal = QgsPalLabeling()
        self.canvas.mapRenderer().setLabelingEngine(pal)
        self.canvas.setFrameStyle(QFrame.NoFrame)

        self.editgroup = QActionGroup(self)
        self.editgroup.setExclusive(True)
        self.editgroup.addAction(self.actionPan)
        self.editgroup.addAction(self.actionZoom_In)
        self.editgroup.addAction(self.actionZoom_Out)
        self.editgroup.addAction(self.actionInfo)

        self.actionGPS = GPSAction(":/icons/gps", self.canvas, self)
        self.projecttoolbar.addAction(self.actionGPS)

        gpsspacewidget= QWidget()
        gpsspacewidget.setMinimumWidth(30)
        gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.topspaceraction = self.projecttoolbar.insertWidget(self.actionGPS, gpsspacewidget)

        self.dataentryselection = QAction(self.projecttoolbar)
        self.dataentryaction = self.projecttoolbar.insertAction(self.topspaceraction, self.dataentryselection)
        self.dataentryselection.triggered.connect(self.select_data_entry)

        self.marker = GPSMarker(self.canvas)
        self.marker.hide()

        self.currentfeatureband = QgsRubberBand(self.canvas)
        self.currentfeatureband.setIconSize(20)
        self.currentfeatureband.setWidth(10)
        self.currentfeatureband.setColor(QColor(186, 93, 212, 76))

        self.gpsband = QgsRubberBand(self.canvas)
        self.gpsband.setColor(QColor(0, 0, 212, 76))
        self.gpsband.setWidth(5)

        RoamEvents.editgeometry.connect(self.queue_feature_for_edit)
        RoamEvents.selectioncleared.connect(self.clear_selection)
        RoamEvents.selectionchanged.connect(self.highlight_selection)
        RoamEvents.featureformloaded.connect(self.feature_form_loaded)

        self.connectButtons()

    def init_qgisproject(self, doc):
        parser = ProjectParser(doc)
        canvasnode = parser.canvasnode
        self.canvas.freeze()
        self.canvas.mapRenderer().readXML(canvasnode)
        self.canvaslayers = parser.canvaslayers()
        self.canvas.setLayerSet(self.canvaslayers)
        #red = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorRedPart", 255 )[0];
        #green = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorGreenPart", 255 )[0];
        #blue = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorBluePart", 255 )[0];
        #color = QColor(red, green, blue);
        #self.canvas.setCanvasColor(color)
        self.canvas.updateScale()
        return self.canvas.mapRenderer().destinationCrs()

    def showEvent(self, *args, **kwargs):
        if self.firstshow:
            self.canvas.refresh()
            self.canvas.repaint()
            self.firstshow = False

    def feature_form_loaded(self, form, feature, project, editmode):
        self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer)

    def highlight_selection(self, results):
        self.clear_selection()
        for layer, features in results.iteritems():
            band = self.selectionbands[layer]
            band.setColor(QColor(255, 0, 0, 200))
            band.setIconSize(20)
            band.setWidth(2)
            band.setBrushStyle(Qt.NoBrush)
            band.reset(layer.geometryType())
            for feature in features:
                band.addGeometry(feature.geometry(), layer)

    def highlight_active_selection(self, layer, feature, features):
        self.clear_selection()
        self.highlight_selection({layer: features})
        self.currentfeatureband.setToGeometry(feature.geometry(), layer)

    def clear_selection(self):
        # Clear the main selection rubber band
        self.currentfeatureband.reset()
        # Clear the rest
        for band in self.selectionbands.itervalues():
            band.reset()

        self.editfeaturestack = []

    def queue_feature_for_edit(self, form, feature):
        def trigger_default_action():
            for action in self.projecttoolbar.actions():
                if action.property('dataentry') and action.isdefault:
                    action.trigger()
                    break

        self.editfeaturestack.append((form, feature))
        self.load_form(form)
        trigger_default_action()

    def clear_temp_objects(self):
        def clear_tool_band():
            """
            Clear the rubber band of the active tool if it has one
            """
            tool = self.canvas.mapTool()
            try:
                tool.clearBand()
            except AttributeError:
                # No clearBand method found, but that's cool.
                pass

        self.currentfeatureband.reset()
        clear_tool_band()


    def settings_updated(self, settings):
        self.actionGPS.updateGPSPort()
        gpslogging = settings.get('gpslogging', True)
        if self.gpslogging:
            self.gpslogging.logging = gpslogging

    def set_gps(self, gps, logging):
        self.gps = gps
        self.gpslogging = logging
        self.gps.gpsposition.connect(self.gps_update_canvas)
        self.gps.firstfix.connect(self.gps_first_fix)
        self.gps.gpsdisconnected.connect(self.gps_disconnected)

    def gps_update_canvas(self, position, gpsinfo):
        # Recenter map if we go outside of the 95% of the area
        if self.gpslogging.logging:
            self.gpsband.addPoint(position)
            self.gpsband.show()

        if roam.config.settings.get('gpscenter', True):
            if not self.lastgpsposition == position:
                self.lastposition = position
                rect = QgsRectangle(position, position)
                extentlimt = QgsRectangle(self.canvas.extent())
                extentlimt.scale(0.95)

                if not extentlimt.contains(position):
                    self.zoom_to_location(position)

        self.marker.show()
        self.marker.setCenter(position)

    def gps_first_fix(self, postion, gpsinfo):
        zoomtolocation = roam.config.settings.get('gpszoomonfix', True)
        if zoomtolocation:
            self.canvas.zoomScale(1000)
            self.zoom_to_location(postion)

    def zoom_to_location(self, position):
        rect = QgsRectangle(position, position)
        self.canvas.setExtent(rect)
        self.canvas.refresh()

    def gps_disconnected(self):
        self.marker.hide()

    def select_data_entry(self):
        def showformerror(form):
            pass

        def actions():
            for form in self.project.forms:
                action = form.createuiaction()
                valid, failreasons = form.valid
                if not valid:
                    roam.utils.warning("Form {} failed to load".format(form.label))
                    roam.utils.warning("Reasons {}".format(failreasons))
                    action.triggered.connect(partial(showformerror, form))
                else:
                    action.triggered.connect(partial(self.load_form, form))
                yield action

        formpicker = PickActionDialog(msg="Select data entry form")
        formpicker.addactions(actions())
        formpicker.exec_()

    def project_loaded(self, project):
        self.project = project
        self.actionPan.trigger()
        try:
            firstform = project.forms[0]
            self.load_form(firstform)
            self.dataentryselection.setVisible(True)
        except IndexError:
            self.dataentryselection.setVisible(False)

        # Enable the raster layers button only if the project contains a raster layer.
        layers = QgsMapLayerRegistry.instance().mapLayers().values()
        hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers)
        self.actionRaster.setEnabled(hasrasters)
        self.defaultextent = self.canvas.extent()
        roam.utils.info("Extent: {}".format(self.defaultextent.toString()))

        self.infoTool.selectionlayers = project.selectlayersmapping()

        self.canvas.freeze(False)
        self.canvas.refresh()

    def setMapTool(self, tool, *args):
        self.canvas.setMapTool(tool)

    def connectButtons(self):
        def connectAction(action, tool):
            action.toggled.connect(partial(self.setMapTool, tool))

        def cursor(name):
            pix = QPixmap(name)
            pix = pix.scaled(QSize(24,24))
            return QCursor(pix)

        self.zoomInTool = QgsMapToolZoom(self.canvas, False)
        self.zoomOutTool = QgsMapToolZoom(self.canvas, True)
        self.panTool = PanTool(self.canvas)
        self.infoTool = InfoTool(self.canvas)

        connectAction(self.actionZoom_In, self.zoomInTool)
        connectAction(self.actionZoom_Out, self.zoomOutTool)
        connectAction(self.actionPan, self.panTool)
        connectAction(self.actionInfo, self.infoTool)

        self.zoomInTool.setCursor(cursor(':/icons/in'))
        self.zoomOutTool.setCursor(cursor(':/icons/out'))
        self.infoTool.setCursor(cursor(':/icons/info'))

        self.actionRaster.triggered.connect(self.toggleRasterLayers)

        self.infoTool.infoResults.connect(RoamEvents.selectionchanged.emit)

        self.actionHome.triggered.connect(self.homeview)

    def homeview(self):
        """
        Zoom the mapview canvas to the extents the project was opened at i.e. the
        default extent.
        """
        self.canvas.setExtent(self.defaultextent)
        self.canvas.refresh()

    def load_form(self, form):
        self.clearCapatureTools()
        self.dataentryselection.setIcon(QIcon(form.icon))
        self.dataentryselection.setText(form.icontext)
        self.create_capture_buttons(form)

    def create_capture_buttons(self, form):
        tool = form.getMaptool()(self.canvas)
        for action in tool.actions:
            # Create the action here.
            if action.ismaptool:
                action.toggled.connect(partial(self.setMapTool, tool))

            # Set the action as a data entry button so we can remove it later.
            action.setProperty("dataentry", True)
            self.editgroup.addAction(action)
            self.layerbuttons.append(action)
            self.projecttoolbar.insertAction(self.topspaceraction, action)
            action.setChecked(action.isdefault)

        if hasattr(tool, 'geometryComplete'):
            add = partial(self.add_new_feature, form)
            tool.geometryComplete.connect(add)
        else:
            tool.finished.connect(self.openForm)
            tool.error.connect(partial(self.showUIMessage, form.label))

    def add_new_feature(self, form, geometry):
        """
        Add a new new feature to the given layer
        """
        # TODO Extract into function.
        # NOTE This function is doing too much, acts as add and also edit.
        layer = form.QGISLayer
        if layer.geometryType() in [QGis.WKBMultiLineString, QGis.WKBMultiPoint, QGis.WKBMultiPolygon]:
            geometry.convertToMultiType()

        try:
            form, feature = self.editfeaturestack.pop()
            self.editfeaturegeometry(form, feature, newgeometry=geometry)
            return
        except IndexError:
            pass

        layer = form.QGISLayer
        fields = layer.pendingFields()

        feature = QgsFeature(fields)
        feature.setGeometry(geometry)

        for index in xrange(fields.count()):
            pkindexes = layer.dataProvider().pkAttributeIndexes()
            if index in pkindexes and layer.dataProvider().name() == 'spatialite':
                continue

            value = layer.dataProvider().defaultValue(index)
            feature[index] = value

        RoamEvents.open_feature_form(form, feature, editmode=False)

    def editfeaturegeometry(self, form, feature, newgeometry):
        # TODO Extract into function.
        layer = form.QGISLayer
        layer.startEditing()
        feature.setGeometry(newgeometry)
        layer.updateFeature(feature)
        saved = layer.commitChanges()
        if not saved:
            map(roam.utils.error, layer.commitErrors())
        self.canvas.refresh()
        self.currentfeatureband.setToGeometry(feature.geometry(), layer)
        RoamEvents.editgeometry_complete.emit(form, feature)

    def clearCapatureTools(self):
        captureselected = False
        for action in self.projecttoolbar.actions():
            if action.objectName() == "capture" and action.isChecked():
                captureselected = True

            if action.property('dataentry'):
                self.projecttoolbar.removeAction(action)
        return captureselected

    def toggleRasterLayers(self):
        """
        Toggle all raster layers on or off.
        """
        if not self.canvaslayers:
            return

        #Freeze the canvas to save on UI refresh
        self.canvas.freeze()
        for layer in self.canvaslayers:
            if layer.layer().type() == QgsMapLayer.RasterLayer:
                layer.setVisible(not layer.isVisible())
                # Really!? We have to reload the whole layer set every time?
            # WAT?
        self.canvas.setLayerSet(self.canvaslayers)
        self.canvas.freeze(False)
        self.canvas.refresh()

    def cleanup(self):
        self.gpsband.reset()
        self.gpsband.hide()
        self.clear_selection()
        self.clear_temp_objects()
        self.clearCapatureTools()
        self.canvas.freeze()
        self.canvas.clear()
        self.canvas.freeze(False)
        for action in self.layerbuttons:
            self.editgroup.removeAction(action)
Example #25
0
class GraphSelectTool(QgsMapToolEmitPoint):

    mouseMove = pyqtSignal(QgsPointXY)
    mouseClicked = pyqtSignal(QgsPointXY)
    selectionChanged = pyqtSignal()

    def __init__(self, iface):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)
        self.rb.setColor(QColor(255,0,0,50))
        self.rb.setFillColor(QColor(255,0,0,50))
        self.rb.setWidth(1)
        self.drawrubber = False
        self.rubberPointX = 0
        self.rubberPointY = 0
        self.layer = None

    def setLayer(self, layer):
        self.layer = layer

    def reset(self):
        self.rb.reset(QgsWkbTypes.PolygonGeometry)


    def canvasPressEvent(self, e):
        self.rubberPointX = e.x()
        self.rubberPointY = e.y()
        self.drawrubber= True


    def canvasReleaseEvent(self, e):

        myOriginalPoint = QgsPointXY(self.canvas.getCoordinateTransform().toMapCoordinates(e.x(), e.y()))
        self.mouseClicked.emit(myOriginalPoint)
        
        self.reset()
        self.drawrubber = False

        myOldPoint = QgsPointXY(self.canvas.getCoordinateTransform().toMapCoordinates(self.rubberPointX, self.rubberPointY))
        rect = QgsRectangle(myOldPoint, myOriginalPoint)

        if(self.layer.select(rect)): 
        
            self.selectionChanged.emit()

        self.canvas.refresh()


    def canvasMoveEvent(self, e):

        myOriginalPoint = QgsPointXY(self.canvas.getCoordinateTransform().toMapCoordinates(e.x(), e.y()))
        self.mouseMove.emit(myOriginalPoint)

        if(self.drawrubber):    
            myPoint1 = QgsPointXY(self.canvas.getCoordinateTransform().toMapCoordinates(e.x(),e.y()))
            myPoint2 = QgsPointXY(self.canvas.getCoordinateTransform().toMapCoordinates(self.rubberPointX,e.y()))
            myPoint3 = QgsPointXY(self.canvas.getCoordinateTransform().toMapCoordinates(self.rubberPointX,self.rubberPointY))
            myPoint4 = QgsPointXY(self.canvas.getCoordinateTransform().toMapCoordinates(e.x(),self.rubberPointY))


            self.reset()
            #convert screen coordinates to map coordinates
            self.rb.addPoint( myPoint1, False )
            self.rb.addPoint( myPoint2, False )
            self.rb.addPoint( myPoint3, False )
            self.rb.addPoint( myPoint4, True ) #true - update canvas
            self.rb.show()
Example #26
0
class MeasureAngleTool(QgsMapTool):
    finished = pyqtSignal()

    def __init__(self, canvas, msglog):
        super().__init__(canvas)
        self.canvas = canvas
        self.msglog = msglog
        self.start_point = self.middle_point = self.end_point = None
        self.rubber_band = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.rubber_band.setColor(QColor(255, 0, 0, 100))
        self.rubber_band.setWidth(3)
        self.rubber_band_points = QgsRubberBand(self.canvas,
                                                QgsWkbTypes.PointGeometry)
        self.rubber_band_points.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.rubber_band_points.setIconSize(10)
        self.rubber_band_points.setColor(QColor(255, 0, 0, 150))
        self.rubber_band_curve = QgsRubberBand(self.canvas)
        self.rubber_band_curve.setWidth(2)
        self.rubber_band_curve.setColor(QColor(255, 153, 0, 100))

        crs = self.canvas.mapSettings().destinationCrs()
        self.distance_calc = QgsDistanceArea()
        self.distance_calc.setSourceCrs(
            crs,
            QgsProject.instance().transformContext())
        self.distance_calc.setEllipsoid(crs.ellipsoidAcronym())
        self.reset()

    def reset(self):
        self.msglog.logMessage("")
        self.start_point = self.middle_point = self.end_point = None
        self.rubber_band.reset(QgsWkbTypes.LineGeometry)
        self.rubber_band_points.reset(QgsWkbTypes.PointGeometry)
        self.rubber_band_curve.reset()

    def canvasPressEvent(self, event):
        pass

    def canvasReleaseEvent(self, event):
        transform = self.canvas.getCoordinateTransform()
        point = transform.toMapCoordinates(event.pos().x(), event.pos().y())
        if self.start_point and self.middle_point:
            angle_start_to_middle = self.distance_calc.bearing(
                self.middle_point, self.start_point)
            angle_end_to_middle = self.distance_calc.bearing(
                self.middle_point, point)
            angle = degrees(angle_end_to_middle - angle_start_to_middle)
            if angle < -180:
                angle = 360 + angle
            elif angle > 180:
                angle = angle - 360

            anglemsg = QMessageBox(self.parent())
            anglemsg.finished.connect(self.deactivate)
            anglemsg.setWindowTitle("Measure angle tool")
            anglemsg.setText("Angle: {:.3F} º".format(abs(angle)))
            anglemsg.exec()
            self.finish()

        elif self.start_point:
            self.middle_point = point
            self.rubber_band.addPoint(self.middle_point)
            self.rubber_band_points.addPoint(self.middle_point)

        else:
            self.start_point = point
            self.rubber_band.addPoint(self.start_point)
            self.rubber_band_points.addPoint(self.start_point)

    def canvasMoveEvent(self, e):
        if self.start_point and not self.end_point:
            transform = self.canvas.getCoordinateTransform()
            point = transform.toMapCoordinates(e.pos().x(), e.pos().y())
            self.rubber_band.movePoint(point)

        if self.start_point and self.middle_point and not self.end_point:
            angle_start_to_middle = self.distance_calc.bearing(
                self.middle_point, self.start_point)
            angle_end_to_middle = self.distance_calc.bearing(
                self.middle_point, point)
            angle = degrees(angle_end_to_middle - angle_start_to_middle)

            if angle < -180:
                angle = 360 + angle
            elif angle > 180:
                angle = angle - 360

            self.msglog.logMessage("")
            self.msglog.logMessage(
                "Current angle: {:.3F} º".format(abs(angle)), "Measure angle:",
                0)

            self.rubber_band_curve.reset()

            # get the distance from center to point
            dist_mid_to_p = sqrt((point.x() - self.middle_point.x()) *
                                 (point.x() - self.middle_point.x()) +
                                 (point.y() - self.middle_point.y()) *
                                 (point.y() - self.middle_point.y()))
            dist_mid_to_start = sqrt(
                (self.start_point.x() - self.middle_point.x()) *
                (self.start_point.x() - self.middle_point.x()) +
                (self.start_point.y() - self.middle_point.y()) *
                (self.start_point.y() - self.middle_point.y()))

            # get angle
            angle_start = atan2(self.start_point.y() - self.middle_point.y(),
                                self.start_point.x() - self.middle_point.x())
            angle_p = atan2(point.y() - self.middle_point.y(),
                            point.x() - self.middle_point.x())

            # smaller distance
            if dist_mid_to_p < dist_mid_to_start:
                dist = dist_mid_to_p
            else:
                dist = dist_mid_to_start

            y_p = dist * sin(angle_p)
            x_p = dist * cos(angle_p)
            y_start = dist * sin(angle_start)
            x_start = dist * cos(angle_start)

            circular_ring = QgsCircularString()
            circular_ring = circular_ring.fromTwoPointsAndCenter(
                QgsPoint(self.middle_point.x() + x_start / 2,
                         self.middle_point.y() + y_start / 2),
                QgsPoint(self.middle_point.x() + x_p / 2,
                         self.middle_point.y() + y_p / 2),
                QgsPoint(self.middle_point.x(), self.middle_point.y()), True)

            circular_geometry = QgsGeometry(circular_ring)

            self.rubber_band_curve.addGeometry(
                circular_geometry,
                QgsCoordinateReferenceSystem(
                    4326, QgsCoordinateReferenceSystem.EpsgCrsId))

    def keyPressEvent(self, event):
        """
        When escape key is pressed, line is restarted
        """
        if event.key() == Qt.Key_Escape:
            self.reset()

    def finish(self):
        self.reset()
        self.finished.emit()
Example #27
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(QgsWkbTypes.LineGeometry)
        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 #28
0
class MeasureAreaTool(QgsMapTool):
    finished = pyqtSignal()

    def __init__(self, canvas, msglog):
        super().__init__(canvas)
        self.canvas = canvas
        self.msglog = msglog
        self.start_point = self.middle_point = self.end_point = None
        self.rubber_band = QgsRubberBand(self.canvas,
                                         QgsWkbTypes.PolygonGeometry)
        self.rubber_band.setColor(QColor(255, 0, 0, 100))
        self.rubber_band.setWidth(3)
        self.rubber_band_points = QgsRubberBand(self.canvas,
                                                QgsWkbTypes.PointGeometry)
        self.rubber_band_points.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.rubber_band_points.setIconSize(10)
        self.rubber_band_points.setColor(QColor(255, 0, 0, 150))

        crs = self.canvas.mapSettings().destinationCrs()
        self.area_calc = QgsDistanceArea()
        self.area_calc.setSourceCrs(crs,
                                    QgsProject.instance().transformContext())
        self.area_calc.setEllipsoid(crs.ellipsoidAcronym())
        self.reset()

    def reset(self):
        """ Reset log message and rubber band"""
        self.msglog.logMessage("")
        self.start_point = self.end_point = None
        self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
        self.rubber_band_points.reset(QgsWkbTypes.PointGeometry)

    def canvasPressEvent(self, event):
        pass

    def canvasReleaseEvent(self, event):
        transform = self.canvas.getCoordinateTransform()
        point = transform.toMapCoordinates(event.pos().x(), event.pos().y())

        if self.start_point and event.button() == Qt.RightButton:
            multipoint = self.rubber_band.asGeometry()
            area = self.area_calc.measureArea(multipoint)
            anglemsg = QMessageBox(self.parent())
            anglemsg.finished.connect(self.deactivate)
            anglemsg.setWindowTitle("Measure area tool")
            anglemsg.setText("Area: {} ".format(
                self.area_calc.formatArea(area, 3,
                                          QgsUnitTypes.AreaSquareMeters,
                                          True)))
            anglemsg.exec()
            self.finish()
        elif self.start_point:
            self.rubber_band.addPoint(point)
            self.rubber_band_points.addPoint(point)

        else:
            self.start_point = point
            self.rubber_band.addPoint(self.start_point)
            self.rubber_band_points.addPoint(self.start_point)

    def canvasMoveEvent(self, e):
        if self.start_point and not self.end_point:
            transform = self.canvas.getCoordinateTransform()
            point = transform.toMapCoordinates(e.pos().x(), e.pos().y())
            self.rubber_band.movePoint(point)

            multipoint = self.rubber_band.asGeometry()
            area = self.area_calc.measureArea(multipoint)
            self.msglog.logMessage("")
            self.msglog.logMessage(
                "Current area: {} ".format(
                    self.area_calc.formatArea(area, 3,
                                              QgsUnitTypes.AreaSquareMeters,
                                              True)), "Measure Area:", 0)

    def keyPressEvent(self, event):
        """
        When escape key is pressed, line is restarted
        """
        if event.key() == Qt.Key_Escape:
            self.reset()

    def finish(self):
        self.reset()
        self.finished.emit()
Example #29
0
class Qgis2threejsDialog(QDialog):
  STYLE_MAX_COUNT = 3

  def __init__(self, iface):
    QDialog.__init__(self, iface.mainWindow())
    self.iface = iface
    self.apiChanged22 = False   # not QgsApplication.prefixPath().startswith("C:/OSGeo4W")  # QGis.QGIS_VERSION_INT >= 20200

    # Set up the user interface from Designer.
    self.ui = ui = Ui_Qgis2threejsDialog()
    ui.setupUi(self)

    self.setWindowFlags(self.windowFlags() | Qt.WindowMinimizeButtonHint)
    ui.lineEdit_OutputFilename.setPlaceholderText("[Temporary file]")

    ui.pushButton_Run.clicked.connect(self.run)
    ui.pushButton_Close.clicked.connect(self.reject)

    # DEM tab
    ui.toolButton_switchFocusMode.setVisible(False)
    ui.toolButton_PointTool.setVisible(False)
    ui.progressBar.setVisible(False)
    self.switchFocusMode(True)

    ui.toolButton_Browse.clicked.connect(self.browseClicked)
    ui.radioButton_Simple.toggled.connect(self.samplingModeChanged)
    ui.horizontalSlider_Resolution.valueChanged.connect(self.calculateResolution)
    ui.spinBox_Height.valueChanged.connect(self.updateQuads)
    ui.toolButton_switchFocusMode.clicked.connect(self.switchFocusModeClicked)
    ui.toolButton_PointTool.clicked.connect(self.startPointSelection)

    # Vector tab
    ui.treeWidget_VectorLayers.setHeaderLabel("Vector layers")
    self.initVectorStyleWidgets()

    ui.treeWidget_VectorLayers.currentItemChanged.connect(self.currentVectorLayerChanged)
    ui.treeWidget_VectorLayers.itemChanged.connect(self.vectorLayerItemChanged)
    ui.comboBox_ObjectType.currentIndexChanged.connect(self.objectTypeSelectionChanged)

    self.bar = None
    self.localBrowsingMode = True
    self.rb_quads = self.rb_point = None
    self.currentVectorLayer = None
    self.vectorPropertiesDict = {}
    self.objectTypeManager = ObjectTypeManager()

    # set map tool
    self.previousMapTool = None
    self.mapTool = RectangleMapTool(iface.mapCanvas())
    self.connect(self.mapTool, SIGNAL("rectangleCreated()"), self.rectangleSelected)
#    self.mapTool = PointMapTool(iface.mapCanvas())
#    QObject.connect(self.mapTool, SIGNAL("pointSelected()"), self.pointSelected)
    iface.mapCanvas().mapToolSet.connect(self.mapToolSet)
    self.startPointSelection()

  def exec_(self):
    ui = self.ui
    messages = []
    # show message if crs unit is degrees
    mapSettings = self.iface.mapCanvas().mapSettings() if self.apiChanged22 else self.iface.mapCanvas().mapRenderer()
    if mapSettings.destinationCrs().mapUnits() in [QGis.Degrees]:
      self.showMessageBar("The unit of current CRS is degrees", "Terrain may not appear well.")

    # show message if there are no dem layer
    no_demlayer = ui.comboBox_DEMLayer.count() == 0
    ui.pushButton_Run.setEnabled(not no_demlayer)
    if no_demlayer:
      self.showMessageBar("No DEM layer", "Load 1-band raster layer with GDAL provider.", QgsMessageBar.WARNING)

    return QDialog.exec_(self)

  def showMessageBar(self, title, text, level=QgsMessageBar.INFO):
    if self.bar is None:
      self.bar = QgsMessageBar()
      self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)

      ui = self.ui
      margins = ui.gridLayout.getContentsMargins()
      vl = ui.gridLayout.takeAt(0)
      ui.gridLayout.setContentsMargins(0,0,0,0)
      ui.gridLayout.addWidget(self.bar, 0, 0)
      ui.gridLayout.addItem(vl, 1, 0)
      ui.verticalLayout.setContentsMargins(margins[0], margins[1] / 2, margins[2], margins[3])
    self.bar.pushMessage(title, text, level=level)

  def initDEMLayerList(self, layerId=None):
    # list 1 band raster layers
    self.ui.comboBox_DEMLayer.clear()
    for id, layer in QgsMapLayerRegistry().instance().mapLayers().items():
      if layer.type() == QgsMapLayer.RasterLayer and layer.providerType() == "gdal" and layer.bandCount() == 1:
        self.ui.comboBox_DEMLayer.addItem(layer.name(), id)

    # select the last selected layer
    if layerId is not None:
      index = self.ui.comboBox_DEMLayer.findData(layerId)
      if index != -1:
        self.ui.comboBox_DEMLayer.setCurrentIndex(index)
      return index
    return -1

  def initVectorLayerTree(self, vectorPropertiesDict):
    self.vectorPropertiesDict = vectorPropertiesDict
    tree = self.ui.treeWidget_VectorLayers
    tree.clear()
    # add vector layers into tree widget
    self.treeTopItems = topItems = {QGis.Point:QTreeWidgetItem(tree, ["Point"]), QGis.Line:QTreeWidgetItem(tree, ["Line"]), QGis.Polygon:QTreeWidgetItem(tree, ["Polygon"])}
    self.vlItems = {}
    for layer in self.iface.legendInterface().layers():
      if layer.type() != QgsMapLayer.VectorLayer:
        continue
      geometry_type = layer.geometryType()
      if geometry_type in [QGis.Point, QGis.Line, QGis.Polygon]:
        self.vlItems[layer.id()] = item = QTreeWidgetItem(topItems[geometry_type], [layer.name()])
        if layer.id() in self.vectorPropertiesDict:
          isVisible = self.vectorPropertiesDict[layer.id()]["visible"]
        else:
          isVisible = False   #self.iface.legendInterface().isLayerVisible(layer)
        check_state = Qt.Checked if isVisible else Qt.Unchecked
        item.setData(0, Qt.CheckStateRole, check_state)
        item.setData(0, Qt.UserRole, layer.id())
        #item.setDisabled(True)
        #item.setData(0, Qt.CheckStateRole, Qt.Unchecked)

    for item in topItems.values():
      tree.expandItem(item)

    self.setVectorStylesEnabled(False)

  def initVectorStyleWidgets(self):
    self.colorWidget = StyleWidget(StyleWidget.COLOR)
    self.ui.verticalLayout_Styles.addWidget(self.colorWidget)
    self.heightWidget = StyleWidget(StyleWidget.HEIGHT)
    self.ui.verticalLayout_zCoordinate.addWidget(self.heightWidget)

    self.styleWidgets = []
    for i in range(self.STYLE_MAX_COUNT):
      widget = StyleWidget()
      widget.setVisible(False)
      self.ui.verticalLayout_Styles.addWidget(widget)
      self.styleWidgets.append(widget)

  def currentVectorLayerChanged(self, currentItem, previousItem):
    # save properties of previous item
    if previousItem is not None:
      layerid = previousItem.data(0, Qt.UserRole)
      if layerid is not None:
        self.saveVectorProperties(layerid)

    layerid = currentItem.data(0, Qt.UserRole)
    if layerid is None:
      self.currentVectorLayer = None
      return
    self.currentVectorLayer = layer = QgsMapLayerRegistry().instance().mapLayer(layerid)
    if layer is None:
      return

    for i in range(self.STYLE_MAX_COUNT):
      self.styleWidgets[i].hide()

    obj_types = self.objectTypeManager.objectTypeNames(layer.geometryType())
    ui = self.ui
    ui.comboBox_ObjectType.blockSignals(True)
    ui.comboBox_ObjectType.clear()
    ui.comboBox_ObjectType.addItems(obj_types)
    ui.comboBox_ObjectType.blockSignals(False)

    # set up property widgets
    self.objectTypeSelectionChanged()

    if layerid in self.vectorPropertiesDict:
      # restore properties
      self.restoreVectorProperties(layerid)

    self.setVectorStylesEnabled(currentItem.data(0, Qt.CheckStateRole) == Qt.Checked)

  def vectorLayerItemChanged(self, item, column):
    # update style form enablement
    currentItem = self.ui.treeWidget_VectorLayers.currentItem()
    if currentItem:
      self.setVectorStylesEnabled(currentItem.data(0, Qt.CheckStateRole) == Qt.Checked)

  def objectTypeSelectionChanged(self, idx=None):
    layer = self.currentVectorLayer
    try:
      ve = float(ui.lineEdit_zFactor.text())
    except:
      ve = 1
    mapTo3d = MapTo3D(self.iface.mapCanvas(), verticalExaggeration=ve)
    self.objectTypeManager.setupForm(self, mapTo3d, layer, layer.geometryType(), self.ui.comboBox_ObjectType.currentIndex())

  def numericFields(self, layer):
    # get attributes of a sample feature and create numeric field name list
    numeric_fields = []
    f = QgsFeature()
    layer.getFeatures().nextFeature(f)
    for field in f.fields():
      isNumeric = False
      try:
        float(f.attribute(field.name()))
        isNumeric = True
      except:
        pass
      if isNumeric:
        numeric_fields.append(field.name())
    return numeric_fields

  def setVectorStylesEnabled(self, enabled):
    self.ui.comboBox_ObjectType.setEnabled(enabled)
    self.ui.label_ObjectType.setEnabled(enabled)
    self.colorWidget.setEnabled(enabled)
    self.heightWidget.setEnabled(enabled)
    for i in range(self.STYLE_MAX_COUNT):
      self.styleWidgets[i].setEnabled(enabled)

  def saveVectorProperties(self, layerid):
    properties = {}
    layer = QgsMapLayerRegistry().instance().mapLayer(layerid)
    itemIndex = self.ui.comboBox_ObjectType.currentIndex()
    properties["itemindex"] = itemIndex
    properties["typeitem"] = self.objectTypeManager.objectTypeItem(layer.geometryType(), itemIndex)
    properties["visible"] = self.vlItems[self.currentVectorLayer.id()].data(0, Qt.CheckStateRole) == Qt.Checked
    properties["color"] = self.colorWidget.values()
    properties["height"] = self.heightWidget.values()
    for i in range(self.STYLE_MAX_COUNT):
      if self.styleWidgets[i].isVisible():
        properties[i] = self.styleWidgets[i].values()
    self.vectorPropertiesDict[layerid] = properties

  def restoreVectorProperties(self, layerid):
    properties = self.vectorPropertiesDict[layerid]
    self.ui.comboBox_ObjectType.setCurrentIndex(properties["itemindex"])
    self.colorWidget.setValues(properties["color"])
    self.heightWidget.setValues(properties["height"])
    for i in range(self.STYLE_MAX_COUNT):
      if i in properties:
        self.styleWidgets[i].setValues(properties[i])

  def calculateResolution(self, v=None):
    extent = self.iface.mapCanvas().extent()
    renderer = self.iface.mapCanvas().mapRenderer()
    size = 100 * self.ui.horizontalSlider_Resolution.value()
    self.ui.label_Resolution.setText("about {0} x {0} px".format(size))

    # calculate resolution and size
    width, height = renderer.width(), renderer.height()
    s = (size * size / float(width * height)) ** 0.5
    if s < 1:
      width = int(width * s)
      height = int(height * s)

    xres = extent.width() / width
    yres = extent.height() / height
    self.ui.lineEdit_HRes.setText(str(xres))
    self.ui.lineEdit_VRes.setText(str(yres))
    self.ui.lineEdit_Width.setText(str(width + 1))
    self.ui.lineEdit_Height.setText(str(height + 1))

  def progress(self, percentage):
    self.ui.progressBar.setValue(percentage)
    self.ui.progressBar.setVisible(percentage != 100)

  def run(self):
    ui = self.ui
    filename = ui.lineEdit_OutputFilename.text()   # ""=Temporary file
    if filename != "" and QFileInfo(filename).exists() and QMessageBox.question(None, "Qgis2threejs", "Output file already exists. Overwrite it?", QMessageBox.Ok | QMessageBox.Cancel) != QMessageBox.Ok:
      return
    self.endPointSelection()

    item = ui.treeWidget_VectorLayers.currentItem()
    if item:
      self.saveVectorProperties(item.data(0, Qt.UserRole))

    ui.pushButton_Run.setEnabled(False)
    self.progress(0)

    canvas = self.iface.mapCanvas()
    htmlfilename = ui.lineEdit_OutputFilename.text()
    demlayerid = ui.comboBox_DEMLayer.itemData(ui.comboBox_DEMLayer.currentIndex())
    mapTo3d = MapTo3D(canvas, verticalExaggeration=float(ui.lineEdit_zFactor.text()))
    if self.ui.radioButton_Simple.isChecked():
      dem_width = int(ui.lineEdit_Width.text())
      dem_height = int(ui.lineEdit_Height.text())
      context = OutputContext(mapTo3d, canvas, demlayerid, self.vectorPropertiesDict, self.objectTypeManager, self.localBrowsingMode,
                              dem_width, dem_height)
      htmlfilename = runSimple(htmlfilename, context, self.progress)
    else:
      context = OutputContext(mapTo3d, canvas, demlayerid, self.vectorPropertiesDict, self.objectTypeManager, self.localBrowsingMode)
      htmlfilename = runAdvanced(htmlfilename, context, self, self.progress)
    self.progress(100)
    ui.pushButton_Run.setEnabled(True)
    if htmlfilename is None:
      return
    self.clearRubberBands()

    if not tools.openHTMLFile(htmlfilename):
      return
    QDialog.accept(self)

  def reject(self):
    self.endPointSelection()
    self.clearRubberBands()
    QDialog.reject(self)

  def startPointSelection(self):
    canvas = self.iface.mapCanvas()
    self.previousMapTool = canvas.mapTool()
    canvas.setMapTool(self.mapTool)
    self.ui.toolButton_PointTool.setVisible(False)

  def endPointSelection(self):
    self.mapTool.reset()
    self.iface.mapCanvas().setMapTool(self.previousMapTool)

  def rectangleSelected(self):
    ui = self.ui
    ui.radioButton_Advanced.setChecked(True)
    rect = self.mapTool.rectangle()
    toRect = rect.width() and rect.height()
    self.switchFocusMode(toRect)
    ui.lineEdit_xmin.setText(str(rect.xMinimum()))
    ui.lineEdit_ymin.setText(str(rect.yMinimum()))
    ui.lineEdit_xmax.setText(str(rect.xMaximum()))
    ui.lineEdit_ymax.setText(str(rect.yMaximum()))

    quadtree = QuadTree(self.iface.mapCanvas().extent())
    quadtree.buildTreeByRect(rect, self.ui.spinBox_Height.value())
    self.createRubberBands(quadtree.quads(), rect.center())
    self.setWindowState(self.windowState() & ~Qt.WindowMinimized | Qt.WindowActive)

  def pointSelected(self):
    # set values of controls
    self.ui.lineEdit_CenterX.setText(str(self.mapTool.point.x()))
    self.ui.lineEdit_CenterY.setText(str(self.mapTool.point.y()))
    self.ui.radioButton_Advanced.setChecked(True)

    quadtree = QuadTree(self.iface.mapCanvas().extent(), self.mapTool.point, self.ui.spinBox_Height.value())
    self.createRubberBands(quadtree.quads(), self.mapTool.point)
    self.setWindowState(self.windowState() & ~Qt.WindowMinimized | Qt.WindowActive)

  def mapToolSet(self, mapTool):
    if mapTool != self.mapTool:
      self.ui.toolButton_PointTool.setVisible(True)

  def createQuadTree(self):
    ui = self.ui
    try:
      c = map(float, [ui.lineEdit_xmin.text(), ui.lineEdit_ymin.text(), ui.lineEdit_xmax.text(), ui.lineEdit_ymax.text()])
    except:
      return None
    quadtree = QuadTree(self.iface.mapCanvas().extent())
    quadtree.buildTreeByRect(QgsRectangle(c[0], c[1], c[2], c[3]), ui.spinBox_Height.value())
    return quadtree

  def createRubberBands(self, quads, point=None):
    self.clearRubberBands()
    # create quads with rubber band
    self.rb_quads = QgsRubberBand(self.iface.mapCanvas(), QGis.Line)
    self.rb_quads.setColor(Qt.blue)
    self.rb_quads.setWidth(1)

    for quad in quads:
      points = []
      extent = quad.extent
      points.append(QgsPoint(extent.xMinimum(), extent.yMinimum()))
      points.append(QgsPoint(extent.xMinimum(), extent.yMaximum()))
      points.append(QgsPoint(extent.xMaximum(), extent.yMaximum()))
      points.append(QgsPoint(extent.xMaximum(), extent.yMinimum()))
      self.rb_quads.addGeometry(QgsGeometry.fromPolygon([points]), None)
      self.log(extent.toString())
    self.log("Quad count: %d" % len(quads))

    # create a point with rubber band
    if point:
      self.rb_point = QgsRubberBand(self.iface.mapCanvas(), QGis.Point)
      self.rb_point.setColor(Qt.red)
      self.rb_point.addPoint(point)

  def clearRubberBands(self):
    # clear quads and point
    if self.rb_quads:
      self.iface.mapCanvas().scene().removeItem(self.rb_quads)
      self.rb_quads = None
    if self.rb_point:
      self.iface.mapCanvas().scene().removeItem(self.rb_point)
      self.rb_point = None

  def browseClicked(self):
    directory = self.ui.lineEdit_OutputFilename.text()
    if directory == "":
      directory = QDir.homePath()
    filename = QFileDialog.getSaveFileName(self, self.tr("Output filename"), directory, "HTML file (*.html *.htm)", options=QFileDialog.DontConfirmOverwrite)
    if filename != "":
      self.ui.lineEdit_OutputFilename.setText(filename)

  def samplingModeChanged(self):
    ui = self.ui
    isSimpleMode = ui.radioButton_Simple.isChecked()
    simple_widgets = [ui.horizontalSlider_Resolution, ui.lineEdit_Width, ui.lineEdit_Height, ui.lineEdit_HRes, ui.lineEdit_VRes]
    for w in simple_widgets:
      w.setEnabled(isSimpleMode)

    isAdvancedMode = not isSimpleMode
    advanced_widgets = [ui.spinBox_Height, ui.lineEdit_xmin, ui.lineEdit_ymin, ui.lineEdit_xmax, ui.lineEdit_ymax, ui.toolButton_switchFocusMode]
    for w in advanced_widgets:
      w.setEnabled(isAdvancedMode)

  def updateQuads(self, v=None):
    quadtree = self.createQuadTree()
    if quadtree:
      self.createRubberBands(quadtree.quads(), quadtree.focusRect.center())
    else:
      self.clearRubberBands()

  def switchFocusModeClicked(self):
    self.switchFocusMode(not self.ui.label_xmin.isVisible())

  def switchFocusMode(self, toRect):
    ui = self.ui
    toPoint = not toRect
    ui.label_xmin.setVisible(toRect)
    ui.label_ymin.setVisible(toRect)
    ui.lineEdit_xmin.setVisible(toRect)
    ui.lineEdit_ymin.setVisible(toRect)

    suffix = "max" if toRect else ""
    ui.label_xmax.setText("x" + suffix)
    ui.label_ymax.setText("y" + suffix)
    mode = "point" if toRect else "rectangle"
    ui.toolButton_switchFocusMode.setText("To " + mode + " selection")
    selection = "area" if toRect else "point"
    action = "Stroke a rectangle" if toRect else "Click"
    ui.label_Focus.setText("Focus {0} ({1} on map canvas to set values)".format(selection, action))

  def log(self, msg):
    if debug_mode:
      qDebug(msg)
Example #30
0
    def draw(self, rows, con, args, geomType, canvasItemList, mapCanvas):
        ''' draw the result '''
        resultPathsRubberBands = canvasItemList['paths']
        rubberBand = None
        cur_path_id = -1

        i = 0
        count = len(rows)
        ids = args['ids'].split(',')
        args['last_id'] = ids[len(ids) - 1]
        pcts = args['pcts'].split(',')
        pct_idx = 0
        for row in rows:
            cur2 = con.cursor()
            args['result_path_id'] = row[1]
            args['result_node_id'] = row[2]
            args['result_edge_id'] = row[3]
            args['result_cost'] = row[4]

            if args['result_path_id'] != cur_path_id:
                cur_path_id = args['result_path_id']
                if rubberBand:
                    resultPathsRubberBands.append(rubberBand)
                    rubberBand = None

                rubberBand = QgsRubberBand(mapCanvas,
                                           Utils.getRubberBandType(False))
                rubberBand.setColor(QColor(255, 0, 0, 128))
                rubberBand.setWidth(4)

            query2 = ""
            if i < (count - 1):
                args['result_next_path_id'] = rows[i + 1][1]
                args['result_next_node_id'] = rows[i + 1][2]
                if args['result_next_path_id'] != args['result_path_id']:
                    pct_idx += 1
            elif i == (count - 1):
                pct_idx = len(pcts) - 1
            args['current_pct'] = pcts[pct_idx]

            if i == 0 and args['result_node_id'] == -1:
                query2 = """
                    SELECT ST_AsText(%(transform_s)sST_Line_Substring(%(geometry)s, %(current_pct)s, 1.0)%(transform_e)s) FROM %(edge_table)s
                        WHERE %(target)s = %(result_next_node_id)s AND %(id)s = %(result_edge_id)s
                    UNION
                    SELECT ST_AsText(%(transform_s)sST_Line_Substring(ST_Reverse(%(geometry)s), 1.0 - %(current_pct)s, 1.0)%(transform_e)s) FROM %(edge_table)s
                        WHERE %(source)s = %(result_next_node_id)s AND %(id)s = %(result_edge_id)s;
                """ % args
            elif i < (count - 1) and (
                    args['result_path_id'] != args['result_next_path_id']
            ) and (args['result_node_id'] == args['result_next_node_id']):
                # round trip case
                query2 = """
                    SELECT ST_AsText(ST_LineMerge(ST_Collect(ARRAY[
                    (
                        SELECT ST_AsText(%(transform_s)sST_Line_Substring(%(geometry)s, 0.0, %(current_pct)s)%(transform_e)s) FROM %(edge_table)s
                            WHERE %(source)s = %(result_node_id)s AND %(id)s = %(result_edge_id)s
                        UNION
                        SELECT ST_AsText(%(transform_s)sST_Line_Substring(ST_Reverse(%(geometry)s), 0.0, 1.0 - %(current_pct)s)%(transform_e)s) FROM %(edge_table)s
                            WHERE %(target)s = %(result_node_id)s AND %(id)s = %(result_edge_id)s
                    ),
                    (
                        SELECT ST_AsText(%(transform_s)sST_Reverse(ST_Line_Substring(%(geometry)s, 0.0, %(current_pct)s))%(transform_e)s) FROM %(edge_table)s
                            WHERE %(source)s = %(result_node_id)s AND %(id)s = %(result_edge_id)s
                        UNION
                        SELECT ST_AsText(%(transform_s)sST_Reverse(ST_Line_Substring(ST_Reverse(%(geometry)s), 0.0, 1.0 - %(current_pct)s))%(transform_e)s) FROM %(edge_table)s
                            WHERE %(target)s = %(result_node_id)s AND %(id)s = %(result_edge_id)s
                    )])));
                """ % args
            elif i == (count - 1) and (
                (args['result_edge_id'] == -1) or
                (str(args['result_edge_id']) == args['last_id'])):
                if args['result_edge_id'] != -1:
                    query2 = """
                        SELECT ST_AsText(%(transform_s)sST_Line_Substring(%(geometry)s, 0.0, %(current_pct)s)%(transform_e)s) FROM %(edge_table)s
                            WHERE %(source)s = %(result_node_id)s AND %(id)s = %(result_edge_id)s
                        UNION
                        SELECT ST_AsText(%(transform_s)sST_Line_Substring(ST_Reverse(%(geometry)s), 0.0, 1.0 - %(current_pct)s)%(transform_e)s) FROM %(edge_table)s
                            WHERE %(target)s = %(result_node_id)s AND %(id)s = %(result_edge_id)s;
                    """ % args
                else:
                    break
            else:
                query2 = """
                    SELECT ST_AsText(%(transform_s)s%(geometry)s%(transform_e)s) FROM %(edge_table)s
                        WHERE %(source)s = %(result_node_id)d AND %(id)s = %(result_edge_id)d
                    UNION
                    SELECT ST_AsText(%(transform_s)sST_Reverse(%(geometry)s)%(transform_e)s) FROM %(edge_table)s
                        WHERE %(target)s = %(result_node_id)d AND %(id)s = %(result_edge_id)d;
                """ % args

            ##Utils.logMessage(query2)
            cur2.execute(query2)
            row2 = cur2.fetchone()
            ##Utils.logMessage(str(row2[0]))
            assert row2, "Invalid result geometry. (node_id:%(result_node_id)d, edge_id:%(result_edge_id)d)" % args

            geom = QgsGeometry().fromWkt(str(row2[0]))
            if geom.wkbType() == QgsWkbTypes.MultiLineString:
                for line in geom.asMultiPolyline():
                    for pt in line:
                        rubberBand.addPoint(pt)
            elif geom.wkbType() == QgsWkbTypes.LineString:
                for pt in geom.asPolyline():
                    rubberBand.addPoint(pt)

            i = i + 1

        if rubberBand:
            resultPathsRubberBands.append(rubberBand)
            rubberBand = None
Example #31
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)  
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
Example #33
0
class MeasureDistanceTool(QgsMapTool):
    finished = pyqtSignal()

    def __init__(self, canvas, msglog):
        super().__init__(canvas)
        self.canvas = canvas
        self.msglog = msglog
        self.start_point = self.end_point = None
        self.rubber_band = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.rubber_band.setColor(QColor(255, 0, 0, 100))
        self.rubber_band.setWidth(3)
        self.rubber_band_points = QgsRubberBand(self.canvas,
                                                QgsWkbTypes.PointGeometry)
        self.rubber_band_points.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.rubber_band_points.setIconSize(10)
        self.rubber_band_points.setColor(QColor(255, 0, 0, 150))
        crs = self.canvas.mapSettings().destinationCrs()
        self.distance_calc = QgsDistanceArea()
        self.distance_calc.setSourceCrs(
            crs,
            QgsProject.instance().transformContext())
        self.distance_calc.setEllipsoid(crs.ellipsoidAcronym())
        self.reset()

    def reset(self):
        self.msglog.logMessage("")
        self.start_point = self.end_point = None
        self.rubber_band.reset(QgsWkbTypes.LineGeometry)
        self.rubber_band_points.reset(QgsWkbTypes.PointGeometry)

    def canvasPressEvent(self, event):
        pass

    def canvasReleaseEvent(self, event):
        transform = self.canvas.getCoordinateTransform()
        point = transform.toMapCoordinates(event.pos().x(), event.pos().y())
        if self.start_point:
            self.end_point = point
            self.rubber_band.addPoint(self.end_point)
            self.rubber_band_points.addPoint(self.end_point)
            distance = self.distance_calc.measureLine(
                [self.start_point, self.end_point])
            bearing = self.distance_calc.bearing(self.start_point, point)
            distancemsg = QMessageBox(self.parent())
            distancemsg.finished.connect(self.deactivate)
            distancemsg.setWindowTitle("Measure tool")
            distancemsg.setText("Distance: {:.3F} m. Bearing: {:.3F} º".format(
                distance, degrees(bearing)))
            distancemsg.exec()
            self.finish()

        else:
            self.start_point = point
            self.rubber_band.addPoint(self.start_point)
            self.rubber_band_points.addPoint(self.start_point)

    def canvasMoveEvent(self, e):
        if self.start_point and not self.end_point:
            transform = self.canvas.getCoordinateTransform()
            point = transform.toMapCoordinates(e.pos().x(), e.pos().y())
            self.rubber_band.movePoint(point)
            distance = self.distance_calc.measureLine(
                [self.start_point, point])
            bearing = self.distance_calc.bearing(self.start_point, point)
            self.msglog.logMessage("")
            self.msglog.logMessage(
                "Current distance: {:.3F} m. Bearing: {:.3F} º".format(
                    distance, degrees(bearing)), "Measure distance:", 0)

    def keyPressEvent(self, event):
        """
        When escape key is pressed, line is restarted
        """
        if event.key() == Qt.Key_Escape:
            self.reset()

    def finish(self):
        self.reset()
        self.finished.emit()
Example #34
0
class PolygonMapTool(QgsMapToolEmitPoint):
    def __init__(self, MapExplorer):
        self.mainWindow = MapExplorer
        self.canvas = MapExplorer.mapCanvas
        self.rasterlayer = MapExplorer.layer
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.rubberBand = QgsRubberBand(self.canvas, True)
        self.rubberBand.setColor(QColor(255, 0, 0))
        self.rubberBand.setWidth(1)
        self.tmpRubberBand = QgsRubberBand(self.canvas, True)
        self.tmpRubberBand.setColor(QColor(255, 0, 0))
        self.tmpRubberBand.setWidth(1)
        self.categories = []
        self.reset()
        self.methodsDict = {
            "最小距离": self.MinDistance,
            "最大似然": self.MaxLikelihood,
            "马氏距离": self.Mahalanobis,
            "支持向量机": self.SVM,
            "神经网络": self.ANN,
            "随机森林": self.RandomForest,
            "AdaBoost": self.AdaBoost
        }

    def reset(self):
        self.isEmittingPoint = False
        self.chooseComplete = False
        self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
        self.tmpRubberBand.reset(True)

    def canvasReleaseEvent(self, e):
        current_point = self.toMapCoordinates(e.pos())
        if e.button() == Qt.LeftButton:
            self.isEmittingPoint = True
            self.tmpRubberBand.addPoint(current_point, True)
        elif e.button() == Qt.RightButton:
            if self.tmpRubberBand.numberOfVertices() > 2:
                lineString = self.tmpRubberBand.asGeometry(
                )  # type:QgsGeometry
                self.tmpRubberBand.reset(True)
                self.rubberBand.addGeometry(
                    QgsGeometry.convertToType(lineString,
                                              QgsWkbTypes.PolygonGeometry))
                self.rubberBand.setColor(QColor(255, 0, 0, 50))
                self.rubberBand.show()
                self.isEmittingPoint = False
                self.chooseComplete = True

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return
        self.tmpRubberBand.removeLastPoint(doUpdate=False)
        point = self.toMapCoordinates(e.pos())
        self.tmpRubberBand.addPoint(point, True)

    def keyReleaseEvent(self, e):
        if self.isEmittingPoint:
            if e.key() == Qt.Key_Backspace:
                self.tmpRubberBand.removeLastPoint(doUpdate=True)
        if self.chooseComplete:
            if e.key() + 1 == Qt.Key_Enter:  # 为啥会差一呢
                self.saveMask()
                self.reset()
                reply = QMessageBox.question(None, '提示', '继续加入类别?',
                                             QMessageBox.Yes | QMessageBox.No)
                if reply == QMessageBox.No:
                    for category in self.categories:
                        maskFile = f'mask/{category["name"]}_clip_mask.shp'
                        sampleFile = f'samples/{category["name"]}.tif'
                        if os.path.exists(sampleFile):
                            os.remove(sampleFile)
                        cmd = f'gdalwarp -of GTiff -cutline {maskFile} -cl {category["name"]}_clip_mask -crop_to_cutline -dstnodata 0 {self.rasterlayer.dataProvider().dataSourceUri()} {sampleFile}'
                        os.system(cmd)
                    dlg = Select_Dialog()
                    dlg.exec_()
                    self.methodsDict[dlg.chosen]()

    def saveMask(self):
        dlg = QInputDialog()
        dlg.setModal(True)
        text, okPressed = dlg.getText(None, "类别标记", "输入该样本类别名:",
                                      QLineEdit.Normal, "")
        while text == '':
            QMessageBox.warning(None, '输入警告', '未输入任何内容!')
            text, okPressed = dlg.getText(None, "类别标记", "输入该样本类别名:",
                                          QLineEdit.Normal, "")
        if okPressed:
            self.chooseComplete = False
            color = QColorDialog.getColor()
            maskLayer = QgsVectorLayer("Polygon", "clip_mask", "memory")
            maskLayer.setCrs(self.rasterlayer.crs())
            pr = maskLayer.dataProvider()  # type:QgsVectorDataProvider
            pr.addAttributes([QgsField("类别名", QVariant.String)])
            maskLayer.updateFields()
            fet = QgsFeature()
            print(self.rubberBand.asGeometry())
            fet.setGeometry(self.rubberBand.asGeometry())
            fet.setAttributes([text])
            pr.addFeatures([fet])
            maskLayer.updateExtents()
            maskFile = f'mask/{text}_clip_mask.shp'
            if os.path.exists(maskFile):
                os.remove(maskFile)  # 文件存在的话就替换一下
            QgsVectorFileWriter.writeAsVectorFormat(
                layer=maskLayer,
                fileName=maskFile,
                fileEncoding='utf-8',
                destCRS=self.rasterlayer.crs(),
                driverName="ESRI Shapefile")
            self.categories.append({"name": text, "color": color})

    def MinDistance(self):
        count_categories = len(self.categories)  # 类别数
        raster_source = self.rasterlayer.dataProvider().dataSourceUri(
        )  # 源图像地址
        raster_dataset = gdal.Open(raster_source)  # type:gdal.Dataset
        bandCount = raster_dataset.RasterCount
        raster_arr = raster_dataset.ReadAsArray()
        all_md = np.zeros(shape=(count_categories, raster_arr.shape[1],
                                 raster_arr.shape[2]),
                          dtype=np.float64)
        for i in range(count_categories):
            category = self.categories[i]
            path = f'samples/{category["name"]}.tif'
            dataset_arr = gdal.Open(path).ReadAsArray()
            mask = np.all(dataset_arr == 0, axis=0)
            pixels = dataset_arr[:, ~mask]  # type:np.ndarray
            # shape of pixels:(bandCount,number of sample pixels)
            mean = np.mean(pixels, axis=1)
            # shape of mean:(bandCount,)
            raster_arr_minus_mean = raster_arr - mean.reshape(bandCount, 1, 1)
            md = (raster_arr_minus_mean**2).sum(axis=0)
            all_md[i, :, :] = md
        min_md = np.argmin(all_md, axis=0)
        classification_result = np.zeros(shape=(min_md.shape[0],
                                                min_md.shape[1], 3),
                                         dtype=np.int)
        for i in range(min_md.shape[0]):
            for j in range(min_md.shape[1]):
                classification_result[i, j, :] = self.categories[min_md[
                    i, j]]["color"].getRgb()[:3]
        driver = gdal.GetDriverByName('GTiff')
        save_path, format = QFileDialog.getSaveFileName(
            None, '存储分类结果', '', '*.tif')
        out_ds = driver.Create(save_path, raster_dataset.RasterXSize,
                               raster_dataset.RasterYSize, 3, gdal.GDT_Byte)
        out_ds.SetProjection(raster_dataset.GetProjection())
        out_ds.SetGeoTransform(raster_dataset.GetGeoTransform())
        for i in range(3):
            out_band = out_ds.GetRasterBand(i + 1)
            out_band.WriteArray(classification_result[:, :, i])
            out_band.ComputeStatistics(False)
        out_ds.FlushCache()
        self.mainWindow.loadMap(save_path, self.categories)

    def MaxLikelihood(self):
        count_categories = len(self.categories)  # 类别数
        raster_source = self.rasterlayer.dataProvider().dataSourceUri(
        )  # 源图像地址
        raster_dataset = gdal.Open(raster_source)  # type:gdal.Dataset
        bandCount = raster_dataset.RasterCount
        raster_arr = raster_dataset.ReadAsArray()
        all_md = np.zeros(shape=(count_categories, raster_arr.shape[1],
                                 raster_arr.shape[2]),
                          dtype=np.float64)
        for i in range(count_categories):
            category = self.categories[i]
            path = f'samples/{category["name"]}.tif'
            dataset_arr = gdal.Open(path).ReadAsArray()
            mask = np.all(dataset_arr == 0, axis=0)
            pixels = dataset_arr[:, ~mask]  # type:np.ndarray
            # shape of pixels:(bandCount,number of sample pixels)
            cov = np.cov(m=pixels, rowvar=True, bias=False)
            # shape of cov:(bandCount,bandCount)
            mean = np.mean(pixels, axis=1)
            # shape of mean:(bandCount,)
            raster_arr_minus_mean = raster_arr - mean.reshape(bandCount, 1, 1)
            tmp = np.tensordot(np.linalg.inv(cov),
                               raster_arr_minus_mean,
                               axes=[[1], [0]])
            md = (tmp * raster_arr_minus_mean).sum(axis=0) * (-0.5)
            all_md[i, :, :] = md
        max_md = np.argmax(all_md, axis=0)
        classification_result = np.zeros(shape=(max_md.shape[0],
                                                max_md.shape[1], 3),
                                         dtype=np.int)
        for i in range(max_md.shape[0]):
            for j in range(max_md.shape[1]):
                classification_result[i, j, :] = self.categories[max_md[
                    i, j]]["color"].getRgb()[:3]
        driver = gdal.GetDriverByName('GTiff')
        save_path, format = QFileDialog.getSaveFileName(
            None, '存储分类结果', '', '*.tif')
        out_ds = driver.Create(save_path, raster_dataset.RasterXSize,
                               raster_dataset.RasterYSize, 3, gdal.GDT_Byte)
        out_ds.SetProjection(raster_dataset.GetProjection())
        out_ds.SetGeoTransform(raster_dataset.GetGeoTransform())
        for i in range(3):
            out_band = out_ds.GetRasterBand(i + 1)
            out_band.WriteArray(classification_result[:, :, i])
            out_band.ComputeStatistics(False)
        out_ds.FlushCache()
        self.mainWindow.loadMap(save_path, self.categories)

    def Mahalanobis(self):
        count_categories = len(self.categories)  # 类别数
        raster_source = self.rasterlayer.dataProvider().dataSourceUri(
        )  # 源图像地址
        raster_dataset = gdal.Open(raster_source)  # type:gdal.Dataset
        bandCount = raster_dataset.RasterCount
        raster_arr = raster_dataset.ReadAsArray()
        all_md = np.zeros(shape=(count_categories, raster_arr.shape[1],
                                 raster_arr.shape[2]),
                          dtype=np.float64)
        for i in range(count_categories):
            category = self.categories[i]
            path = f'samples/{category["name"]}.tif'
            dataset_arr = gdal.Open(path).ReadAsArray()
            mask = np.all(dataset_arr == 0, axis=0)
            pixels = dataset_arr[:, ~mask]  # type:np.ndarray
            # shape of pixels:(bandCount,number of sample pixels)
            cov = np.cov(m=pixels, rowvar=True, bias=False)
            # shape of cov:(bandCount,bandCount)
            mean = np.mean(pixels, axis=1)
            # shape of mean:(bandCount,)
            raster_arr_minus_mean = raster_arr - mean.reshape(bandCount, 1, 1)
            tmp = np.tensordot(np.linalg.inv(cov),
                               raster_arr_minus_mean,
                               axes=[[1], [0]])
            md = (tmp * raster_arr_minus_mean).sum(axis=0)
            all_md[i, :, :] = md
        min_md = np.argmin(all_md, axis=0)
        classification_result = np.zeros(shape=(min_md.shape[0],
                                                min_md.shape[1], 3),
                                         dtype=np.int)
        for i in range(min_md.shape[0]):
            for j in range(min_md.shape[1]):
                classification_result[i, j, :] = self.categories[min_md[
                    i, j]]["color"].getRgb()[:3]
        driver = gdal.GetDriverByName('GTiff')
        save_path, format = QFileDialog.getSaveFileName(
            None, '存储分类结果', '', '*.tif')
        out_ds = driver.Create(save_path, raster_dataset.RasterXSize,
                               raster_dataset.RasterYSize, 3, gdal.GDT_Byte)
        out_ds.SetProjection(raster_dataset.GetProjection())
        out_ds.SetGeoTransform(raster_dataset.GetGeoTransform())
        for i in range(3):
            out_band = out_ds.GetRasterBand(i + 1)
            out_band.WriteArray(classification_result[:, :, i])
            out_band.ComputeStatistics(False)
        out_ds.FlushCache()
        self.mainWindow.loadMap(save_path, self.categories)

    def SVM(self):
        count_categories = len(self.categories)
        X = []
        Y = []
        for i in range(count_categories):
            category = self.categories[i]
            path = f'samples/{category["name"]}.tif'
            dataset_arr = gdal.Open(path).ReadAsArray()
            mask = np.all(dataset_arr == 0, axis=0)
            pixels = dataset_arr[:, ~mask]  # type:np.ndarray
            X.append(pixels)
            Y.append([i] * pixels.shape[1])
        X = np.concatenate(X, axis=1)
        Y = np.concatenate(Y)
        # clf = svm.SVC(decision_function_shape='ovo',C=1,kernel='rbf',degree=3,gamma='auto')
        clf = svm.SVC(decision_function_shape='ovo')
        time_start = time.time()
        clf.fit(X.transpose(), Y)
        time_end = time.time()
        print("totally cost", time_end - time_start)
        raster_source = self.rasterlayer.dataProvider().dataSourceUri()
        raster_dataset = gdal.Open(raster_source)  # type:gdal.Dataset
        raster_arr = raster_dataset.ReadAsArray()
        row = raster_arr.shape[1]
        col = raster_arr.shape[2]
        classification_result = np.zeros(shape=(row, col, 3))
        predicts = clf.predict(
            raster_arr.reshape((raster_arr.shape[0], -1)).transpose())
        for i in range(row):
            for j in range(col):
                classification_result[i, j, :] = self.categories[predicts[
                    i * col + j]]['color'].getRgb()[:3]
        driver = gdal.GetDriverByName('GTiff')
        save_path, format = QFileDialog.getSaveFileName(
            None, '存储分类结果', '', '*.tif')
        out_ds = driver.Create(save_path, raster_dataset.RasterXSize,
                               raster_dataset.RasterYSize, 3, gdal.GDT_Byte)
        out_ds.SetProjection(raster_dataset.GetProjection())
        out_ds.SetGeoTransform(raster_dataset.GetGeoTransform())
        for i in range(3):
            out_band = out_ds.GetRasterBand(i + 1)
            out_band.WriteArray(classification_result[:, :, i])
            out_band.ComputeStatistics(False)
        out_ds.FlushCache()
        self.mainWindow.loadMap(save_path, self.categories)

    def ANN(self):
        count_categories = len(self.categories)
        raster_source = self.rasterlayer.dataProvider().dataSourceUri()
        raster_dataset = gdal.Open(raster_source)  # type:gdal.Dataset
        raster_arr = raster_dataset.ReadAsArray()
        row = raster_arr.shape[1]
        col = raster_arr.shape[2]
        mean = np.mean(raster_arr, axis=(1, 2))
        sigma = np.std(raster_arr, axis=(1, 2))
        raster_arr = (raster_arr - mean.reshape(
            mean.shape[0], 1, 1)) / sigma.reshape(sigma.shape[0], 1, 1)
        X = []
        Y = []
        for i in range(count_categories):
            category = self.categories[i]
            path = f'samples/{category["name"]}.tif'
            dataset_arr = gdal.Open(path).ReadAsArray()
            mask = np.all(dataset_arr == 0, axis=0)
            pixels = dataset_arr[:, ~mask]  # type:np.ndarray
            X.append(pixels)
            Y.append([i] * pixels.shape[1])
        X = np.concatenate(X, axis=1)
        Y = np.concatenate(Y)
        X = (X - mean.reshape(mean.shape[0], 1)) / sigma.reshape(
            sigma.shape[0], 1)  # 标准化
        clf = MLPClassifier(solver='adam',
                            alpha=1e-5,
                            hidden_layer_sizes=(30, 30),
                            shuffle=True,
                            random_state=1)
        time_start = time.time()
        clf.fit(X.transpose(), Y)
        time_end = time.time()
        print("totally cost", time_end - time_start)
        classification_result = np.zeros(shape=(row, col, 3))
        predicts = clf.predict(
            raster_arr.reshape((raster_arr.shape[0], -1)).transpose())
        for i in range(row):
            for j in range(col):
                classification_result[i, j, :] = self.categories[predicts[
                    i * col + j]]['color'].getRgb()[:3]
        driver = gdal.GetDriverByName('GTiff')
        save_path, format = QFileDialog.getSaveFileName(
            None, '存储分类结果', '', '*.tif')
        out_ds = driver.Create(save_path, raster_dataset.RasterXSize,
                               raster_dataset.RasterYSize, 3, gdal.GDT_Byte)
        out_ds.SetProjection(raster_dataset.GetProjection())
        out_ds.SetGeoTransform(raster_dataset.GetGeoTransform())
        for i in range(3):
            out_band = out_ds.GetRasterBand(i + 1)
            out_band.WriteArray(classification_result[:, :, i])
            out_band.ComputeStatistics(False)
        out_ds.FlushCache()
        self.mainWindow.loadMap(save_path, self.categories)

    def RandomForest(self):
        count_categories = len(self.categories)
        X = []
        Y = []
        for i in range(count_categories):
            category = self.categories[i]
            path = f'samples/{category["name"]}.tif'
            dataset_arr = gdal.Open(path).ReadAsArray()
            mask = np.all(dataset_arr == 0, axis=0)
            pixels = dataset_arr[:, ~mask]  # type:np.ndarray
            X.append(pixels)
            Y.append([i] * pixels.shape[1])
        X = np.concatenate(X, axis=1)
        Y = np.concatenate(Y)
        clf = RandomForestClassifier()
        time_start = time.time()
        clf.fit(X.transpose(), Y)
        time_end = time.time()
        print("totally cost", time_end - time_start)
        raster_source = self.rasterlayer.dataProvider().dataSourceUri()
        raster_dataset = gdal.Open(raster_source)  # type:gdal.Dataset
        raster_arr = raster_dataset.ReadAsArray()
        row = raster_arr.shape[1]
        col = raster_arr.shape[2]
        classification_result = np.zeros(shape=(row, col, 3))
        predicts = clf.predict(
            raster_arr.reshape((raster_arr.shape[0], -1)).transpose())
        for i in range(row):
            for j in range(col):
                classification_result[i, j, :] = self.categories[predicts[
                    i * col + j]]['color'].getRgb()[:3]
        driver = gdal.GetDriverByName('GTiff')
        save_path, format = QFileDialog.getSaveFileName(
            None, '存储分类结果', '', '*.tif')
        out_ds = driver.Create(save_path, raster_dataset.RasterXSize,
                               raster_dataset.RasterYSize, 3, gdal.GDT_Byte)
        out_ds.SetProjection(raster_dataset.GetProjection())
        out_ds.SetGeoTransform(raster_dataset.GetGeoTransform())
        for i in range(3):
            out_band = out_ds.GetRasterBand(i + 1)
            out_band.WriteArray(classification_result[:, :, i])
            out_band.ComputeStatistics(False)
        out_ds.FlushCache()
        self.mainWindow.loadMap(save_path, self.categories)

    def AdaBoost(self):
        count_categories = len(self.categories)
        X = []
        Y = []
        for i in range(count_categories):
            category = self.categories[i]
            path = f'samples/{category["name"]}.tif'
            dataset_arr = gdal.Open(path).ReadAsArray()
            mask = np.all(dataset_arr == 0, axis=0)
            pixels = dataset_arr[:, ~mask]  # type:np.ndarray
            X.append(pixels)
            Y.append([i] * pixels.shape[1])
        X = np.concatenate(X, axis=1)
        Y = np.concatenate(Y)
        clf = AdaBoostClassifier(n_estimators=50, random_state=0)
        time_start = time.time()
        clf.fit(X.transpose(), Y)
        time_end = time.time()
        print("totally cost", time_end - time_start)
        raster_source = self.rasterlayer.dataProvider().dataSourceUri()
        raster_dataset = gdal.Open(raster_source)  # type:gdal.Dataset
        raster_arr = raster_dataset.ReadAsArray()
        row = raster_arr.shape[1]
        col = raster_arr.shape[2]
        classification_result = np.zeros(shape=(row, col, 3))
        predicts = clf.predict(
            raster_arr.reshape((raster_arr.shape[0], -1)).transpose())
        for i in range(row):
            for j in range(col):
                classification_result[i, j, :] = self.categories[predicts[
                    i * col + j]]['color'].getRgb()[:3]
        driver = gdal.GetDriverByName('GTiff')
        save_path, format = QFileDialog.getSaveFileName(
            None, '存储分类结果', '', '*.tif')
        out_ds = driver.Create(save_path, raster_dataset.RasterXSize,
                               raster_dataset.RasterYSize, 3, gdal.GDT_Byte)
        out_ds.SetProjection(raster_dataset.GetProjection())
        out_ds.SetGeoTransform(raster_dataset.GetGeoTransform())
        for i in range(3):
            out_band = out_ds.GetRasterBand(i + 1)
            out_band.WriteArray(classification_result[:, :, i])
            out_band.ComputeStatistics(False)
        out_ds.FlushCache()
        self.mainWindow.loadMap(save_path, self.categories)

    def deactivate(self):
        super(PolygonMapTool, self).deactivate()
        self.deactivated.emit()
        self.reset()
Example #35
0
class RectangleMapTool(QgsMapToolEmitPoint):
    def __init__(self, canvas):
        self.canvas = canvas
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon)
        self.rubberBand.setColor(QColor(255, 0, 0, 180))
        self.rubberBand.setWidth(1)
        self.reset()

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBand.reset(QGis.Polygon)

    def canvasPressEvent(self, e):
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True
        self.showRect(self.startPoint, self.endPoint)

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False
        self.emit(SIGNAL("rectangleCreated()"))

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return
        self.endPoint = self.toMapCoordinates(e.pos())
        self.showRect(self.startPoint, self.endPoint)

    def showRect(self, startPoint, endPoint):
        self.rubberBand.reset(QGis.Polygon)
        if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
            return

        point1 = QgsPoint(startPoint.x(), startPoint.y())
        point2 = QgsPoint(startPoint.x(), endPoint.y())
        point3 = QgsPoint(endPoint.x(), endPoint.y())
        point4 = QgsPoint(endPoint.x(), startPoint.y())

        self.rubberBand.addPoint(point1, False)
        self.rubberBand.addPoint(point2, False)
        self.rubberBand.addPoint(point3, False)
        self.rubberBand.addPoint(point4, True)  # true to update canvas
        self.rubberBand.show()

    def rectangle(self):
        if self.startPoint == None or self.endPoint == None:
            return None
        #elif self.startPoint.x() == self.endPoint.x() or self.startPoint.y() == self.endPoint.y():
        #  return None

        return QgsRectangle(self.startPoint, self.endPoint)

    def setRectangle(self, rect):
        if rect == self.rectangle():
            return False

        if rect == None:
            self.reset()
        else:
            self.startPoint = QgsPoint(rect.xMaximum(), rect.yMaximum())
            self.endPoint = QgsPoint(rect.xMinimum(), rect.yMinimum())
            self.showRect(self.startPoint, self.endPoint)
        return True
Example #36
0
class GeodesicMeasureDialog(QDialog, FORM_CLASS):
    def __init__(self, iface, parent):
        super(GeodesicMeasureDialog, self).__init__(parent)
        self.setupUi(self)
        self.iface = iface
        self.canvas = iface.mapCanvas()
        settings = QSettings()

        self.restoreGeometry(
            settings.value("ShapeTools/MeasureDialogGeometry",
                           QByteArray(),
                           type=QByteArray))
        self.closeButton.clicked.connect(self.closeDialog)
        self.newButton.clicked.connect(self.newDialog)
        self.saveToLayerButton.clicked.connect(self.saveToLayer)
        self.saveToLayerButton.setEnabled(False)

        self.unitsComboBox.addItems(UNITS)

        self.tableWidget.setColumnCount(3)
        self.tableWidget.setSortingEnabled(False)
        self.tableWidget.setHorizontalHeaderLabels(
            ['Heading To', 'Heading From', 'Distance'])

        self.unitsComboBox.activated.connect(self.unitsChanged)

        self.capturedPoints = []
        self.distances = []
        self.geod = Geodesic.WGS84
        self.activeMeasuring = True
        self.unitsChanged()
        self.currentDistance = 0.0

        color = QColor(222, 167, 67, 150)
        self.pointRb = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry)
        self.pointRb.setColor(color)
        self.pointRb.setIconSize(10)
        self.lineRb = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.lineRb.setColor(color)
        self.lineRb.setWidth(3)
        self.tempRb = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.tempRb.setColor(color)
        self.tempRb.setWidth(3)

    def ready(self):
        return self.activeMeasuring

    def stop(self):
        self.activeMeasuring = False

    def closeEvent(self, event):
        self.closeDialog()

    def closeDialog(self):
        self.clear()
        QSettings().setValue("ShapeTools/MeasureDialogGeometry",
                             self.saveGeometry())
        self.close()

    def newDialog(self):
        self.clear()

    def unitsChanged(self):
        label = "Distance [{}]".format(
            UNITS[self.unitsComboBox.currentIndex()])
        item = QTableWidgetItem(label)
        self.tableWidget.setHorizontalHeaderItem(2, item)
        ptcnt = len(self.capturedPoints)
        if ptcnt >= 2:
            i = 0
            while i < ptcnt - 1:
                item = QTableWidgetItem('{:.4f}'.format(
                    self.unitDistance(self.distances[i])))
                self.tableWidget.setItem(i, 2, item)
                i += 1
            self.formatTotal()

    def motionReady(self):
        if len(self.capturedPoints) > 0 and self.activeMeasuring:
            return True
        return False

    def addPoint(self, pt, button):
        self.currentDistance = 0
        index = len(self.capturedPoints)
        if index > 0 and pt == self.capturedPoints[index - 1]:
            # the clicked point is the same as the previous so just ignore it
            return
        self.capturedPoints.append(pt)
        # Add rubber band points
        canvasCrs = self.canvas.mapSettings().destinationCrs()
        transform = QgsCoordinateTransform(epsg4326, canvasCrs,
                                           QgsProject.instance())
        ptCanvas = transform.transform(pt.x(), pt.y())
        self.pointRb.addPoint(ptCanvas, True)
        # If there is more than 1 point add it to the table
        if index > 0:
            self.saveToLayerButton.setEnabled(True)
            (distance, startAngle,
             endAngle) = self.calcParameters(self.capturedPoints[index - 1],
                                             self.capturedPoints[index])
            self.distances.append(distance)
            self.insertParams(index, distance, startAngle, endAngle)
            # Add Rubber Band Line
            linePts = self.getLinePts(distance, self.capturedPoints[index - 1],
                                      self.capturedPoints[index])
            self.lineRb.addGeometry(QgsGeometry.fromPolylineXY(linePts), None)
        self.formatTotal()

    def inMotion(self, pt):
        index = len(self.capturedPoints)
        if index <= 0:
            return
        (self.currentDistance, startAngle,
         endAngle) = self.calcParameters(self.capturedPoints[index - 1], pt)
        self.insertParams(index, self.currentDistance, startAngle, endAngle)
        self.formatTotal()
        linePts = self.getLinePts(self.currentDistance,
                                  self.capturedPoints[index - 1], pt)
        self.tempRb.setToGeometry(QgsGeometry.fromPolylineXY(linePts), None)

    def calcParameters(self, pt1, pt2):
        l = self.geod.Inverse(pt1.y(), pt1.x(), pt2.y(), pt2.x())
        az2 = (l['azi2'] + 180) % 360.0
        if az2 > 180:
            az2 = az2 - 360.0
        l2 = self.geod.Inverse(pt2.y(), pt2.x(), pt1.y(), pt1.x())
        return (l['s12'], l['azi1'], az2)

    def getLinePts(self, distance, pt1, pt2):
        canvasCrs = self.canvas.mapSettings().destinationCrs()
        transform = QgsCoordinateTransform(epsg4326, canvasCrs,
                                           QgsProject.instance())
        pt1c = transform.transform(pt1.x(), pt1.y())
        pt2c = transform.transform(pt2.x(), pt2.y())
        if distance < 10000:
            return [pt1c, pt2c]
        l = self.geod.InverseLine(pt1.y(), pt1.x(), pt2.y(), pt2.x())
        n = int(math.ceil(distance / 10000.0))
        if n > 20:
            n = 20
        seglen = distance / n
        pts = [pt1c]
        for i in range(1, n):
            s = seglen * i
            g = l.Position(
                s,
                Geodesic.LATITUDE | Geodesic.LONGITUDE | Geodesic.LONG_UNROLL)
            ptc = transform.transform(g['lon2'], g['lat2'])
            pts.append(ptc)
        pts.append(pt2c)
        return pts

    def saveToLayer(self):
        units = self.unitDesignator()
        canvasCrs = self.canvas.mapSettings().destinationCrs()
        fields = QgsFields()
        fields.append(QgsField("label", QVariant.String))
        fields.append(QgsField("value", QVariant.Double))
        fields.append(QgsField("units", QVariant.String))
        fields.append(QgsField("heading_to", QVariant.Double))
        fields.append(QgsField("heading_from", QVariant.Double))

        layer = QgsVectorLayer("LineString?crs={}".format(canvasCrs.authid()),
                               "Measurements", "memory")
        dp = layer.dataProvider()
        dp.addAttributes(fields)
        layer.updateFields()

        num = len(self.capturedPoints)
        for i in range(1, num):
            (distance, startA,
             endA) = self.calcParameters(self.capturedPoints[i - 1],
                                         self.capturedPoints[i])
            pts = self.getLinePts(distance, self.capturedPoints[i - 1],
                                  self.capturedPoints[i])
            distance = self.unitDistance(distance)
            feat = QgsFeature(layer.fields())
            feat.setAttribute(0, "{:.2f} {}".format(distance, units))
            feat.setAttribute(1, distance)
            feat.setAttribute(2, units)
            feat.setAttribute(3, startA)
            feat.setAttribute(4, endA)
            feat.setGeometry(QgsGeometry.fromPolylineXY(pts))
            dp.addFeatures([feat])

        label = QgsPalLayerSettings()
        label.fieldName = 'label'
        label.placement = QgsPalLayerSettings.AboveLine
        labeling = QgsVectorLayerSimpleLabeling(label)
        layer.setLabeling(labeling)
        layer.setLabelsEnabled(True)

        layer.updateExtents()
        QgsProject.instance().addMapLayer(layer)

    def insertParams(self, position, distance, startAngle, endAngle):
        if position > self.tableWidget.rowCount():
            self.tableWidget.insertRow(position - 1)
        item = QTableWidgetItem('{:.4f}'.format(self.unitDistance(distance)))
        item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        self.tableWidget.setItem(position - 1, 2, item)
        item = QTableWidgetItem('{:.4f}'.format(startAngle))
        item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        self.tableWidget.setItem(position - 1, 0, item)
        item = QTableWidgetItem('{:.4f}'.format(endAngle))
        item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        self.tableWidget.setItem(position - 1, 1, item)

    def formatTotal(self):
        total = self.currentDistance
        ptcnt = len(self.capturedPoints)
        if ptcnt >= 2:
            i = 0
            while i < ptcnt - 1:
                total += self.distances[i]
                i += 1
        self.distanceLineEdit.setText('{:.2f}'.format(
            self.unitDistance(total)))

    def clear(self):
        self.tableWidget.setRowCount(0)
        self.capturedPoints = []
        self.distances = []
        self.activeMeasuring = True
        self.currentDistance = 0.0
        self.distanceLineEdit.setText('')
        self.pointRb.reset(QgsWkbTypes.PointGeometry)
        self.lineRb.reset(QgsWkbTypes.LineGeometry)
        self.tempRb.reset(QgsWkbTypes.LineGeometry)
        self.saveToLayerButton.setEnabled(False)

    def unitDistance(self, distance):
        units = self.unitsComboBox.currentIndex()
        if units == 0:  # meters
            return distance
        elif units == 1:  # kilometers
            return distance / 1000.0
        elif units == 2:  # feet
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceFeet)
        elif units == 3:  # yards
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceYards)
        elif units == 4:  # miles
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceMiles)
        else:  # nautical miles
            return distance * QgsUnitTypes.fromUnitToUnitFactor(
                QgsUnitTypes.DistanceMeters,
                QgsUnitTypes.DistanceNauticalMiles)

    def unitDesignator(self):
        units = self.unitsComboBox.currentIndex()
        if units == 0:  # meters
            return 'm'
        elif units == 1:  # kilometers
            return 'km'
        elif units == 2:  # feet
            return 'ft'
        elif units == 3:  # yards
            return 'yd'
        elif units == 4:  # miles
            return 'mi'
        else:  # nautical miles
            return 'nm'
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 #38
0
class VideoWidget(QVideoWidget):

    def __init__(self, parent=None):
        ''' Constructor '''
        super(VideoWidget, self).__init__(parent)
        self.surface = VideoWidgetSurface(self)
        self.Tracking_RubberBand = QRubberBand(QRubberBand.Rectangle, self)

        self.Censure_RubberBand = QRubberBand(QRubberBand.Rectangle, self)

        pal = QPalette()
        pal.setBrush(QPalette.Highlight, QBrush(QColor(Qt.blue)))
        self.Tracking_RubberBand.setPalette(pal)

        pal = QPalette()
        pal.setBrush(QPalette.Highlight, QBrush(QColor(Qt.black)))
        self.Censure_RubberBand.setPalette(pal)

        self.var_currentMouseMoveEvent = None

        self._interaction = InteractionState()
        self._filterSatate = FilterState()

        self.setUpdatesEnabled(True)
        self.snapped = False
        self.zoomed = False
        self._isinit = False
        self.gt = None

        self.drawCesure = []
        self.poly_coordinates, self.drawPtPos, self.drawLines, self.drawRuler, self.drawPolygon = [], [], [], [], []
        self.poly_RubberBand = QgsRubberBand(
            iface.mapCanvas(), True)  # Polygon type
        # set rubber band style
        color = QColor(176, 255, 128)
        self.poly_RubberBand.setColor(color)
        color.setAlpha(190)
        self.poly_RubberBand.setStrokeColor(color)
        self.poly_RubberBand.setWidth(3)

        self.parent = parent.parent()

        self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)

        self.setAttribute(Qt.WA_NoSystemBackground)
        self.setAttribute(Qt.WA_PaintOnScreen)
        self.setAttribute(Qt.WA_OpaquePaintEvent)
        self.setAttribute(Qt.WA_DeleteOnClose)
        palette = self.palette()
        palette.setColor(QPalette.Background, Qt.black)
        self.setPalette(palette)
        self.setSizePolicy(QSizePolicy.MinimumExpanding,
                           QSizePolicy.MinimumExpanding)

        self.offset, self.origin, self.pressPos, self.dragPos = QPoint(
        ), QPoint(), QPoint(), QPoint()
        self.tapTimer = QBasicTimer()
        self.zoomPixmap, self.maskPixmap = QPixmap(), QPixmap()

    def removeLastLine(self):
        ''' Remove Last Line Objects '''
        if len(self.drawLines) > 0:
            for pt in range(len(self.drawLines) - 1, -1, -1):
                del self.drawLines[pt]
                try:
                    if self.drawLines[pt - 1][0] is None:
                        break
                except Exception:
                    None
            self.UpdateSurface()
            AddDrawLineOnMap(self.drawLines)
        return

    def removeLastSegmentLine(self):
        ''' Remove Last Segment Line Objects '''
        if len(self.drawLines) > 0:
            del self.drawLines[-1]
            self.UpdateSurface()
            AddDrawLineOnMap(self.drawLines)
        return

    def removeAllLines(self):
        ''' Resets Line List '''
        self.drawLines = []
        self.UpdateSurface()
        # Clear all Layer
        RemoveAllDrawLineOnMap()

    def ResetDrawRuler(self):
        ''' Resets Ruler List '''
        self.drawRuler = []

    def removeAllCensure(self):
        ''' Remove All Censure Objects '''
        self.drawCesure = []

    def removeLastCensured(self):
        ''' Remove Last Censure Objects '''
        if len(self.drawCesure) > 0:
            del self.drawCesure[-1]

    def removeLastPoint(self):
        ''' Remove All Point Drawer Objects '''
        if len(self.drawPtPos) > 0:
            del self.drawPtPos[-1]
            self.UpdateSurface()
            RemoveLastDrawPointOnMap()
        return

    def removeAllPoint(self):
        ''' Remove All Point Drawer Objects '''
        self.drawPtPos = []
        self.UpdateSurface()
        # Clear all Layer
        RemoveAllDrawPointOnMap()
        return

    def removeAllPolygon(self):
        ''' Remove All Polygon Drawer Objects '''
        self.drawPolygon = []
        self.UpdateSurface()
        # Clear all Layer
        RemoveAllDrawPolygonOnMap()

    def removeLastPolygon(self):
        ''' Remove Last Polygon Drawer Objects '''
        if len(self.drawPolygon) > 0:
            for pt in range(len(self.drawPolygon) - 1, -1, -1):
                del self.drawPolygon[pt]
                try:
                    if self.drawPolygon[pt - 1][0] is None:
                        break
                except Exception:
                    None
            self.UpdateSurface()
            # remove last index layer
            RemoveLastDrawPolygonOnMap()

    def currentMouseMoveEvent(self, event):
        self.var_currentMouseMoveEvent = event

    def keyPressEvent(self, event):
        ''' Exit fullscreen '''
        if event.key() == Qt.Key_Escape and self.isFullScreen():
            self.setFullScreen(False)
            event.accept()
        elif event.key() == Qt.Key_Enter and event.modifiers() & Qt.Key_Alt:
            self.setFullScreen(not self.isFullScreen())
            event.accept()
        else:
            super(VideoWidget, self).keyPressEvent(event)

    def mouseDoubleClickEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if GetImageHeight() == 0:
            return

        if(not vut.IsPointOnScreen(event.x(), event.y(), self.surface)):
            return

        if self.gt is not None and self._interaction.lineDrawer:
            self.drawLines.append([None, None, None])
            self.UpdateSurface()
            return
        if self.gt is not None and self._interaction.ruler:
            self.drawRuler.append([None, None, None])
            self.UpdateSurface()
            return
        if self.gt is not None and self._interaction.polygonDrawer:
            self.drawPolygon.append([None, None, None])

            AddDrawPolygonOnMap(self.poly_coordinates)

            # Empty RubberBand
            for _ in range(self.poly_RubberBand.numberOfVertices()):
                self.poly_RubberBand.removeLastPoint()
            # Empty List
            self.poly_coordinates = []
            self.UpdateSurface()
            return

        self.setFullScreen(not self.isFullScreen())
        event.accept()

    def videoSurface(self):
        ''' Return video Surface '''
        return self.surface

    def UpdateSurface(self):
        ''' Update Video Surface '''
        self.surface.widget.update()

    def sizeHint(self):
        ''' This property holds the recommended size for the widget '''
        return self.surface.surfaceFormat().sizeHint()

    def GetCurrentFrame(self):
        ''' Return current frame QImage '''
        return self.surface.image

    def SetInvertColor(self, value):
        ''' Set Invert color filter '''
        self._filterSatate.invertColorFilter = value

    def SetObjectTracking(self, value):
        ''' Set Object Tracking '''
        self._interaction.objectTracking = value

    def SetRuler(self, value):
        ''' Set Ruler '''
        self._interaction.ruler = value

    def SetCensure(self, value):
        ''' Set Censure Video Parts '''
        self._interaction.censure = value

    def SetGray(self, value):
        ''' Set gray scale '''
        self._filterSatate.grayColorFilter = value

    def SetMirrorH(self, value):
        ''' Set Horizontal Mirror '''
        self._filterSatate.MirroredHFilter = value

    def SetEdgeDetection(self, value):
        ''' Set Canny Edge filter '''
        self._filterSatate.edgeDetectionFilter = value

    def SetAutoContrastFilter(self, value):
        ''' Set Automatic Contrast filter '''
        self._filterSatate.contrastFilter = value

    def SetMonoFilter(self, value):
        ''' Set mono filter '''
        self._filterSatate.monoFilter = value

    def RestoreFilters(self):
        ''' Remove and restore all video filters '''
        self._filterSatate.clear()

    def RestoreDrawer(self):
        ''' Remove and restore all Drawer Options '''
        self._interaction.clear()

    def paintEvent(self, event):
        ''' Paint Event '''
        self.gt = GetGCPGeoTransform()

        self.painter = QPainter(self)
        self.painter.setRenderHint(QPainter.HighQualityAntialiasing)

        if (self.surface.isActive()):
            videoRect = self.surface.videoRect()
            if not videoRect.contains(event.rect()):
                region = event.region()
                region.subtracted(QRegion(videoRect))
                brush = self.palette().window()
                for rect in region.rects():
                    self.painter.fillRect(rect, brush)

            try:
                self.painter = self.surface.paint(self.painter)
            except Exception:
                None
        else:
            self.painter.fillRect(event.rect(), self.palette().window())
        try:
            SetImageSize(self.surface.currentFrame.width(),
                         self.surface.currentFrame.height())
        except Exception:
            None

        # Draw On Video
        draw.drawOnVideo(self.drawPtPos, self.drawLines, self.drawPolygon,
                         self.drawRuler, self.drawCesure, self.painter, self.surface, self.gt)

        # Magnifier Glass
        if self.zoomed and self._interaction.magnifier:
            draw.drawMagnifierOnVideo(self.width(), self.height(
            ), self.maskPixmap, self.dragPos, self.zoomPixmap, self.surface, self.painter, self.offset)

        self.painter.end()
        return

    def resizeEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        QWidget.resizeEvent(self, event)
        self.zoomed = False
        self.surface.updateVideoRect()

    def mouseMoveEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if GetImageHeight() == 0:
            return

        # check if the point  is on picture (not in black borders)
        if(not vut.IsPointOnScreen(event.x(), event.y(), self.surface)):
            return

        if self._interaction.pointDrawer or self._interaction.polygonDrawer or self._interaction.lineDrawer or self._interaction.ruler:
            self.setCursor(QCursor(Qt.CrossCursor))

        # Cursor Coordinates
        if self.gt is not None:

            Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                event, self.surface)

            txt = "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>"
            txt += "<span style='font-size:9pt; font-weight:normal;'>" + \
                ("%.3f" % Longitude) + "</span>"
            txt += "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>"
            txt += "<span style='font-size:9pt; font-weight:normal;'>" + \
                ("%.3f" % Latitude) + "</span>"

            if hasElevationModel():
                txt += "<span style='font-size:10pt; font-weight:bold;'> Alt :</span>"
                txt += "<span style='font-size:9pt; font-weight:normal;'>" + \
                    ("%.0f" % Altitude) + "</span>"
            else:
                txt += "<span style='font-size:10pt; font-weight:bold;'> Alt :</span>"
                txt += "<span style='font-size:9pt; font-weight:normal;'>-</span>"

            self.parent.lb_cursor_coord.setText(txt)

        else:
            self.parent.lb_cursor_coord.setText("<span style='font-size:10pt; font-weight:bold;'>Lon :</span>" +
                                                "<span style='font-size:9pt; font-weight:normal;'>-</span>" +
                                                "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>" +
                                                "<span style='font-size:9pt; font-weight:normal;'>-</span>" +
                                                "<span style='font-size:10pt; font-weight:bold;'> Alt :</span>" +
                                                "<span style='font-size:9pt; font-weight:normal;'>-</span>")

        if not event.buttons():
            return

        if not self.Tracking_RubberBand.isHidden():
            self.Tracking_RubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

        if not self.Censure_RubberBand.isHidden():
            self.Censure_RubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

        if not self.zoomed:
            delta = event.pos() - self.pressPos
            if not self.snapped:
                self.pressPos = event.pos()
                self.pan(delta)
                self.tapTimer.stop()
                return
            else:
                threshold = 10
                self.snapped &= delta.x() < threshold
                self.snapped &= delta.y() < threshold
                self.snapped &= delta.x() > -threshold
                self.snapped &= delta.y() > -threshold

        else:
            self.dragPos = event.pos()
            self.surface.updateVideoRect()

    def pan(self, delta):
        """ Pan Action (Magnifier method)"""
        self.offset += delta
        self.surface.updateVideoRect()

    def timerEvent(self, _):
        """ Time Event (Magnifier method)"""
        if not self.zoomed:
            self.activateMagnifier()
        self.surface.updateVideoRect()

    def mousePressEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if GetImageHeight() == 0:
            return

        if event.button() == Qt.LeftButton:
            self.snapped = True
            self.pressPos = self.dragPos = event.pos()
            self.tapTimer.stop()
            self.tapTimer.start(100, self)

            if(not vut.IsPointOnScreen(event.x(), event.y(), self.surface)):
                self.UpdateSurface()
                return

            # point drawer
            if self.gt is not None and self._interaction.pointDrawer:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)

                pointIndex = len(self.drawPtPos) + 1
                AddDrawPointOnMap(pointIndex, Longitude,
                                  Latitude, Altitude)

                self.drawPtPos.append([Longitude, Latitude, Altitude])

            # polygon drawer
            if self.gt is not None and self._interaction.polygonDrawer:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)
                self.poly_RubberBand.addPoint(QgsPointXY(Longitude, Latitude))
                self.poly_coordinates.extend(QgsPointXY(Longitude, Latitude))
                self.drawPolygon.append([Longitude, Latitude, Altitude])

            # line drawer
            if self.gt is not None and self._interaction.lineDrawer:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)

                self.drawLines.append([Longitude, Latitude, Altitude])

                AddDrawLineOnMap(self.drawLines)

            if self._interaction.objectTracking:
                self.origin = event.pos()
                self.Tracking_RubberBand.setGeometry(
                    QRect(self.origin, QSize()))
                self.Tracking_RubberBand.show()

            if self._interaction.censure:
                self.origin = event.pos()
                self.Censure_RubberBand.setGeometry(
                    QRect(self.origin, QSize()))
                self.Censure_RubberBand.show()

            # Ruler drawer
            if self.gt is not None and self._interaction.ruler:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)
                self.drawRuler.append([Longitude, Latitude, Altitude])

        # if not called, the paint event is not triggered.
        self.UpdateSurface()

    def activateMagnifier(self):
        """ Activate Magnifier Glass """
        self.zoomed = True
        self.tapTimer.stop()
        self.surface.updateVideoRect()

    def SetMagnifier(self, value):
        """ Set Magnifier Glass """
        self._interaction.magnifier = value

    def SetPointDrawer(self, value):
        """ Set Point Drawer """
        self._interaction.pointDrawer = value

    def SetLineDrawer(self, value):
        """ Set Line Drawer """
        self._interaction.lineDrawer = value

    def SetPolygonDrawer(self, value):
        """ Set Polygon Drawer """
        self._interaction.polygonDrawer = value

    def mouseReleaseEvent(self, _):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if self._interaction.censure:
            geom = self.Tracking_RubberBand.geometry()
            self.Censure_RubberBand.hide()
            self.drawCesure.append([geom])

        if self._interaction.objectTracking:
            geom = self.Tracking_RubberBand.geometry()
            bbox = (geom.x(), geom.y(), geom.width(), geom.height())
            frame = convertQImageToMat(self.GetCurrentFrame())
            self.Tracking_RubberBand.hide()
            self.tracker = cv2.TrackerBoosting_create()
            self.tracker.clear()
            ok = self.tracker.init(frame, bbox)
            if ok:
                self._isinit = True
            else:
                self._isinit = False

    def leaveEvent(self, _):
        self.parent.lb_cursor_coord.setText("")
        self.setCursor(QCursor(Qt.ArrowCursor))
Example #39
0
class RectangleMapTool(QgsMapToolEmitPoint):

  def __init__(self, canvas):
    QgsMapToolEmitPoint.__init__(self, canvas)

    self.canvas = canvas
    self.rubberBand = QgsRubberBand(canvas, QGis.Polygon)
    self.rubberBand.setColor(QColor(255, 0, 0, 180))
    self.rubberBand.setWidth(1)
    self.reset()

  def reset(self):
    self.startPoint = self.endPoint = None
    self.isDrawing = False
    self.rubberBand.reset(QGis.Polygon)

  def canvasPressEvent(self, e):
    self.startPoint = self.toMapCoordinates(e.pos())
    self.endPoint = self.startPoint

    mapSettings = self.canvas.mapSettings() if QGis.QGIS_VERSION_INT >= 20300 else self.canvas.mapRenderer()
    self.mupp = mapSettings.mapUnitsPerPixel()
    self.rotation = mapSettings.rotation() if QGis.QGIS_VERSION_INT >= 20700 else 0

    self.isDrawing = True
    self.showRect(self.startPoint, self.endPoint)

  def canvasReleaseEvent(self, e):
    self.isDrawing = False
    self.emit(SIGNAL("rectangleCreated()"))

  def canvasMoveEvent(self, e):
    if not self.isDrawing:
      return
    self.endPoint = self.toMapCoordinates(e.pos())
    self.showRect(self.startPoint, self.endPoint)

  def showRect(self, startPoint, endPoint):
    self.rubberBand.reset(QGis.Polygon)
    if startPoint.x() == endPoint.x() and startPoint.y() == endPoint.y():
      return

    for i, pt in enumerate(self._rect(startPoint, endPoint).vertices()):
      self.rubberBand.addPoint(pt, bool(i == 3))
    self.rubberBand.show()

  def _rect(self, startPoint, endPoint):
    if startPoint is None or endPoint is None:
      return None

    p0 = self.toCanvasCoordinates(startPoint)
    p1 = self.toCanvasCoordinates(endPoint)
    canvas_rect = QgsRectangle(QgsPoint(p0.x(), p0.y()), QgsPoint(p1.x(), p1.y()))
    center = QgsPoint((startPoint.x() + endPoint.x()) / 2, (startPoint.y() + endPoint.y()) / 2)
    return RotatedRect(center, self.mupp * canvas_rect.width(), self.mupp * canvas_rect.height()).rotate(self.rotation, center)

  def rectangle(self):
    return self._rect(self.startPoint, self.endPoint)

  def setRectangle(self, rect):
    if rect == self._rect(self.startPoint, self.endPoint):
      return False

    v = rect.vertices()
    self.startPoint = v[3]
    self.endPoint = v[1]
    self.showRect(self.startPoint, self.endPoint)
    return True
Example #40
0
class DsgLineTool(QgsMapTool):

    lineCreated = pyqtSignal(QgsGeometry)

    def __init__(self, canvas):
        super(DsgLineTool, self).__init__(canvas)
        
        self.canvas = canvas
        self.rubberBand = None
        self.reset()

    def deactivate(self):
        self.canvas.scene().removeItem(self.rubberBand)
        super(DsgLineTool, self).deactivate()
        
    def defineRubberBand(self):
        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):
        if self.rubberBand:
            self.rubberBand.reset(QGis.Line)
        self.isEmittingPoint = False
        self.defineRubberBand()

    def canvasPressEvent(self, e):
        if self.isEmittingPoint:
            point = self.snapPoint(e.pos())
            self.rubberBand.addPoint(point, True)
        else:
            self.reset()

        self.isEmittingPoint = True
        
    def canvasReleaseEvent(self, e):
        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):
        if not self.isEmittingPoint:
            return
        
        point = self.snapPoint(e.pos())
        self.rubberBand.movePoint(point)
        
    def snapPoint(self, p):
        m = self.canvas.snappingUtils().snapToMap(p)
        if m.isValid():
            return m.point()
        else:
            return self.canvas.getCoordinateTransform().toMapCoordinates(p)  
Example #41
0
class Qgis2threejsDialog(QDialog):
    STYLE_MAX_COUNT = 3

    def __init__(self, iface):
        QDialog.__init__(self, iface.mainWindow())
        self.iface = iface
        self.apiChanged22 = False  # not QgsApplication.prefixPath().startswith("C:/OSGeo4W")  # QGis.QGIS_VERSION_INT >= 20200

        # Set up the user interface from Designer.
        self.ui = ui = Ui_Qgis2threejsDialog()
        ui.setupUi(self)

        self.setWindowFlags(self.windowFlags() | Qt.WindowMinimizeButtonHint)
        ui.lineEdit_OutputFilename.setPlaceholderText("[Temporary file]")

        ui.pushButton_Run.clicked.connect(self.run)
        ui.pushButton_Close.clicked.connect(self.reject)

        # DEM tab
        ui.toolButton_switchFocusMode.setVisible(False)
        ui.toolButton_PointTool.setVisible(False)
        ui.progressBar.setVisible(False)
        self.switchFocusMode(True)

        ui.toolButton_Browse.clicked.connect(self.browseClicked)
        ui.radioButton_Simple.toggled.connect(self.samplingModeChanged)
        ui.horizontalSlider_Resolution.valueChanged.connect(
            self.calculateResolution)
        ui.spinBox_Height.valueChanged.connect(self.updateQuads)
        ui.toolButton_switchFocusMode.clicked.connect(
            self.switchFocusModeClicked)
        ui.toolButton_PointTool.clicked.connect(self.startPointSelection)

        # Vector tab
        ui.treeWidget_VectorLayers.setHeaderLabel("Vector layers")
        self.initVectorStyleWidgets()

        ui.treeWidget_VectorLayers.currentItemChanged.connect(
            self.currentVectorLayerChanged)
        ui.treeWidget_VectorLayers.itemChanged.connect(
            self.vectorLayerItemChanged)
        ui.comboBox_ObjectType.currentIndexChanged.connect(
            self.objectTypeSelectionChanged)

        self.bar = None
        self.localBrowsingMode = True
        self.rb_quads = self.rb_point = None
        self.currentVectorLayer = None
        self.vectorPropertiesDict = {}
        self.objectTypeManager = ObjectTypeManager()

        # set map tool
        self.previousMapTool = None
        self.mapTool = RectangleMapTool(iface.mapCanvas())
        self.connect(self.mapTool, SIGNAL("rectangleCreated()"),
                     self.rectangleSelected)
        #    self.mapTool = PointMapTool(iface.mapCanvas())
        #    QObject.connect(self.mapTool, SIGNAL("pointSelected()"), self.pointSelected)
        iface.mapCanvas().mapToolSet.connect(self.mapToolSet)
        self.startPointSelection()

    def exec_(self):
        ui = self.ui
        messages = []
        # show message if crs unit is degrees
        mapSettings = self.iface.mapCanvas().mapSettings(
        ) if self.apiChanged22 else self.iface.mapCanvas().mapRenderer()
        if mapSettings.destinationCrs().mapUnits() in [QGis.Degrees]:
            self.showMessageBar("The unit of current CRS is degrees",
                                "Terrain may not appear well.")

        # show message if there are no dem layer
        no_demlayer = ui.comboBox_DEMLayer.count() == 0
        ui.pushButton_Run.setEnabled(not no_demlayer)
        if no_demlayer:
            self.showMessageBar(
                "No DEM layer", "Load 1-band raster layer with GDAL provider.",
                QgsMessageBar.WARNING)

        return QDialog.exec_(self)

    def showMessageBar(self, title, text, level=QgsMessageBar.INFO):
        if self.bar is None:
            self.bar = QgsMessageBar()
            self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)

            ui = self.ui
            margins = ui.gridLayout.getContentsMargins()
            vl = ui.gridLayout.takeAt(0)
            ui.gridLayout.setContentsMargins(0, 0, 0, 0)
            ui.gridLayout.addWidget(self.bar, 0, 0)
            ui.gridLayout.addItem(vl, 1, 0)
            ui.verticalLayout.setContentsMargins(margins[0], margins[1] / 2,
                                                 margins[2], margins[3])
        self.bar.pushMessage(title, text, level=level)

    def initDEMLayerList(self, layerId=None):
        # list 1 band raster layers
        self.ui.comboBox_DEMLayer.clear()
        for id, layer in QgsMapLayerRegistry().instance().mapLayers().items():
            if layer.type() == QgsMapLayer.RasterLayer and layer.providerType(
            ) == "gdal" and layer.bandCount() == 1:
                self.ui.comboBox_DEMLayer.addItem(layer.name(), id)

        # select the last selected layer
        if layerId is not None:
            index = self.ui.comboBox_DEMLayer.findData(layerId)
            if index != -1:
                self.ui.comboBox_DEMLayer.setCurrentIndex(index)
            return index
        return -1

    def initVectorLayerTree(self, vectorPropertiesDict):
        self.vectorPropertiesDict = vectorPropertiesDict
        tree = self.ui.treeWidget_VectorLayers
        tree.clear()
        # add vector layers into tree widget
        self.treeTopItems = topItems = {
            QGis.Point: QTreeWidgetItem(tree, ["Point"]),
            QGis.Line: QTreeWidgetItem(tree, ["Line"]),
            QGis.Polygon: QTreeWidgetItem(tree, ["Polygon"])
        }
        self.vlItems = {}
        for layer in self.iface.legendInterface().layers():
            if layer.type() != QgsMapLayer.VectorLayer:
                continue
            geometry_type = layer.geometryType()
            if geometry_type in [QGis.Point, QGis.Line, QGis.Polygon]:
                self.vlItems[layer.id()] = item = QTreeWidgetItem(
                    topItems[geometry_type], [layer.name()])
                if layer.id() in self.vectorPropertiesDict:
                    isVisible = self.vectorPropertiesDict[
                        layer.id()]["visible"]
                else:
                    isVisible = False  #self.iface.legendInterface().isLayerVisible(layer)
                check_state = Qt.Checked if isVisible else Qt.Unchecked
                item.setData(0, Qt.CheckStateRole, check_state)
                item.setData(0, Qt.UserRole, layer.id())
                #item.setDisabled(True)
                #item.setData(0, Qt.CheckStateRole, Qt.Unchecked)

        for item in topItems.values():
            tree.expandItem(item)

        self.setVectorStylesEnabled(False)

    def initVectorStyleWidgets(self):
        self.colorWidget = StyleWidget(StyleWidget.COLOR)
        self.ui.verticalLayout_Styles.addWidget(self.colorWidget)
        self.heightWidget = StyleWidget(StyleWidget.HEIGHT)
        self.ui.verticalLayout_zCoordinate.addWidget(self.heightWidget)

        self.styleWidgets = []
        for i in range(self.STYLE_MAX_COUNT):
            widget = StyleWidget()
            widget.setVisible(False)
            self.ui.verticalLayout_Styles.addWidget(widget)
            self.styleWidgets.append(widget)

    def currentVectorLayerChanged(self, currentItem, previousItem):
        # save properties of previous item
        if previousItem is not None:
            layerid = previousItem.data(0, Qt.UserRole)
            if layerid is not None:
                self.saveVectorProperties(layerid)

        layerid = currentItem.data(0, Qt.UserRole)
        if layerid is None:
            self.currentVectorLayer = None
            return
        self.currentVectorLayer = layer = QgsMapLayerRegistry().instance(
        ).mapLayer(layerid)
        if layer is None:
            return

        for i in range(self.STYLE_MAX_COUNT):
            self.styleWidgets[i].hide()

        obj_types = self.objectTypeManager.objectTypeNames(
            layer.geometryType())
        ui = self.ui
        ui.comboBox_ObjectType.blockSignals(True)
        ui.comboBox_ObjectType.clear()
        ui.comboBox_ObjectType.addItems(obj_types)
        ui.comboBox_ObjectType.blockSignals(False)

        # set up property widgets
        self.objectTypeSelectionChanged()

        if layerid in self.vectorPropertiesDict:
            # restore properties
            self.restoreVectorProperties(layerid)

        self.setVectorStylesEnabled(
            currentItem.data(0, Qt.CheckStateRole) == Qt.Checked)

    def vectorLayerItemChanged(self, item, column):
        # update style form enablement
        currentItem = self.ui.treeWidget_VectorLayers.currentItem()
        if currentItem:
            self.setVectorStylesEnabled(
                currentItem.data(0, Qt.CheckStateRole) == Qt.Checked)

    def objectTypeSelectionChanged(self, idx=None):
        layer = self.currentVectorLayer
        try:
            ve = float(ui.lineEdit_zFactor.text())
        except:
            ve = 1
        mapTo3d = MapTo3D(self.iface.mapCanvas(), verticalExaggeration=ve)
        self.objectTypeManager.setupForm(
            self, mapTo3d, layer, layer.geometryType(),
            self.ui.comboBox_ObjectType.currentIndex())

    def numericFields(self, layer):
        # get attributes of a sample feature and create numeric field name list
        numeric_fields = []
        f = QgsFeature()
        layer.getFeatures().nextFeature(f)
        for field in f.fields():
            isNumeric = False
            try:
                float(f.attribute(field.name()))
                isNumeric = True
            except:
                pass
            if isNumeric:
                numeric_fields.append(field.name())
        return numeric_fields

    def setVectorStylesEnabled(self, enabled):
        self.ui.comboBox_ObjectType.setEnabled(enabled)
        self.ui.label_ObjectType.setEnabled(enabled)
        self.colorWidget.setEnabled(enabled)
        self.heightWidget.setEnabled(enabled)
        for i in range(self.STYLE_MAX_COUNT):
            self.styleWidgets[i].setEnabled(enabled)

    def saveVectorProperties(self, layerid):
        properties = {}
        layer = QgsMapLayerRegistry().instance().mapLayer(layerid)
        itemIndex = self.ui.comboBox_ObjectType.currentIndex()
        properties["itemindex"] = itemIndex
        properties["typeitem"] = self.objectTypeManager.objectTypeItem(
            layer.geometryType(), itemIndex)
        properties["visible"] = self.vlItems[
            self.currentVectorLayer.id()].data(0,
                                               Qt.CheckStateRole) == Qt.Checked
        properties["color"] = self.colorWidget.values()
        properties["height"] = self.heightWidget.values()
        for i in range(self.STYLE_MAX_COUNT):
            if self.styleWidgets[i].isVisible():
                properties[i] = self.styleWidgets[i].values()
        self.vectorPropertiesDict[layerid] = properties

    def restoreVectorProperties(self, layerid):
        properties = self.vectorPropertiesDict[layerid]
        self.ui.comboBox_ObjectType.setCurrentIndex(properties["itemindex"])
        self.colorWidget.setValues(properties["color"])
        self.heightWidget.setValues(properties["height"])
        for i in range(self.STYLE_MAX_COUNT):
            if i in properties:
                self.styleWidgets[i].setValues(properties[i])

    def calculateResolution(self, v=None):
        extent = self.iface.mapCanvas().extent()
        renderer = self.iface.mapCanvas().mapRenderer()
        size = 100 * self.ui.horizontalSlider_Resolution.value()
        self.ui.label_Resolution.setText("about {0} x {0} px".format(size))

        # calculate resolution and size
        width, height = renderer.width(), renderer.height()
        s = (size * size / float(width * height))**0.5
        if s < 1:
            width = int(width * s)
            height = int(height * s)

        xres = extent.width() / width
        yres = extent.height() / height
        self.ui.lineEdit_HRes.setText(str(xres))
        self.ui.lineEdit_VRes.setText(str(yres))
        self.ui.lineEdit_Width.setText(str(width + 1))
        self.ui.lineEdit_Height.setText(str(height + 1))

    def progress(self, percentage):
        self.ui.progressBar.setValue(percentage)
        self.ui.progressBar.setVisible(percentage != 100)

    def run(self):
        ui = self.ui
        filename = ui.lineEdit_OutputFilename.text()  # ""=Temporary file
        if filename != "" and QFileInfo(
                filename).exists() and QMessageBox.question(
                    None, "Qgis2threejs",
                    "Output file already exists. Overwrite it?",
                    QMessageBox.Ok | QMessageBox.Cancel) != QMessageBox.Ok:
            return
        self.endPointSelection()

        item = ui.treeWidget_VectorLayers.currentItem()
        if item:
            self.saveVectorProperties(item.data(0, Qt.UserRole))

        ui.pushButton_Run.setEnabled(False)
        self.progress(0)

        canvas = self.iface.mapCanvas()
        htmlfilename = ui.lineEdit_OutputFilename.text()
        demlayerid = ui.comboBox_DEMLayer.itemData(
            ui.comboBox_DEMLayer.currentIndex())
        mapTo3d = MapTo3D(canvas,
                          verticalExaggeration=float(
                              ui.lineEdit_zFactor.text()))
        if self.ui.radioButton_Simple.isChecked():
            dem_width = int(ui.lineEdit_Width.text())
            dem_height = int(ui.lineEdit_Height.text())
            context = OutputContext(mapTo3d, canvas, demlayerid,
                                    self.vectorPropertiesDict,
                                    self.objectTypeManager,
                                    self.localBrowsingMode, dem_width,
                                    dem_height)
            htmlfilename = runSimple(htmlfilename, context, self.progress)
        else:
            context = OutputContext(mapTo3d, canvas, demlayerid,
                                    self.vectorPropertiesDict,
                                    self.objectTypeManager,
                                    self.localBrowsingMode)
            htmlfilename = runAdvanced(htmlfilename, context, self,
                                       self.progress)
        self.progress(100)
        ui.pushButton_Run.setEnabled(True)
        if htmlfilename is None:
            return
        self.clearRubberBands()

        if not tools.openHTMLFile(htmlfilename):
            return
        QDialog.accept(self)

    def reject(self):
        self.endPointSelection()
        self.clearRubberBands()
        QDialog.reject(self)

    def startPointSelection(self):
        canvas = self.iface.mapCanvas()
        self.previousMapTool = canvas.mapTool()
        canvas.setMapTool(self.mapTool)
        self.ui.toolButton_PointTool.setVisible(False)

    def endPointSelection(self):
        self.mapTool.reset()
        self.iface.mapCanvas().setMapTool(self.previousMapTool)

    def rectangleSelected(self):
        ui = self.ui
        ui.radioButton_Advanced.setChecked(True)
        rect = self.mapTool.rectangle()
        toRect = rect.width() and rect.height()
        self.switchFocusMode(toRect)
        ui.lineEdit_xmin.setText(str(rect.xMinimum()))
        ui.lineEdit_ymin.setText(str(rect.yMinimum()))
        ui.lineEdit_xmax.setText(str(rect.xMaximum()))
        ui.lineEdit_ymax.setText(str(rect.yMaximum()))

        quadtree = QuadTree(self.iface.mapCanvas().extent())
        quadtree.buildTreeByRect(rect, self.ui.spinBox_Height.value())
        self.createRubberBands(quadtree.quads(), rect.center())
        self.setWindowState(self.windowState() & ~Qt.WindowMinimized
                            | Qt.WindowActive)

    def pointSelected(self):
        # set values of controls
        self.ui.lineEdit_CenterX.setText(str(self.mapTool.point.x()))
        self.ui.lineEdit_CenterY.setText(str(self.mapTool.point.y()))
        self.ui.radioButton_Advanced.setChecked(True)

        quadtree = QuadTree(self.iface.mapCanvas().extent(),
                            self.mapTool.point, self.ui.spinBox_Height.value())
        self.createRubberBands(quadtree.quads(), self.mapTool.point)
        self.setWindowState(self.windowState() & ~Qt.WindowMinimized
                            | Qt.WindowActive)

    def mapToolSet(self, mapTool):
        if mapTool != self.mapTool:
            self.ui.toolButton_PointTool.setVisible(True)

    def createQuadTree(self):
        ui = self.ui
        try:
            c = map(float, [
                ui.lineEdit_xmin.text(),
                ui.lineEdit_ymin.text(),
                ui.lineEdit_xmax.text(),
                ui.lineEdit_ymax.text()
            ])
        except:
            return None
        quadtree = QuadTree(self.iface.mapCanvas().extent())
        quadtree.buildTreeByRect(QgsRectangle(c[0], c[1], c[2], c[3]),
                                 ui.spinBox_Height.value())
        return quadtree

    def createRubberBands(self, quads, point=None):
        self.clearRubberBands()
        # create quads with rubber band
        self.rb_quads = QgsRubberBand(self.iface.mapCanvas(), QGis.Line)
        self.rb_quads.setColor(Qt.blue)
        self.rb_quads.setWidth(1)

        for quad in quads:
            points = []
            extent = quad.extent
            points.append(QgsPoint(extent.xMinimum(), extent.yMinimum()))
            points.append(QgsPoint(extent.xMinimum(), extent.yMaximum()))
            points.append(QgsPoint(extent.xMaximum(), extent.yMaximum()))
            points.append(QgsPoint(extent.xMaximum(), extent.yMinimum()))
            self.rb_quads.addGeometry(QgsGeometry.fromPolygon([points]), None)
            self.log(extent.toString())
        self.log("Quad count: %d" % len(quads))

        # create a point with rubber band
        if point:
            self.rb_point = QgsRubberBand(self.iface.mapCanvas(), QGis.Point)
            self.rb_point.setColor(Qt.red)
            self.rb_point.addPoint(point)

    def clearRubberBands(self):
        # clear quads and point
        if self.rb_quads:
            self.iface.mapCanvas().scene().removeItem(self.rb_quads)
            self.rb_quads = None
        if self.rb_point:
            self.iface.mapCanvas().scene().removeItem(self.rb_point)
            self.rb_point = None

    def browseClicked(self):
        directory = self.ui.lineEdit_OutputFilename.text()
        if directory == "":
            directory = QDir.homePath()
        filename = QFileDialog.getSaveFileName(
            self,
            self.tr("Output filename"),
            directory,
            "HTML file (*.html *.htm)",
            options=QFileDialog.DontConfirmOverwrite)
        if filename != "":
            self.ui.lineEdit_OutputFilename.setText(filename)

    def samplingModeChanged(self):
        ui = self.ui
        isSimpleMode = ui.radioButton_Simple.isChecked()
        simple_widgets = [
            ui.horizontalSlider_Resolution, ui.lineEdit_Width,
            ui.lineEdit_Height, ui.lineEdit_HRes, ui.lineEdit_VRes
        ]
        for w in simple_widgets:
            w.setEnabled(isSimpleMode)

        isAdvancedMode = not isSimpleMode
        advanced_widgets = [
            ui.spinBox_Height, ui.lineEdit_xmin, ui.lineEdit_ymin,
            ui.lineEdit_xmax, ui.lineEdit_ymax, ui.toolButton_switchFocusMode
        ]
        for w in advanced_widgets:
            w.setEnabled(isAdvancedMode)

    def updateQuads(self, v=None):
        quadtree = self.createQuadTree()
        if quadtree:
            self.createRubberBands(quadtree.quads(),
                                   quadtree.focusRect.center())
        else:
            self.clearRubberBands()

    def switchFocusModeClicked(self):
        self.switchFocusMode(not self.ui.label_xmin.isVisible())

    def switchFocusMode(self, toRect):
        ui = self.ui
        toPoint = not toRect
        ui.label_xmin.setVisible(toRect)
        ui.label_ymin.setVisible(toRect)
        ui.lineEdit_xmin.setVisible(toRect)
        ui.lineEdit_ymin.setVisible(toRect)

        suffix = "max" if toRect else ""
        ui.label_xmax.setText("x" + suffix)
        ui.label_ymax.setText("y" + suffix)
        mode = "point" if toRect else "rectangle"
        ui.toolButton_switchFocusMode.setText("To " + mode + " selection")
        selection = "area" if toRect else "point"
        action = "Stroke a rectangle" if toRect else "Click"
        ui.label_Focus.setText(
            "Focus {0} ({1} on map canvas to set values)".format(
                selection, action))

    def log(self, msg):
        if debug_mode:
            qDebug(msg)
class RectangleMapTool(QgsMapToolEmitPoint):
    """
    Map tool that lets the user define the analysis extents.
    """
    rectangle_created = pyqtSignal()
    deactivated = pyqtSignal()

    def __init__(self, canvas):
        """Constructor for the map tool.

        :param canvas: Canvas that tool will interact with.
        :type canvas: QgsMapCanvas
        """
        self.canvas = canvas
        self.start_point = None
        self.end_point = None
        self.is_emitting_point = False

        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rubber_band = QgsRubberBand(self.canvas, geometryType=QGis.Line)
        self.rubber_band.setColor(QColor(0, 0, 240, 100))
        # Needs QGIS 2.6
        # self.rubber_band.setFillColor(QColor(0, 0, 240, 0))
        self.rubber_band.setWidth(1)

        self.reset()

    def reset(self):
        """
        Clear the rubber band for the analysis extents.
        """
        self.start_point = self.end_point = None
        self.is_emitting_point = False
        self.rubber_band.reset(QGis.Polygon)

    def canvasPressEvent(self, e):
        """
        Handle canvas press events so we know when user is capturing the rect.

        :param e: A Qt event object.
        :type: QEvent
        """
        self.start_point = self.toMapCoordinates(e.pos())
        self.end_point = self.start_point
        self.is_emitting_point = True

        self.show_rectangle(self.start_point, self.end_point)

    def canvasReleaseEvent(self, e):
        """
        Handle canvas release events  has finished capturing e

        :param e: A Qt event object.
        :type: QEvent
        """
        _ = e
        self.is_emitting_point = False
        self.rectangle_created.emit()

    def canvasMoveEvent(self, e):
        """

        :param e:
        :return:
        """
        if not self.is_emitting_point:
            return

        self.end_point = self.toMapCoordinates(e.pos())
        self.show_rectangle(self.start_point, self.end_point)

    def show_rectangle(self, start_point, end_point):
        """
        Show the rectangle on the canvas.

        :param start_point: QGIS Point object representing the origin (
            top left).
        :type start_point: QgsPoint

        :param end_point: QGIS Point object representing the contra-origin (
            bottom right).
        :type end_point: QgsPoint

        :return:
        """
        self.rubber_band.reset(QGis.Polygon)
        if (start_point.x() == end_point.x()
                or start_point.y() == end_point.y()):
            return

        point1 = start_point
        point2 = QgsPoint(end_point.x(), start_point.y())
        point3 = end_point
        point4 = QgsPoint(start_point.x(), end_point.y())

        update_canvas = False
        self.rubber_band.addPoint(point1, update_canvas)
        self.rubber_band.addPoint(point2, update_canvas)
        self.rubber_band.addPoint(point3, update_canvas)
        self.rubber_band.addPoint(point4, update_canvas)
        # noinspection PyArgumentEqualDefault
        # no False so canvas will update
        # close the polygon otherwise it shows as a filled rect
        self.rubber_band.addPoint(point1)
        self.rubber_band.show()

    def rectangle(self):
        """
        Accessor for the rectangle.

        :return: A rectangle showing the designed extent.
        :rtype: QgsRectangle
        """
        if self.start_point is None or self.end_point is None:
            return None
        elif self.start_point.x() == self.end_point.x() or \
                self.start_point.y() == self.end_point.y():
            return None

        return QgsRectangle(self.start_point, self.end_point)

    def set_rectangle(self, rectangle):
        """
        Set the rectangle for the selection.
        :param rectangle:
        :return:
        """
        if rectangle == self.rectangle():
            return False

        if rectangle is None:
            self.reset()
        else:
            self.start_point = QgsPoint(
                rectangle.xMinimum(), rectangle.yMinimum())
            self.end_point = QgsPoint(
                rectangle.xMaximum(), rectangle.yMaximum())
            self.show_rectangle(self.start_point, self.end_point)
        return True

    def deactivate(self):
        """
        Disable the tool.
        """
        QgsMapTool.deactivate(self)
        self.deactivated.emit()
Example #43
0
class Gban:

    def __init__(self, iface):
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(
            os.path.dirname(__file__),
            'i18n',
            'gban_{}.qm'.format(locale))
        
        self.translator = None
        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        self.iface = iface
        self.canvas = self.iface.mapCanvas()

        self.exclusive = QActionGroup( self.iface.mainWindow() )

        self.actions = []
        self.menu = '&Gban'
        self.toolbar = self.iface.addToolBar('Gban')
        self.toolbar.setObjectName('Gban')
        
        #Select tool initialization
        self.tool = QgsMapToolEmitPoint(self.canvas)
        self.tool.canvasClicked.connect(self.doReverseGeocoding)
        self.tool.deactivated.connect(self.uncheckReverseGeocoding)

        self.rb = QgsRubberBand(self.iface.mapCanvas(), QGis.Point)
        self.rb.setColor( QColor(255, 0, 0) )
        self.rb.setWidth( 5 )
        
        # Network configuration
        self.manager = QgsNetworkAccessManager.instance()
                                   
    def unload(self):
        for action in self.actions:
            self.iface.removePluginMenu('&Gban', action)
            self.iface.removeToolBarIcon(action)
        del self.toolbar
        
    def tr(self, message):
        return QCoreApplication.translate('Gban', message)

    def add_action(
        self,
        icon_path,
        text,
        callback,
        enabled_flag=True,
        checkable=False,
        add_to_menu=True,
        add_to_toolbar=True,
        status_tip=None,
        whats_this=None,
        parent=None):

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)
        action.setCheckable(checkable)

        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)

        if checkable:
            self.exclusive.addAction( action )

        self.actions.append(action)

        return action

    def initGui(self):
        icon_path = ":/plugins/qgeric/resources/icon_geocode.png"
        self.add_action(
            icon_path,
            text=self.tr("Geocoding"),
            callback=self.geocoding,
            parent=self.iface.mainWindow()
        )
        icon_path = ":/plugins/qgeric/resources/icon_reversegeocode.png"
        self.add_action(
            icon_path,
            checkable = True,
            text=self.tr("Reverse geocoding"),
            callback=self.reverseGeocoding,
            parent=self.iface.mainWindow()
        )
        
    def geocoding(self):
        self.rb.reset( QGis.Point )
        address, ok = QInputDialog.getText(self.iface.mainWindow(), self.tr("Address"), self.tr("Input address to geocode:"))
        if ok and address:
            self.doGeocoding(address)
         
    def doGeocoding(self, address):
        address = unicodedata.normalize('NFKD', unicode(address)).encode('ASCII', 'ignore')
        url = "http://api-adresse.data.gouv.fr/search/?q="+address.replace(" ", "%20")
        
        result = self.request(url)

        try:
            data = json.loads(result)
            features = data["features"]
            if len(features) > 0:
                feature_list = []
                for feature in features:
                    feature_list.append(feature["properties"]["label"]+" - "+str(round(feature["properties"]["score"]*100))+"%")
                feature, ok = QInputDialog.getItem(self.iface.mainWindow(), self.tr("Result"), "", feature_list)
                if ok:
                    index = feature_list.index(feature)
                    x = features[index]["geometry"]["coordinates"][0]
                    y = features[index]["geometry"]["coordinates"][1]
                    point_4326 = QgsPoint(x, y)
                    transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem(4326), 
                                                        self.canvas.mapSettings().destinationCrs())
                    point_2154 = transform.transform(point_4326)
                    self.rb.addPoint(point_2154)
                    self.iface.mapCanvas().setCenter(point_2154)
                    self.iface.mapCanvas().refresh()
            else:
                QMessageBox.information(self.iface.mainWindow(), self.tr("Result"), self.tr("No result."))
        except ValueError:
            QMessageBox.critical(self.iface.mainWindow(), self.tr("Error"), self.tr("An error occured. Check your network settings (proxy)."))

    
    def reverseGeocoding(self):
        self.canvas.setMapTool(self.tool)
        
    def doReverseGeocoding(self, point_orig):
        transform = QgsCoordinateTransform(self.canvas.mapSettings().destinationCrs(), 
                                            QgsCoordinateReferenceSystem(4326))
        point_4326 = transform.transform(point_orig)
        url = "http://api-adresse.data.gouv.fr/reverse/?lon="+str(point_4326.x())+"&lat="+str(point_4326.y())

        result = self.request(url)

        try:
            data = json.loads(result)
            
            if len(data["features"]) > 0:
                address = data["features"][0]["properties"]["label"]
                clicked = QMessageBox.information(self.iface.mainWindow(), self.tr("Result"), address, QDialogButtonBox.Ok, QDialogButtonBox.Save)
                if clicked == QDialogButtonBox.Save:
                    QApplication.clipboard().setText(address)
            else:
                QMessageBox.information(self.iface.mainWindow(), self.tr("Result"), self.tr("No result."))
        except ValueError:
            QMessageBox.critical(self.iface.mainWindow(), self.tr("Error"), self.tr("An error occured. Check your network settings (proxy)."))

    def uncheckReverseGeocoding(self):
        self.exclusive.checkedAction().setChecked(False)

    def request(self, url):
        ''' prepare the request and return the result of the reply
        '''
        request = QNetworkRequest(QUrl(url))
        reply = self.manager.get(request)
        reply.deleteLater()
        evloop = QEventLoop()
        reply.finished.connect(evloop.quit)
        evloop.exec_(QEventLoop.ExcludeUserInputEvents)
        return unicode(reply.readAll())
Example #44
0
    def btnPreview_Click(self):
        self.priviewClickFlag = not self.priviewClickFlag
        if not self.priviewClickFlag:
            QgisHelper.ClearRubberBandInCanvas(define._canvas)
            return
        if self.comboBox.currentIndex() == ProtectionAreaType.Primary:
            rBand = QgsRubberBand(define._canvas, QGis.Polygon)

            for point in self.area.PreviewArea.method_14():
                rBand.addPoint(point)
            rBand.setFillColor(QtGui.QColor(46, 64, 142, 100))
            rBand.setBorderColor(QtGui.QColor(0, 10, 238))
            rBand.show()
        elif self.comboBox.currentIndex() == ProtectionAreaType.Secondary:
            rBand = QgsRubberBand(define._canvas, QGis.Polygon)
            if isinstance(self.area, SecondaryObstacleAreaWithManyPoints):
                for point in self.area.PreviewArea.method_14():
                    rBand.addPoint(point)
                rBand.setFillColor(QtGui.QColor(46, 64, 142, 100))
                rBand.setBorderColor(QtGui.QColor(0, 10, 238))
                rBand.show()
            else:
                for point in self.area.area.PreviewArea.method_14():
                    rBand.addPoint(point)
                rBand.setFillColor(QtGui.QColor(46, 64, 142, 100))
                rBand.setBorderColor(QtGui.QColor(0, 10, 238))
                rBand.show()
        elif self.comboBox.currentIndex(
        ) == ProtectionAreaType.PrimaryAndSecondary:
            rBand = QgsRubberBand(define._canvas, QGis.Polygon)
            for point in self.area.primaryArea.PreviewArea.method_14():
                rBand.addPoint(point)
            rBand.setFillColor(QtGui.QColor(46, 64, 142, 100))
            rBand.setBorderColor(QtGui.QColor(0, 10, 238))
            rBand.show()

            rBand = QgsRubberBand(define._canvas, QGis.Polygon)
            for point in self.area.secondaryArea1.PreviewArea.method_14():
                rBand.addPoint(point)
            rBand.setFillColor(QtGui.QColor(46, 64, 142, 100))
            rBand.setBorderColor(QtGui.QColor(0, 10, 238))
            rBand.show()

            rBand = QgsRubberBand(define._canvas, QGis.Polygon)
            for point in self.area.secondaryArea2.PreviewArea.method_14():
                rBand.addPoint(point)
            rBand.setFillColor(QtGui.QColor(46, 64, 142, 100))
            rBand.setBorderColor(QtGui.QColor(0, 10, 238))
            rBand.show()
        else:
            for obstacleArea in self.area:
                if isinstance(obstacleArea, PrimaryObstacleArea):
                    rBand = QgsRubberBand(define._canvas, QGis.Polygon)

                    for point in obstacleArea.PreviewArea.method_14():
                        rBand.addPoint(point)
                    rBand.setFillColor(QtGui.QColor(46, 64, 142, 100))
                    rBand.setBorderColor(QtGui.QColor(0, 10, 238))
                    rBand.show()
                else:
                    rBand = QgsRubberBand(define._canvas, QGis.Polygon)
                    if isinstance(obstacleArea,
                                  SecondaryObstacleAreaWithManyPoints):
                        for point in obstacleArea.PreviewArea.method_14():
                            rBand.addPoint(point)
                        rBand.setFillColor(QtGui.QColor(46, 64, 142, 100))
                        rBand.setBorderColor(QtGui.QColor(0, 10, 238))
                        rBand.show()
                    else:
                        for point in obstacleArea.area.PreviewArea.method_14():
                            rBand.addPoint(point)
                        rBand.setFillColor(QtGui.QColor(46, 64, 142, 100))
                        rBand.setBorderColor(QtGui.QColor(0, 10, 238))
                        rBand.show()

        define._canvas.refresh()
Example #45
0
class RubberBandResultRenderer():

    def __init__(self):
        self.iface = iface

        self.srs_wgs84 = QgsCoordinateReferenceSystem(4326)
        self.transformation = QgsCoordinateTransform(self.srs_wgs84, self.srs_wgs84)

        self.rb = QgsRubberBand(self.iface.mapCanvas(), QGis.Point)
        self.rb.setColor(QColor('magenta'))
        self.rb.setIconSize(12)

        self.features_rb = QgsRubberBand(self.iface.mapCanvas(), QGis.Point)
        self.features_rb.setColor(QColor('green'))
        self.features_rb.setIconSize(12)
        self.features_rb.setWidth(3)

    def show_point(self, point, center=False):
        #check srs
        if self.need_transform():
            point = self.transform_point(point)

        self.rb.addPoint(point)
        if center:
            self.center_to_point(point)

    def clear(self):
        self.rb.reset(QGis.Point)

    def need_transform(self):
        return self.iface.mapCanvas().mapRenderer().destinationCrs().postgisSrid() != 4326

    def transform_point(self, point):
        dest_srs_id = self.iface.mapCanvas().mapRenderer().destinationCrs().srsid()
        self.transformation.setDestCRSID(dest_srs_id)
        try:
            return self.transformation.transform(point)
        except:
            print 'Error on transform!'  # DEBUG! need message???
            return

    def transform_bbox(self, bbox):
        dest_srs_id = self.iface.mapCanvas().mapRenderer().destinationCrs().srsid()
        self.transformation.setDestCRSID(dest_srs_id)
        try:
            return self.transformation.transformBoundingBox(bbox)
        except:
            print 'Error on transform!'  # DEBUG! need message???
            return

    def transform_geom(self, geom):
        dest_srs_id = self.iface.mapCanvas().mapRenderer().destinationCrs().srsid()
        self.transformation.setDestCRSID(dest_srs_id)
        try:
            geom.transform(self.transformation)
            return geom
        except:
            print 'Error on transform!'  # DEBUG! need message???
            return

    def center_to_point(self, point):
        canvas = self.iface.mapCanvas()
        new_extent = QgsRectangle(canvas.extent())
        new_extent.scale(1, point)
        canvas.setExtent(new_extent)
        canvas.refresh()

    def zoom_to_bbox(self, bbox):
        if self.need_transform():
            bbox = self.transform_bbox(bbox)
        self.iface.mapCanvas().setExtent(bbox)
        self.iface.mapCanvas().refresh()


    def show_feature(self, geom):
        if self.need_transform():
            geom = self.transform_geom(geom)
        self.features_rb.setToGeometry(geom, None)

    def clear_feature(self):
        self.features_rb.reset(QGis.Point)
Example #46
0
class DivisionFusion:
    """QGIS Plugin Implementation."""
    def __init__(self, iface, ACA):
        """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
        self.CFG = None
        self.UTI = None
        self.DFS = None
        self.DBJ = None
        self.ELM = None
        self.ACA = ACA
        self.TPG = None
        # 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',
                                   'DivisionFusion_{}.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)

        # Create the dialog (after translation) and keep reference
        self.dlg = DivisionFusionDialog(parent=iface.mainWindow())
        #self.dlg.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&DivisionFusion')
        # TODO: We are going to let the user set this up in a future iteration
        self.toolbar = self.iface.addToolBar(u'DivisionFusion')
        self.toolbar.setObjectName(u'DivisionFusion')

        #self.dlg.setMinimumSize(QSize(464, 465))
        #self.dlg.setMaximumSize(QSize(371, 372))
        #print(self.dlg.size())
        #self.dlg.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
        self.eventos = EventoDivision(iface.mapCanvas(), self)
        self.VentanaAreas = VentanaAreas(self)

        self.VentanaFusion = VentanaFusionV3(iface, self)
        self.VentanaClaves = VentanaClavesV3(iface, self)
        self.rubberMarca = QgsRubberBand(iface.mapCanvas(),
                                         QgsWkbTypes.PolygonGeometry)
        self.rubberMarca.setFillColor(QColor(255, 255, 0, 12))
        self.rubberMarca.setStrokeColor(QColor(255, 150, 0, 255))
        self.rubberMarca.setWidth(2)
        self.listaNuevosPredios = []
        self.cargoPredio = False
        self.listaColores = []
        self.rubbersAreas = []

        self.dlg.btnDibujarCortes.setEnabled(False)
        self.dlg.btnEditarCortes.setEnabled(False)
        self.dlg.btnEliminarCortes.setEnabled(False)
        self.dlg.btnApagarHerramientas.setEnabled(False)
        self.dlg.btnConfirmarCortes.setEnabled(False)
        self.dlg.btnDeshacerTodo.setEnabled(False)
        self.dlg.btnCancelarSub.setEnabled(False)
        self.dlg.btnDeshacerCortes.setEnabled(False)
        self.dlg.btnLlamarCalcular.setEnabled(False)

        self.dlg.btnFusionar.clicked.connect(self.preguntarFusion)
        self.dlg.btnCargarPredio.clicked.connect(self.pasarAModoDivision)
        self.dlg.btnConfirmarCortes.clicked.connect(self.confirmarCortes)
        self.dlg.btnDibujarCortes.clicked.connect(self.encenderModoDividir)
        self.dlg.btnEliminarCortes.clicked.connect(self.encenderModoEliminar)
        self.dlg.btnApagarHerramientas.clicked.connect(self.apagarHerramientas)
        self.dlg.btnDeshacerTodo.clicked.connect(self.rollBack)
        self.dlg.btnCancelarSub.clicked.connect(self.cancelarSubdivision)
        self.dlg.btnDeshacerCortes.clicked.connect(self.vaciarLineasCorte)
        self.dlg.btnLlamarCalcular.clicked.connect(self.irAreas)
        self.dlg.btnEditarCortes.clicked.connect(self.encenderModoEditar)

        self.geomsAreas = []
        #self.p

    # 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('DivisionFusion', 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:
            self.toolbar.addAction(action)

        if add_to_menu:
            self.iface.addPluginToMenu(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/DivisionFusion/icon.png'
        self.add_action(icon_path,
                        text=self.tr(u'DivisionFusion'),
                        callback=self.run,
                        parent=self.iface.mainWindow())

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(self.tr(u'&DivisionFusion'), action)
            self.iface.removeToolBarIcon(action)
        # remove the toolbar
        del self.toolbar

    def run(self):
        """Run method that performs all the real work"""
        # show the dialog
        for x in iface.mapNavToolToolBar().actions():
            if x.objectName() == 'mActionPan':
                x.trigger()

        self.dlg.show()
        self.UTI.strechtTabla(self.VentanaFusion.dlg.tabComp)
        # Run the dialog event loop
        iface.mapCanvas().setMapTool(self.eventos)
        result = self.dlg.exec_()
        # See if OK was pressed
        self.dlg.btnFusionar.setEnabled(True)
        self.dlg.comboPredios.setEnabled(True)
        self.dlg.btnCargarPredio.setEnabled(True)
        self.dlg.btnDibujarCortes.setEnabled(False)
        self.dlg.btnEditarCortes.setEnabled(False)
        self.dlg.btnEliminarCortes.setEnabled(False)
        self.dlg.btnApagarHerramientas.setEnabled(False)
        self.dlg.btnConfirmarCortes.setEnabled(False)
        self.dlg.btnDeshacerTodo.setEnabled(False)
        if result:
            # Do something useful here - delete the line containing pass and
            # substitute with your code.
            pass

#------------------------------------------------------------------------------

#Preguntamos si quiere fusionar

    def preguntarFusion(self):
        if iface.activeLayer() != None:
            seleccion = self.iface.activeLayer().selectedFeatures()
            self.VentanaFusion.dlg.close()
            if self.validarCuentaSeleccion():  #Si la seleccion es valida

                self.VentanaFusion.dlg.show()
                self.VentanaFusion.llenarTablaComp(seleccion[0], seleccion[1])
                self.dlg.btnCargarPredio.setEnabled(False)
        else:
            self.UTI.mostrarAlerta(
                'La fusion requiere la seleccion de exactamente 2 predios contiguos',
                QMessageBox().Critical, 'Error de fusion')

#------------------------------------------------------------------

#Validamosla seleccion

    def validarCuentaSeleccion(self):
        seleccion = self.iface.activeLayer().selectedFeatures()

        if len(seleccion) != 2:  #Cuando tenemos seleccionados no 2 elementos
            self.UTI.mostrarAlerta(
                'La fusion requiere la seleccion de exactamente 2 predios contiguos',
                QMessageBox().Critical, 'Error de fusion')
            return False
        else:
            if not self.validarContiguedad():
                self.UTI.mostrarAlerta(
                    'Los predios seleccionados no son contiguos',
                    QMessageBox().Critical, 'Error de fusion')
                return False
            else:
                return True
#-----------------------------------------------------------------------------

    def validarContiguedad(self):  #Aqui checamos si dos predios son contiguos
        seleccion = self.iface.activeLayer().selectedFeatures()
        pred1 = seleccion[0].geometry().buffer(0.0000001, 1)
        pred2 = seleccion[1].geometry().buffer(0.0000001, 1)
        #Checamos que el area de interseccion sea un valor considerable
        area = pred1.intersection(pred2).area()
        return area > 0.0000000001

#-----------------------------------------------------------------------------------

    def fusionarPredios(self, eleccion):  #Aqui fusionamos los predios

        #OBtener las capas
        capaManzana = QgsProject.instance().mapLayer(
            self.ACA.obtenerIdCapa('manzana'))
        capaPuntos = QgsProject.instance().mapLayer(
            self.ACA.obtenerIdCapa('predios.num'))
        capaPredios = QgsProject.instance().mapLayer(
            self.ACA.obtenerIdCapa('predios.geom'))
        capaConstru = QgsProject.instance().mapLayer(
            self.ACA.obtenerIdCapa('construcciones'))
        capaCondH = QgsProject.instance().mapLayer(
            self.ACA.obtenerIdCapa('horizontales.geom'))

        #Puntos y eleccion de victima
        seleccion = self.iface.activeLayer().selectedFeatures()

        listaPuntos = [None, None]

        #Definimos el predio 'victima
        if eleccion == 0:
            victima = 1
        else:
            victima = 0

        #eliminamos el predio no elegido
        self.eliminarNoElegido(seleccion[victima])

        #Eliminar punto del predio no elegido
        for punto in capaPuntos.getFeatures():
            if punto.geometry().intersects(seleccion[victima].geometry(
            )):  #Bsucamos el punto del predio victima
                capaPuntos.startEditing()
                capaPuntos.dataProvider().deleteFeatures([punto.id()])
                capaPuntos.triggerRepaint()
                capaPuntos.commitChanges()
                break

        #Generar geometria del predio fusionado
        rango = len(seleccion)
        geomFusion = seleccion[0].geometry()

        featFusion = QgsFeature()
        capaPredios.startEditing()

        #Generar geometria del predio fusionado
        for i in range(0, rango):
            self.iface.activeLayer().dataProvider().deleteFeatures(
                [seleccion[i].id()])
            geomFusion = geomFusion.combine(seleccion[i].geometry())

        #self.geom
        listaFinal = []
        listaPrimera = []
        featFusion.setGeometry(geomFusion)

        #Renombrar construcciones
        cuentaConstruccion = 1
        capaConstru.startEditing()

        #--------Renombrar construcciones----
        for construccion in capaConstru.getFeatures():
            geomConstru = construccion.geometry()

            if geomConstru.buffer(-0.0000001, 1).intersects(
                    geomFusion
            ):  #Sacamos las construcciones dentro del predio fusionado
                listaPrimera.append(construccion)
            else:
                if self.contarIntegraciones(
                        geomConstru.buffer(-0.0000001, 1), 'predios.geom'
                ) == 0:  #Obtenemos los aleros del predio fusionado
                    if geomConstru.buffer(
                            0.0000001,
                            1).intersection(geomFusion).area() > 0.000000001:
                        #print(geomConstru.buffer(0.0000001, 1).intersection(geomFusion).area())
                        listaPrimera.append(construccion)

        for construccion in listaPrimera:
            geomConstru = construccion.geometry()
            seIncluye = True
            for condominio in capaCondH.getFeatures():
                geomHori = condominio.geometry()
                if geomConstru.buffer(-0.0000001, 1).intersects(geomHori):
                    seIncluye = False
                    break

            if seIncluye:
                listaFinal.append(construccion)

        supConst = 0  #Renombramos ls volumenes
        for construccion in listaFinal:
            geomConstru = construccion.geometry()
            construccion['nom_volumen'] = 'V' + str(cuentaConstruccion)
            niveles = construccion['num_niveles']
            if niveles <= 0:
                niveles = 1
            capaConstru.updateFeature(construccion)
            cuentaConstruccion += 1
            supConst += (geomConstru.area() * niveles)
        #----------------------------------------------

        #Estableer atributos del predio fusionado
        idx1 = capaPredios.fields().lookupField('sup_terr')
        idx2 = capaPredios.fields().lookupField('sup_contruccion')
        attr = seleccion[eleccion].attributes()
        attr[idx1] = geomFusion.area()
        attr[idx2] = supConst
        featFusion.setAttributes(attr)
        capaPredios.updateFeature(featFusion)
        capaPredios.dataProvider().addFeatures([featFusion])
        capaPredios.triggerRepaint()
        capaPredios.commitChanges()

        self.UTI.mostrarAlerta('Fusion completada con exito',
                               QMessageBox().Information, 'Fusion de predios')
        self.dlg.close()

#-----------------------------------------------------------------------------------

#Aqui contmaos cuantas geometrias de una capa toca una geomtrias especifica

    def contarIntegraciones(self, geometria, nombreCapa):
        capa = QgsProject.instance().mapLayersByName(nombreCapa)[0]
        cuenta = 0
        for feat in capa.getFeatures():
            if geometria.intersects(feat.geometry()):
                cuenta += 1

        return cuenta

#---------------------------------------------------------------------------

#Poinemos en lista de eliminados el predio no elegido

    def eliminarNoElegido(self, feat):
        campos = {}
        campos['wkt'] = feat.geometry().asWkt()
        campos['srid'] = 32614

        campos['tabla'] = 'e_predio'
        atributos = {}
        capaPredios = QgsProject.instance().mapLayer(
            self.ACA.obtenerIdCapa('predios.geom'))
        nombresAtrbutos = capaPredios.fields()

        nombres = [campo.name() for campo in nombresAtrbutos]

        for x in range(0, len(nombres)):
            atributo = feat.attributes()[x]
            if str(feat.attributes()[x]) == "NULL":
                atributo = None
            atributos[str(nombres[x])] = atributo

        campos['attr'] = atributos

        campos['nuevo'] = False
        campos['eliminado'] = True

        listaTemp = QSettings().value('listaEliminada')
        listaTemp.append(campos)

        QSettings().setValue('listaEliminada', listaTemp)

#--------------------------------------------------------------------------

#Activamos el modo de division

    def pasarAModoDivision(self):
        clave = self.dlg.comboPredios.currentText(
        )  #Obtenemos la clave del predio a editar

        if clave == '':
            self.UTI.mostrarAlerta(
                'Primero debes cargar una manzana de la seccion de consulta',
                QMessageBox().Critical, 'Error de cargado de predio')
            return

        capaPredios = QgsProject.instance().mapLayer(
            self.ACA.obtenerIdCapa('predios.geom'))
        #capaPredios.setReadOnly(False)
        capaPredios.startEditing()

        self.predioEnDivision = None

        for predio in capaPredios.getFeatures(
        ):  #Obtenemos el feature a dividr con base en la clave elegida
            if predio.attributes()[1] == clave:
                self.predioEnDivision = predio
                break

        if self.predioEnDivision != None:

            self.atributosAHeredar = self.predioEnDivision.attributes(
            )  #Obtenemos los atributos a heredar
            self.atributosAHeredar[1] = None  #Ponemos le id como vacio

            self.rubberMarca.reset(
                QgsWkbTypes.PolygonGeometry)  #Borramos la geometria amarillita
            self.UTI.mostrarAlerta(
                "Dibuja las lineas de corte sobre el predio indicado.\nRecuerda que los cortes no pueden estar sobre construcciones o condiminios.\nAsegurate que las lineas atraviesen el predio por completo\nNOTA: Las lineas solo afectaran al predio seleccionado.",
                QMessageBox().Information, "Subdivision de predios")
            self.cargoPredio = True
            self.encenderModoDividir()  #Encendemos modo dividir
            capaPredios.commitChanges()
            self.geomEnDivision = self.predioEnDivision.geometry()
            n = 0  #Obtenemos todos los vertices de la geometria en division
            ver = self.geomEnDivision.vertexAt(0)
            listaVertices = []
            while (ver != QgsPoint(0, 0)):
                n += 1
                ver = self.geomEnDivision.vertexAt(n)
                listaVertices.append(ver)

            listaVertices.append(listaVertices[0])
            rangoVertices = len(listaVertices)
            for x in range(0, rangoVertices - 2):
                vertice = listaVertices[x]
                self.rubberMarca.addPoint(QgsPointXY(vertice.x(), vertice.y()),
                                          True)
            self.rubberMarca.show(
            )  #Aqui pintamos de amarillito la geometria en division
            self.dlg.btnFusionar.setEnabled(False)
            self.dlg.btnCancelarSub.setEnabled(True)
            self.dlg.btnCargarPredio.setEnabled(False)
            self.dlg.comboPredios.setEnabled(False)
            self.dlg.comboPredios.setEnabled(False)
            self.dlg.btnConfirmarCortes.setEnabled(True)
            self.dlg.btnDeshacerTodo.setEnabled(True)
            self.dlg.btnDeshacerCortes.setEnabled(True)
            self.dlg.btnLlamarCalcular.setEnabled(True)
        else:
            self.UTI.mostrarAlerta('El predio no fue encontrado',
                                   QMessageBox().Critical,
                                   'Error de cargado de predio')

#-------------------------------------------------------------------------

    def cancelarSubdivision(self):

        mensaje = "El modo de division se apagara, el progreso se perdera\nDeseas continuar?"
        respuesta = QMessageBox.question(iface.mainWindow(),
                                         "Cancelar subdivision", mensaje,
                                         QMessageBox.Yes, QMessageBox.No)

        #Si el usuario acepta....
        if respuesta == QMessageBox.Yes:

            self.vaciarRubbers()
            self.predioEnDivision = None
            self.geomEnDivision = None
            self.modoDividir = False
            self.modoEliminar = False
            self.apagarHerramientas()
            self.dlg.btnCancelarSub.setEnabled(False)
            self.dlg.btnCargarPredio.setEnabled(True)
            self.dlg.comboPredios.setEnabled(True)
            self.dlg.btnFusionar.setEnabled(True)
            self.dlg.btnConfirmarCortes.setEnabled(False)
            self.dlg.btnDeshacerCortes.setEnabled(False)
            self.dlg.btnLlamarCalcular.setEnabled(False)
            self.dlg.btnApagarHerramientas.setEnabled(False)
            self.dlg.btnEliminarCortes.setEnabled(False)
            self.dlg.btnDibujarCortes.setEnabled(False)
            self.dlg.btnEditarCortes.setEnabled(False)
            self.dlg.btnDeshacerTodo.setEnabled(False)
#-----------------------------------------------------------------------------------

#--------------------------------------------

    def confirmarCortes(self):  #Aqui cehcamos que los cortes esten en orden

        #cuentaCortes = 0
        rango = len(self.eventos.relaciones) - 1
        #for i in range(0, rango):
        #    geom = self.eventos.relaciones[i].geom
        #    if geom != None:
        #        cuentaCortes += 1
        #Obtenemos la cantidad de corte
        #print('cuentaCortes ', cuentaCortes)
        geoTemp = QgsGeometry.fromWkt(self.geomEnDivision.asWkt())
        cuentaSalida = self.subdividirPredio(
            geoTemp, True
        ) - 1  #Aqui enviamos una geomtria temporal, para ven en cuantos cortes quedara

        if cuentaSalida >= 2:

            listaNoTocar = []
            capaPredios = QgsProject.instance().mapLayer(
                self.ACA.obtenerIdCapa('predios.geom'))
            capaCondH = QgsProject.instance().mapLayersByName(
                'horizontales.geom')[0]
            capaCondV = QgsProject.instance().mapLayersByName('verticales')[0]
            capaConstru = QgsProject.instance().mapLayer(
                self.ACA.obtenerIdCapa('construcciones'))

            #Obtenemos los features que no deben tocarse
            for feat in capaConstru.getFeatures():
                geom = feat.geometry().buffer(-0.0000002, 1)
                if geom.intersects(self.geomEnDivision):
                    listaNoTocar.append(geom)

            for feat in capaCondH.getFeatures():
                geom = feat.geometry().buffer(-0.0000002, 1)
                if geom.intersects(self.geomEnDivision):
                    listaNoTocar.append(geom)

            for feat in capaCondV.getFeatures():
                geom = feat.geometry().buffer(-0.0000002, 1)
                if geom.intersects(self.geomEnDivision):
                    listaNoTocar.append(geom)

            bandera = True

            #Aqui checamos que cada linea no toque lo no tocable
            for i in range(0, rango):
                for comp in listaNoTocar:
                    geom = self.eventos.relaciones[i].geom
                    if geom != None:
                        if geom.buffer(0.0000001, 1).intersects(comp):
                            bandera = False
                            self.eventos.relaciones[i].rubber.setStrokeColor(
                                QColor(255, 0, 0, 255))
                        else:
                            self.eventos.relaciones[i].rubber.setStrokeColor(
                                QColor(0, 61, 240, 255))

            iface.mapCanvas().refresh()
            if bandera:  #Si todo esta en orden
                self.eventos.rubberPunto.reset(QgsWkbTypes.PointGeometry)
                self.apagarHerramientas()
                #mostramos mensaje de confirmacion
                mensaje = "La cantidad de predios que quedaran como resultado, es de: " + str(
                    cuentaSalida) + "\nDeseas continua?"
                respuesta = QMessageBox.question(
                    iface.mainWindow(), "Nota de subdivision de predio",
                    mensaje, QMessageBox.Yes, QMessageBox.No)

                #Si el usuario acepta....
                if respuesta == QMessageBox.Yes:
                    self.subdividirPredio(self.geomEnDivision, False)
                    self.rubberMarca.reset(
                        QgsWkbTypes.PolygonGeometry)  #Quitamos lo amarillito

                    for i in range(0, rango):
                        self.eventos.relaciones[i].rubber.reset(
                            QgsWkbTypes.LineGeometry)
                        self.eventos.relaciones[i].vaciarMarcadores()
                    self.eventos.recargarRelaciones()

                    capaPredios.startEditing()
                    capaPredios.dataProvider().deleteFeatures(
                        [self.predioEnDivision.id()])
                    capaPredios.triggerRepaint()
                    capaPredios.commitChanges()

                    self.VentanaAreas.close()
                    self.limpiarAreas()
                    self.vaciarRubbers()

                    self.UTI.mostrarAlerta(
                        "La division ha sido realizada con exito\nLos cambios se guardaran hasta que asignes las claves.",
                        QMessageBox().Information,
                        "Subdivision completa, Parte 1 de 2")
                    self.irAClaves(
                    )  #Mostramos la ventana que llena las claves
                    iface.actionSelect().trigger()
            else:
                self.UTI.mostrarAlerta(
                    "Las lineas de division no deben atravesar construcciones ni condominios\nLas lineas rojas presentan un corte invalido",
                    QMessageBox().Critical, "Error en subdivision")

        else:
            print('cuentasalida ', cuentaSalida)
            self.UTI.mostrarAlerta(
                "Primero debes dibujar las lineas de corte\nAsegurate que las lineas atraviesen por completo el predio",
                QMessageBox().Critical, "Error en subdivision")

##################################################################################

    def vaciarLineasCorte(self):
        rango = len(self.eventos.relaciones) - 1
        for i in range(0, rango):
            self.eventos.relaciones[i].rubber.reset(QgsWkbTypes.LineGeometry)
            self.eventos.relaciones[i].vaciarMarcadores()

        self.eventos.recargarRelaciones()

#-------------------------------------------------------------------------------------

    def subdividirPredio(self, geometria, modoPre):  #Subdividir
        capaHori = QgsProject.instance().mapLayersByName(
            'horizontales.geom')[0]
        capaPredio = QgsProject.instance().mapLayer(
            self.ACA.obtenerIdCapa('predios.geom'))
        capaVert = QgsProject.instance().mapLayersByName('verticales')[0]

        self.listaNuevosPredios = []
        self.geomsAreas = []
        listaParam = []  #La lista que llega al fileteo
        rango = len(self.eventos.relaciones) - 1
        for i in range(0, rango):

            geom = self.eventos.relaciones[i].geom
            if geom != None:
                listaParam.append(
                    geom.asPolyline())  #Generamos los polyline van a partir

        salida = self.filetear(
            geometria,
            listaParam)  #Mandamos filetear el poligono con las lineas

        if modoPre:  #Si es modoPre, es solo para visaulizar cuantos poligonos quedarian...

            for cadaUno in salida:
                self.geomsAreas.append(cadaUno)
            return len(salida)
        else:  #Si no, efectuamos realmente el corte
            for cadaUno in salida:
                nuevoFeat = QgsFeature()
                nuevoFeat.setGeometry(cadaUno)
                #Agregamos cada predio a la capa y le ponemos sus atributos

                self.asignarAtributos(nuevoFeat)

                capaPredio.startEditing()
                capaPredio.dataProvider().addFeatures([nuevoFeat])
                capaPredio.triggerRepaint()
                capaPredio.commitChanges()

                self.listaNuevosPredios.append(nuevoFeat.geometry().asWkt())

        self.apagarHerramientas()
        self.dlg.btnCargarPredio.setEnabled(True)

##################################################################################

#Metodo para filetear los predios con lineas
#OJO: Ni se te ocurra moverle aqui karnal, seguramente la vas a pifiar :)

    def filetear(self, poligono, lineas):
        listaActuales = []  #Lista de las geometrias en espera de ser cortadas
        listaActuales.append(
            poligono)  #Agregamos el poligono a cortar en la lista de espera
        listaSiguiente = [
            poligono
        ]  #Agregamos le poligono a cortar en la lista de la siguiente interacion

        for linea in lineas:  #Iteramos cada linea de corte

            listaActuales = listaSiguiente  #Igualamos la lista de corte a la iteracion anterior
            listaSiguiente = [
            ]  #Vaciamos la lista que dara lugar a la siguiente iteracion de corte

            for actual in listaActuales:  #Checamos cada geometria en espera

                partida = actual.splitGeometry(
                    linea, True
                )  #Aplicamos el split geometry de qgis, vamos partiendo el poligono, tut, tut, tut
                if len(partida[1]
                       ) == 0:  #Esto ocurre cuando el corte no hizo nada
                    listaSiguiente.append(
                        actual
                    )  #Asi que nos quedamos con la geometria tal cual esta
                else:  #Cuando si hubo corte
                    parte1 = partida[1][
                        0]  #obtenemos la geometria resultante del corte, VER DOCUMENTACION DE SPLITGEOMETRY PARA ENTENDER
                    parte2 = actual.difference(
                        parte1
                    )  #Al poligono que se corto, le quitamos la parte previa al corte anterior
                    #De esta forma nos quedamos con la geometria partida en 2

                    if parte1.area(
                    ) > 0.0:  #Checamos que el area de esta parte sea mayor que 0, por motivos de los decimales
                        listaSiguiente.append(
                            parte1
                        )  #Si es asi, significa un fragmento que puede ser cortado por otra linea

                    if parte2.area() > 0.0:  #Lo mismo
                        listaSiguiente.append(parte2)

        temporal = poligono  #Obtenemos una geometria igualita al poligono entrannte

        for geomSal in listaSiguiente:  #Obtenemos las diferencia respeto a los poligonos obtenidos y el entrante, lo que resulte, tambien es parte del corte
            temporal = temporal.difference(geomSal.buffer(0.0000001, 1))
            #El buffer tu sabes por que es, si llegaste hasta aqui y no sabes por que le ponemos buffer, mejor quita los cambios que hiciste colega, seguramente la pifiaste :)

        listaSiguiente.append(temporal)  #Aqui ponemos todas las geometrias
        return listaSiguiente  #Retornamos la lista

#-------------------------------------------------------------------------

    def encenderModoDividir(self):  #Activamos el modo de dividir

        self.eventos.modoDividir = True
        self.eventos.modoEliminar = False
        self.eventos.modoEditar = False
        self.dlg.btnDibujarCortes.setEnabled(False)
        self.dlg.btnEditarCortes.setEnabled(True)
        self.dlg.btnEliminarCortes.setEnabled(True)
        self.dlg.btnApagarHerramientas.setEnabled(True)
        self.dlg.btnConfirmarCortes.setEnabled(True)
        self.dlg.btnDeshacerTodo.setEnabled(True)
        self.dlg.btnCargarPredio.setEnabled(False)
        iface.mapCanvas().setCursor(self.DBJ.eventos.cursorRedondo)

#----------------------------------------------------------------------------

    def encenderModoEditar(self):  #Activamos el modo de dividir

        self.eventos.modoDividir = False
        self.eventos.modoEliminar = False
        self.eventos.modoEditar = True
        self.dlg.btnDibujarCortes.setEnabled(True)
        self.dlg.btnEditarCortes.setEnabled(False)
        self.dlg.btnEliminarCortes.setEnabled(True)
        self.dlg.btnApagarHerramientas.setEnabled(True)
        self.dlg.btnConfirmarCortes.setEnabled(True)
        self.dlg.btnDeshacerTodo.setEnabled(True)
        self.dlg.btnCargarPredio.setEnabled(False)
        iface.mapCanvas().setCursor(self.DBJ.eventos.cursorRedondo)

#----------------------------------------------------------------------------

    def encenderModoEliminar(self):  #Activamos el modo de eliminar
        self.eventos.modoDividir = False
        self.eventos.modoEliminar = True
        self.eventos.modoEditar = False
        self.dlg.btnDibujarCortes.setEnabled(True)
        self.dlg.btnEditarCortes.setEnabled(True)
        self.dlg.btnEliminarCortes.setEnabled(False)
        self.dlg.btnApagarHerramientas.setEnabled(True)
        self.dlg.btnConfirmarCortes.setEnabled(True)
        self.dlg.btnCargarPredio.setEnabled(False)
        iface.mapCanvas().setCursor(self.DBJ.eventos.cursorCuadro)

#----------------------------------------------------------------------------

    def apagarHerramientas(self):  #Apagamos las herramientas
        self.eventos.modoDividir = False
        self.eventos.modoEliminar = False
        self.eventos.modoEditar = False

        self.dlg.btnDibujarCortes.setEnabled(True)
        self.dlg.btnEliminarCortes.setEnabled(True)
        self.dlg.btnEditarCortes.setEnabled(True)
        self.dlg.btnApagarHerramientas.setEnabled(False)
        self.dlg.btnConfirmarCortes.setEnabled(True)
        self.dlg.btnCargarPredio.setEnabled(False)
        iface.mapCanvas().setCursor(self.DBJ.eventos.cursorCruz)

#-----------------------------------------------------------------

    def rollBack(self):  #Deshacemos cambios

        mensaje = "Todos los cambio se perderan, el area de trabajo se limpiara... deseas continuar?"
        respuesta = QMessageBox.question(iface.mainWindow(),
                                         "Cancelar cambios", mensaje,
                                         QMessageBox.Yes, QMessageBox.No)

        #Si el usuario acepta....
        if respuesta == QMessageBox.Yes:

            self.eventos.modoDividir = False
            self.eventos.modoEliminar = False
            self.dlg.close()
            self.VentanaClaves.dlg.close()
            self.vaciarRubbers()
            self.predioEnDivision = None
            self.geomEnDivision = None
            self.VentanaAreas.close()
            self.UTI.limpiarCanvas()

#------------------------------------------------------------

    def vaciarRubbers(self):
        rango = len(self.eventos.relaciones) - 1
        for i in range(0, rango):
            self.eventos.relaciones[i].rubber.reset(QgsWkbTypes.LineGeometry)
            #self.eventos.relaciones[i].geom = None
            self.eventos.relaciones[i].vaciarMarcadores()

        self.eventos.recargarRelaciones()
        self.rubberMarca.reset(QgsWkbTypes.PolygonGeometry)
        #self.eventos.vaciarMarcadores()

#-----------------------------------------------------------------

    def asignarAtributos(self, feat):  #Asignamos los atributos
        capaPredios = QgsProject.instance().mapLayer(
            self.ACA.obtenerIdCapa('predios.geom'))
        campos = capaPredios.fields()
        nombres = [campo.name() for campo in campos]

        listaAsignacion = []

        for nombre in nombres:
            idx = capaPredios.fields().lookupField(nombre)
            if nombre == 'sup_terr':
                attr = feat.geometry().area()
            elif nombre == 'sup_contruccion':
                attr = self.calcularSupConst(feat)
            elif nombre == 'clave':
                attr = ''
            elif nombre == 'cve_cat':
                attr = ''
            elif nombre == 'id':
                attr = ''
            else:
                attr = self.predioEnDivision.attributes()[idx]
            listaAsignacion.append(attr)

        capaPredios.startEditing()
        feat.setAttributes(listaAsignacion)
        capaPredios.triggerRepaint()
        capaPredios.commitChanges()

#------------------------------------------------------------

    def calcularSupConst(self, feat):  #calculamos superficie de construccion

        capaConstru = QgsProject.instance().mapLayer(
            self.ACA.obtenerIdCapa('construcciones'))
        capaCondH = QgsProject.instance().mapLayer(
            self.ACA.obtenerIdCapa('horizontales.geom'))

        listaFinal = []
        listaPrimera = []

        #Renombrar construcciones
        cuentaConstruccion = 1
        capaConstru.startEditing()
        geomFeat = feat.geometry()

        #--------Renombrar construcciones----
        for construccion in capaConstru.getFeatures():
            geomConstru = construccion.geometry()

            if geomConstru.buffer(-0.0000001, 1).intersects(
                    geomFeat
            ):  #Sacamos las construcciones dentro del predio fusionado
                listaPrimera.append(construccion)
            else:
                if self.contarIntegraciones(
                        geomConstru.buffer(-0.0000001, 1), 'predios.geom'
                ) == 0:  #Obtenemos los aleros del predio fusionado
                    if geomConstru.buffer(
                            0.0000001,
                            1).intersection(geomFeat).area() > 0.000000001:
                        #print(geomConstru.buffer(0.0000001, 1).intersection(geomFusion).area())
                        listaPrimera.append(construccion)

        for construccion in listaPrimera:
            geomConstru = construccion.geometry()
            seIncluye = True
            for condominio in capaCondH.getFeatures():
                geomHori = condominio.geometry()
                if geomConstru.buffer(-0.0000001, 1).intersects(geomHori):
                    seIncluye = False
                    break

            if seIncluye:
                listaFinal.append(construccion)

        supConst = 0  #Renombramos ls volumenes
        for construccion in listaFinal:
            geomConstru = construccion.geometry()
            construccion['nom_volumen'] = 'V' + str(cuentaConstruccion)
            niveles = construccion['num_niveles']
            if niveles <= 0:
                niveles = 1
            capaConstru.updateFeature(construccion)
            cuentaConstruccion += 1
            supConst += (geomConstru.area() * niveles)

        return supConst

#--------------------------------------------------------------------------------------------------

    def irAClaves(self):  #Pintamos la ventanita de asignar clavees
        self.VentanaClaves.rellenarClaves()
        self.VentanaClaves.llenar(False)
        self.VentanaClaves.dlg.show()
        #self.dlg.close()
        self.dlg.btnDibujarCortes.setEnabled(False)
        self.dlg.btnEditarCortes.setEnabled(False)
        self.dlg.btnEliminarCortes.setEnabled(False)
        self.dlg.btnApagarHerramientas.setEnabled(False)
        self.dlg.btnConfirmarCortes.setEnabled(False)
        self.dlg.btnCargarPredio.setEnabled(False)
        self.dlg.btnDeshacerCortes.setEnabled(False)
        self.dlg.btnLlamarCalcular.setEnabled(False)
        self.dlg.btnCancelarSub.setEnabled(False)
        self.dlg.comboPredios.setEnabled(False)
        self.enClaves = True

#-------------------------------------------------------------------------

    def irAreas(self):

        self.limpiarAreas()
        self.rubberMarca.reset(QgsWkbTypes.PolygonGeometry)
        geoTemp = QgsGeometry.fromWkt(self.geomEnDivision.asWkt())
        self.subdividirPredio(geoTemp, True)
        self.listaColores = []
        for geom in self.geomsAreas:
            if geom.area() <= 0:
                continue
            newRub = self.eventos.crearNuevoRubberPoly()

            n = 0  #Obtenemos todos los vertices de la geometria en division
            ver = geom.vertexAt(0)
            listaVertices = []
            while (ver != QgsPoint(0, 0)):
                n += 1
                ver = geom.vertexAt(n)
                listaVertices.append(ver)

            listaVertices.append(listaVertices[0])
            rangoVertices = len(listaVertices)
            for x in range(0, rangoVertices - 2):
                vertice = listaVertices[x]
                newRub.addPoint(QgsPointXY(vertice.x(), vertice.y()), True)

            newRub.show()
            self.rubbersAreas.append(newRub)

        self.VentanaAreas.mostrarAreas()
        #for geom in self.geomsAreas:

#--------------------------------------------------------------------

    def limpiarAreas(self):
        for rub in self.rubbersAreas:
            rub.reset(QgsWkbTypes.PolygonGeometry)

        self.rubbersAreas = []

#------------------------------------------------------------------

    def quitarAreas(self):
        self.limpiarAreas()
        n = 0  #Obtenemos todos los vertices de la geometria en division
        if self.geomEnDivision == None:
            return
        ver = self.geomEnDivision.vertexAt(0)
        listaVertices = []
        while (ver != QgsPoint(0, 0)):
            n += 1
            ver = self.geomEnDivision.vertexAt(n)
            listaVertices.append(ver)

        listaVertices.append(listaVertices[0])
        rangoVertices = len(listaVertices)
        for x in range(0, rangoVertices - 2):
            vertice = listaVertices[x]
            self.rubberMarca.addPoint(QgsPointXY(vertice.x(), vertice.y()),
                                      True)
        self.rubberMarca.show(
        )  #Aqui pintamos de amarillito la geometria en division

#--------------------------------------------------------------------------

    def closeEvent(self, evnt):
        if self.enClaves:
            evnt.ignore()
Example #47
0
class QgepMapToolConnectNetworkElements(QgsMapTool):
    """
    This map tool connects wastewater networkelements.

    It works on two lists of layers:
      source layers with fields with a foreign key to a networkelement
      target layers which depict networkelements (reaches and network nodes)

    The tool will snap to source layers first and once one is chosen to a target layer.

    It will then ask which field(s) should be connected and perform the update on the database
    """

    def __init__(self, iface, action):
        QgsMapTool.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.action = action

        self.rbline = QgsRubberBand(self.iface.mapCanvas(), QGis.Line)
        self.rbline.setColor(QColor('#f4530e'))
        self.rbline.setWidth(3)
        self.rbmarkers = QgsRubberBand(self.iface.mapCanvas(), QGis.Point)
        self.rbmarkers.setColor(QColor('#f4530e'))
        self.rbmarkers.setIconSize(6)

        self.source_snapper = QgepAreaSnapper(self.iface.mapCanvas())
        self.target_snapper = QgepAreaSnapper(self.iface.mapCanvas())

        self.source_feature = QgsFeature()
        self.rb_source_feature = QgsRubberBand(self.iface.mapCanvas())
        self.rb_source_feature.setColor(QColor('#f49e79'))
        self.rb_source_feature.setWidth(3)
        self.target_feature = QgsFeature()
        self.rb_target_feature = QgsRubberBand(self.iface.mapCanvas())
        self.rb_target_feature.setColor(QColor('#f49e79'))
        self.rb_target_feature.setWidth(3)

    def activate(self):
        """
        Called by QGIS whenever the tool is activated.
        """
        source_snap_layers = list()
        target_snap_layers = list()

        # A dict of layers and the fields that are foreign keys
        # pointing to wastewater networkelements
        self.network_element_sources = {
            QgepLayerManager.layer('vw_qgep_reach'): [
                ('rp_to_fk_wastewater_networkelement',
                 QCoreApplication.translate('QgepMapToolConnectNetworkElements', 'Reach Point To')),
                ('rp_from_fk_wastewater_networkelement',
                 QCoreApplication.translate('QgepMapToolConnectNetworkElements', 'Reach Point From'))
            ],
            QgepLayerManager.layer('od_catchment_area'): [
                ('fk_wastewater_networkelement_rw_current', QCoreApplication.translate(
                    'QgepMapToolConnectNetworkElements', 'Rainwater current')),
                ('fk_wastewater_networkelement_rw_planned', QCoreApplication.translate(
                    'QgepMapToolConnectNetworkElements', 'Rainwater planned')),
                ('fk_wastewater_networkelement_ww_current', QCoreApplication.translate(
                    'QgepMapToolConnectNetworkElements', 'Wastewater current')),
                ('fk_wastewater_networkelement_ww_planned', QCoreApplication.translate(
                    'QgepMapToolConnectNetworkElements', 'Wastewater planned'))
            ]
        }

        # A list of layers that can be used as wastewater networkelement
        # targets
        self.network_element_targets = [
            QgepLayerManager.layer('vw_wastewater_node'),
            QgepLayerManager.layer('vw_qgep_reach')
        ]

        for layer in self.network_element_sources.keys():
            if layer:
                snap_layer = QgsSnappingUtils.LayerConfig(
                    layer, QgsPointLocator.All, 16, QgsTolerance.Pixels)
                source_snap_layers.append(snap_layer)

        for layer in self.network_element_targets:
            if layer:
                snap_layer = QgsSnappingUtils.LayerConfig(
                    layer, QgsPointLocator.All, 16, QgsTolerance.Pixels)
                target_snap_layers.append(snap_layer)

        self.source_snapper.setLayers(source_snap_layers)
        self.source_snapper.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced)

        self.target_snapper.setLayers(target_snap_layers)
        self.target_snapper.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced)

        self.reset()

        self.action.setChecked(True)

        self.iface.mapCanvas().setCursor(QCursor(Qt.CrossCursor))

    def canvasMoveEvent(self, event):
        """
        When the mouse moves, update the rubberbands.
        """
        pt = event.originalMapPoint()
        snap_match = self.snapper.snapToMap(pt)

        if snap_match.isValid():
            if snap_match.type() != QgsPointLocator.Area:
                pt = snap_match.point()
            self.matchpoint = pt

            if self.source_match:
                if self.target_feature.id() != snap_match.featureId():
                    self.target_feature = self.get_feature_for_match(
                        snap_match)
                    self.rb_target_feature.setToGeometry(
                        self.target_feature.geometry(), snap_match.layer())
                self.rb_target_feature.show()
                self.rbmarkers.movePoint(pt)
            else:
                if self.source_feature.id() != snap_match.featureId():
                    self.source_feature = self.get_feature_for_match(
                        snap_match)
                    self.rb_source_feature.setToGeometry(
                        self.source_feature.geometry(), snap_match.layer())
                self.rb_source_feature.show()
                self.rbmarkers.movePoint(pt, 0)
            self.rbmarkers.show()
        else:
            self.rbmarkers.hide()
            if self.source_match:
                self.rb_target_feature.hide()
            else:
                self.rb_source_feature.hide()

        self.rbline.movePoint(pt)

        self.snapresult = snap_match

    def canvasReleaseEvent(self, event):
        """
        On a click update the rubberbands and the snapping results if it's a left click. Reset if it's a right click.
        """
        if event.button() == Qt.LeftButton:
            if self.snapresult.isValid():
                if self.source_match:
                    self.connect_features(self.source_match, self.snapresult)
                else:
                    self.rbline.show()
                    self.rbline.addPoint(self.matchpoint)
                    self.source_match = self.snapresult
                    self.snapper = self.target_snapper
        else:
            self.reset()

    def deactivate(self):
        """
        Called by QGIS whenever this tool is deactivated.
        """
        self.reset()
        self.action.setChecked(False)

    def reset(self):
        """
        Resets the tool to a pristine state
        """
        self.source_match = None
        self.rbline.hide()
        self.rbline.reset()
        self.rbmarkers.hide()
        self.rbmarkers.reset(QGis.Point)
        self.rbmarkers.addPoint(QgsPoint())
        self.snapresult = None
        self.source_match = None
        self.snapper = self.source_snapper
        self.source_feature = QgsFeature()
        self.target_feature = QgsFeature()
        self.rb_source_feature.reset()
        self.rb_target_feature.reset()

    def get_feature_for_match(self, match):
        """
        Get the feature for a snapping result
        @param match: The QgsPointLocator.SnapMatch object
        @return: A feature
        """
        return next(match.layer().getFeatures(QgsFeatureRequest().setFilterFid(match.featureId())))

    def connect_features(self, source, target):
        """
        Connects the source feature with the target feature.

        @param source: A QgsPointLocator.Match object. Its foreign key will be updated.
                       A dialog will be opened which asks the user for which foreign key(s) he wants to update.
        @param target: A QgsPointLocator.Match object. This feature will be used as link target.
                       Its obj_id attribute will be used as primary key.
        """
        dlg = QDialog(self.iface.mainWindow())
        dlg.setWindowTitle(self.tr('Select properties to connect'))
        dlg.setLayout(QFormLayout())

        properties = list()

        for prop in self.network_element_sources[source.layer()]:
            cbx = QCheckBox(prop[1])
            cbx.setObjectName(prop[0])
            properties.append(cbx)
            dlg.layout().addWidget(cbx)

        btn_box = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        dlg.layout().addWidget(btn_box)
        btn_box.accepted.connect(dlg.accept)
        btn_box.rejected.connect(dlg.reject)

        source_feature = self.get_feature_for_match(source)
        target_feature = self.get_feature_for_match(target)

        if dlg.exec_():
            for cbx in properties:
                if cbx.isChecked():
                    source_feature[cbx.objectName()] = target_feature['obj_id']
            if source.layer().updateFeature(source_feature):
                self.iface.messageBar().pushMessage('QGEP',
                                                    self.tr('Connected {} to {}').format(
                                                        source_feature[
                                                            'identifier'],
                                                        target_feature['identifier']),
                                                    QgsMessageBar.INFO, 5)
            else:
                self.iface.messageBar().pushMessage('QGEP',
                                                    self.tr(
                                                        'Error connecting features'),
                                                    QgsMessageBar.WARNING, 5)

        self.reset()
Example #48
0
class MapWidget(Ui_CanvasWidget, QMainWindow):
    def __init__(self, parent=None):
        super(MapWidget, self).__init__(parent)
        self.setupUi(self)

        self.firstshow = True
        self.layerbuttons = []
        self.editfeaturestack = []
        self.lastgpsposition = None
        self.project = None
        self.gps = None
        self.gpslogging = None
        self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas))

        self.canvas.setCanvasColor(Qt.white)
        self.canvas.enableAntiAliasing(True)
        self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor)

        if hasattr(self.canvas, 'setParallelRenderingEnabled'):
            self.canvas.setParallelRenderingEnabled(True)

        pal = QgsPalLabeling()
        self.canvas.mapRenderer().setLabelingEngine(pal)
        self.canvas.setFrameStyle(QFrame.NoFrame)

        self.editgroup = QActionGroup(self)
        self.editgroup.setExclusive(True)
        self.editgroup.addAction(self.actionPan)
        self.editgroup.addAction(self.actionZoom_In)
        self.editgroup.addAction(self.actionZoom_Out)
        self.editgroup.addAction(self.actionInfo)

        self.actionGPS = GPSAction(":/icons/gps", self.canvas, self)
        self.projecttoolbar.addAction(self.actionGPS)

        gpsspacewidget= QWidget()
        gpsspacewidget.setMinimumWidth(30)
        gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.topspaceraction = self.projecttoolbar.insertWidget(self.actionGPS, gpsspacewidget)

        self.dataentryselection = QAction(self.projecttoolbar)
        self.dataentryaction = self.projecttoolbar.insertAction(self.topspaceraction, self.dataentryselection)
        self.dataentryselection.triggered.connect(self.select_data_entry)

        self.marker = GPSMarker(self.canvas)
        self.marker.hide()

        self.currentfeatureband = QgsRubberBand(self.canvas)
        self.currentfeatureband.setIconSize(20)
        self.currentfeatureband.setWidth(10)
        self.currentfeatureband.setColor(QColor(186, 93, 212, 76))

        self.gpsband = QgsRubberBand(self.canvas)
        self.gpsband.setColor(QColor(0, 0, 212, 76))
        self.gpsband.setWidth(5)

        RoamEvents.editgeometry.connect(self.queue_feature_for_edit)
        RoamEvents.selectioncleared.connect(self.clear_selection)
        RoamEvents.selectionchanged.connect(self.highlight_selection)
        RoamEvents.featureformloaded.connect(self.feature_form_loaded)

        self.connectButtons()

    def init_qgisproject(self, doc):
        parser = ProjectParser(doc)
        canvasnode = parser.canvasnode
        self.canvas.freeze()
        self.canvas.mapRenderer().readXML(canvasnode)
        self.canvaslayers = parser.canvaslayers()
        self.canvas.setLayerSet(self.canvaslayers)
        #red = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorRedPart", 255 )[0];
        #green = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorGreenPart", 255 )[0];
        #blue = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorBluePart", 255 )[0];
        #color = QColor(red, green, blue);
        #self.canvas.setCanvasColor(color)
        self.canvas.updateScale()
        return self.canvas.mapRenderer().destinationCrs()

    def showEvent(self, *args, **kwargs):
        if self.firstshow:
            self.canvas.refresh()
            self.canvas.repaint()
            self.firstshow = False

    def feature_form_loaded(self, form, feature, project, editmode):
        self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer)

    def highlight_selection(self, results):
        self.clear_selection()
        for layer, features in results.iteritems():
            band = self.selectionbands[layer]
            band.setColor(QColor(255, 0, 0, 200))
            band.setIconSize(20)
            band.setWidth(2)
            band.setBrushStyle(Qt.NoBrush)
            band.reset(layer.geometryType())
            for feature in features:
                band.addGeometry(feature.geometry(), layer)

    def highlight_active_selection(self, layer, feature, features):
        self.clear_selection()
        self.highlight_selection({layer: features})
        self.currentfeatureband.setToGeometry(feature.geometry(), layer)

    def clear_selection(self):
        # Clear the main selection rubber band
        self.currentfeatureband.reset()
        # Clear the rest
        for band in self.selectionbands.itervalues():
            band.reset()

        self.editfeaturestack = []

    def queue_feature_for_edit(self, form, feature):
        def trigger_default_action():
            for action in self.projecttoolbar.actions():
                if action.property('dataentry') and action.isdefault:
                    action.trigger()
                    break

        self.editfeaturestack.append((form, feature))
        self.load_form(form)
        trigger_default_action()

    def clear_temp_objects(self):
        def clear_tool_band():
            """
            Clear the rubber band of the active tool if it has one
            """
            tool = self.canvas.mapTool()
            try:
                tool.clearBand()
            except AttributeError:
                # No clearBand method found, but that's cool.
                pass

        self.currentfeatureband.reset()
        clear_tool_band()


    def settings_updated(self, settings):
        self.actionGPS.updateGPSPort()
        gpslogging = settings.get('gpslogging', True)
        if self.gpslogging:
            self.gpslogging.logging = gpslogging

    def set_gps(self, gps, logging):
        self.gps = gps
        self.gpslogging = logging
        self.gps.gpsposition.connect(self.gps_update_canvas)
        self.gps.firstfix.connect(self.gps_first_fix)
        self.gps.gpsdisconnected.connect(self.gps_disconnected)

    def gps_update_canvas(self, position, gpsinfo):
        # Recenter map if we go outside of the 95% of the area
        if self.gpslogging.logging:
            self.gpsband.addPoint(position)
            self.gpsband.show()

        if roam.config.settings.get('gpscenter', True):
            if not self.lastgpsposition == position:
                self.lastposition = position
                rect = QgsRectangle(position, position)
                extentlimt = QgsRectangle(self.canvas.extent())
                extentlimt.scale(0.95)

                if not extentlimt.contains(position):
                    self.zoom_to_location(position)

        self.marker.show()
        self.marker.setCenter(position)

    def gps_first_fix(self, postion, gpsinfo):
        zoomtolocation = roam.config.settings.get('gpszoomonfix', True)
        if zoomtolocation:
            self.canvas.zoomScale(1000)
            self.zoom_to_location(postion)

    def zoom_to_location(self, position):
        rect = QgsRectangle(position, position)
        self.canvas.setExtent(rect)
        self.canvas.refresh()

    def gps_disconnected(self):
        self.marker.hide()

    def select_data_entry(self):
        def showformerror(form):
            pass

        def actions():
            for form in self.project.forms:
                action = form.createuiaction()
                valid, failreasons = form.valid
                if not valid:
                    roam.utils.warning("Form {} failed to load".format(form.label))
                    roam.utils.warning("Reasons {}".format(failreasons))
                    action.triggered.connect(partial(showformerror, form))
                else:
                    action.triggered.connect(partial(self.load_form, form))
                yield action

        formpicker = PickActionDialog(msg="Select data entry form")
        formpicker.addactions(actions())
        formpicker.exec_()

    def project_loaded(self, project):
        self.project = project
        self.actionPan.trigger()
        try:
            firstform = project.forms[0]
            self.load_form(firstform)
            self.dataentryselection.setVisible(True)
        except IndexError:
            self.dataentryselection.setVisible(False)

        # Enable the raster layers button only if the project contains a raster layer.
        layers = QgsMapLayerRegistry.instance().mapLayers().values()
        hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers)
        self.actionRaster.setEnabled(hasrasters)
        self.defaultextent = self.canvas.extent()
        roam.utils.info("Extent: {}".format(self.defaultextent.toString()))

        self.infoTool.selectionlayers = project.selectlayersmapping()

        self.canvas.freeze(False)
        self.canvas.refresh()

    def setMapTool(self, tool, *args):
        self.canvas.setMapTool(tool)

    def connectButtons(self):
        def connectAction(action, tool):
            action.toggled.connect(partial(self.setMapTool, tool))

        def cursor(name):
            pix = QPixmap(name)
            pix = pix.scaled(QSize(24,24))
            return QCursor(pix)

        self.zoomInTool = QgsMapToolZoom(self.canvas, False)
        self.zoomOutTool = QgsMapToolZoom(self.canvas, True)
        self.panTool = PanTool(self.canvas)
        self.infoTool = InfoTool(self.canvas)

        connectAction(self.actionZoom_In, self.zoomInTool)
        connectAction(self.actionZoom_Out, self.zoomOutTool)
        connectAction(self.actionPan, self.panTool)
        connectAction(self.actionInfo, self.infoTool)

        self.zoomInTool.setCursor(cursor(':/icons/in'))
        self.zoomOutTool.setCursor(cursor(':/icons/out'))
        self.infoTool.setCursor(cursor(':/icons/info'))

        self.actionRaster.triggered.connect(self.toggleRasterLayers)

        self.infoTool.infoResults.connect(RoamEvents.selectionchanged.emit)

        self.actionHome.triggered.connect(self.homeview)

    def homeview(self):
        """
        Zoom the mapview canvas to the extents the project was opened at i.e. the
        default extent.
        """
        self.canvas.setExtent(self.defaultextent)
        self.canvas.refresh()

    def load_form(self, form):
        self.clearCapatureTools()
        self.dataentryselection.setIcon(QIcon(form.icon))
        self.dataentryselection.setText(form.icontext)
        self.create_capture_buttons(form)

    def create_capture_buttons(self, form):
        tool = form.getMaptool()(self.canvas)
        for action in tool.actions:
            # Create the action here.
            if action.ismaptool:
                action.toggled.connect(partial(self.setMapTool, tool))

            # Set the action as a data entry button so we can remove it later.
            action.setProperty("dataentry", True)
            self.editgroup.addAction(action)
            self.layerbuttons.append(action)
            self.projecttoolbar.insertAction(self.topspaceraction, action)
            action.setChecked(action.isdefault)

        if hasattr(tool, 'geometryComplete'):
            add = partial(self.add_new_feature, form)
            tool.geometryComplete.connect(add)
        else:
            tool.finished.connect(self.openForm)
            tool.error.connect(partial(self.showUIMessage, form.label))

    def add_new_feature(self, form, geometry):
        """
        Add a new new feature to the given layer
        """
        # TODO Extract into function.
        # NOTE This function is doing too much, acts as add and also edit.
        layer = form.QGISLayer
        if layer.geometryType() in [QGis.WKBMultiLineString, QGis.WKBMultiPoint, QGis.WKBMultiPolygon]:
            geometry.convertToMultiType()

        try:
            form, feature = self.editfeaturestack.pop()
            self.editfeaturegeometry(form, feature, newgeometry=geometry)
            return
        except IndexError:
            pass

        layer = form.QGISLayer
        fields = layer.pendingFields()

        feature = QgsFeature(fields)
        feature.setGeometry(geometry)

        for index in xrange(fields.count()):
            pkindexes = layer.dataProvider().pkAttributeIndexes()
            if index in pkindexes and layer.dataProvider().name() == 'spatialite':
                continue

            value = layer.dataProvider().defaultValue(index)
            feature[index] = value

        RoamEvents.open_feature_form(form, feature, editmode=False)

    def editfeaturegeometry(self, form, feature, newgeometry):
        # TODO Extract into function.
        layer = form.QGISLayer
        layer.startEditing()
        feature.setGeometry(newgeometry)
        layer.updateFeature(feature)
        saved = layer.commitChanges()
        if not saved:
            map(roam.utils.error, layer.commitErrors())
        self.canvas.refresh()
        self.currentfeatureband.setToGeometry(feature.geometry(), layer)
        RoamEvents.editgeometry_complete.emit(form, feature)

    def clearCapatureTools(self):
        captureselected = False
        for action in self.projecttoolbar.actions():
            if action.objectName() == "capture" and action.isChecked():
                captureselected = True

            if action.property('dataentry'):
                self.projecttoolbar.removeAction(action)
        return captureselected

    def toggleRasterLayers(self):
        """
        Toggle all raster layers on or off.
        """
        if not self.canvaslayers:
            return

        #Freeze the canvas to save on UI refresh
        self.canvas.freeze()
        for layer in self.canvaslayers:
            if layer.layer().type() == QgsMapLayer.RasterLayer:
                layer.setVisible(not layer.isVisible())
                # Really!? We have to reload the whole layer set every time?
            # WAT?
        self.canvas.setLayerSet(self.canvaslayers)
        self.canvas.freeze(False)
        self.canvas.refresh()

    def cleanup(self):
        self.gpsband.reset()
        self.gpsband.hide()
        self.clear_selection()
        self.clear_temp_objects()
        self.clearCapatureTools()
        self.canvas.freeze()
        self.canvas.clear()
        self.canvas.freeze(False)
        for action in self.layerbuttons:
            self.editgroup.removeAction(action)
Example #49
0
class Qgis2threejsDialog(QDialog):
  STYLE_MAX_COUNT = 4

  def __init__(self, iface, properties=None):
    QDialog.__init__(self, iface.mainWindow())
    self.iface = iface

    self.templateType = None
    self.currentItem = None
    self.currentPage = None
    topItemCount = len(ObjectTreeItem.topItemNames)
    if properties is None:
      self.properties = [None] * topItemCount
      for i in range(ObjectTreeItem.ITEM_OPTDEM, topItemCount):
        self.properties[i] = {}
    else:
      self.properties = properties

    # Set up the user interface from Designer.
    self.ui = ui = Ui_Qgis2threejsDialog()
    ui.setupUi(self)

    self.setWindowFlags(self.windowFlags() | Qt.WindowMinimizeButtonHint)
    ui.lineEdit_OutputFilename.setPlaceholderText("[Temporary file]")
    ui.progressBar.setVisible(False)
    ui.label_MessageIcon.setVisible(False)

    ui.pushButton_Run.clicked.connect(self.run)
    ui.pushButton_Close.clicked.connect(self.reject)

    # set up map tool
    self.previousMapTool = None
    self.mapTool = RectangleMapTool(iface.mapCanvas())
    #self.mapTool = PointMapTool(iface.mapCanvas())

    # set up the template combo box
    self.initTemplateList()
    self.ui.comboBox_Template.currentIndexChanged.connect(self.currentTemplateChanged)

    # set up the properties pages
    self.pages = {}
    self.pages[ppages.PAGE_WORLD] = ppages.WorldPropertyPage(self)
    self.pages[ppages.PAGE_CONTROLS] = ppages.ControlsPropertyPage(self)
    self.pages[ppages.PAGE_DEM] = ppages.DEMPropertyPage(self)
    self.pages[ppages.PAGE_VECTOR] = ppages.VectorPropertyPage(self)
    container = ui.propertyPagesContainer
    for page in self.pages.itervalues():
      page.hide()
      container.addWidget(page)

    # build object tree
    self.topItemPages = {ObjectTreeItem.ITEM_WORLD: ppages.PAGE_WORLD, ObjectTreeItem.ITEM_CONTROLS: ppages.PAGE_CONTROLS, ObjectTreeItem.ITEM_DEM: ppages.PAGE_DEM}
    self.initObjectTree()
    self.ui.treeWidget.currentItemChanged.connect(self.currentObjectChanged)
    self.ui.treeWidget.itemChanged.connect(self.objectItemChanged)
    self.currentTemplateChanged()   # update item visibility

    ui.toolButton_Browse.clicked.connect(self.browseClicked)

    #iface.mapCanvas().mapToolSet.connect(self.mapToolSet)    # to show button to enable own map tool

    self.localBrowsingMode = True
    self.rb_quads = self.rb_point = None
    self.objectTypeManager = ObjectTypeManager()

  def showMessageBar(self, text, level=QgsMessageBar.INFO):
    # from src/gui/qgsmessagebaritem.cpp
    if level == QgsMessageBar.CRITICAL:
      msgIcon = "/mIconCritical.png"
      bgColor = "#d65253"
    elif level == QgsMessageBar.WARNING:
      msgIcon = "/mIconWarn.png"
      bgColor = "#ffc800"
    else:
      msgIcon = "/mIconInfo.png"
      bgColor = "#e7f5fe"
    stylesheet = "QLabel {{ background-color:{0}; }}".format(bgColor)

    label = self.ui.label_MessageIcon
    label.setPixmap(QgsApplication.getThemeIcon(msgIcon).pixmap(24))
    label.setStyleSheet(stylesheet)
    label.setVisible(True)

    label = self.ui.label_Status
    label.setText(text)
    label.setStyleSheet(stylesheet)

  def clearMessageBar(self):
    self.ui.label_MessageIcon.setVisible(False)
    self.ui.label_Status.setText("")
    self.ui.label_Status.setStyleSheet("QLabel { background-color: rgba(0, 0, 0, 0); }")

  def initTemplateList(self):
    cbox = self.ui.comboBox_Template
    cbox.clear()
    templateDir = QDir(tools.templateDir())
    for i, entry in enumerate(templateDir.entryList(["*.html", "*.htm"])):
      cbox.addItem(entry)

      config = tools.getTemplateConfig(templateDir.filePath(entry))
      # get template type
      templateType = config.get("type", "plain")
      cbox.setItemData(i, templateType, Qt.UserRole)

      # set tool tip text
      desc = config.get("description", "")
      if desc:
        cbox.setItemData(i, desc, Qt.ToolTipRole)

    # select the last used template
    templateName = QSettings().value("/Qgis2threejs/lastTemplate", "", type=unicode)
    if templateName:
      index = cbox.findText(templateName)
      if index != -1:
        cbox.setCurrentIndex(index)
      return index
    return -1

  def initObjectTree(self):
    tree = self.ui.treeWidget
    tree.clear()

    # add vector and raster layers into tree widget
    topItems = []
    for index, itemName in enumerate(ObjectTreeItem.topItemNames):
      item = QTreeWidgetItem(tree, [itemName])
      item.setData(0, Qt.UserRole, index)
      topItems.append(item)

    optDEMChecked = False
    for layer in self.iface.legendInterface().layers():
      layerType = layer.type()
      if layerType not in (QgsMapLayer.VectorLayer, QgsMapLayer.RasterLayer):
        continue

      parentId = None
      if layerType == QgsMapLayer.VectorLayer:
        geometry_type = layer.geometryType()
        if geometry_type in [QGis.Point, QGis.Line, QGis.Polygon]:
          parentId = ObjectTreeItem.ITEM_POINT + geometry_type    # - QGis.Point
      elif layerType == QgsMapLayer.RasterLayer and layer.providerType() == "gdal" and layer.bandCount() == 1:
        parentId = ObjectTreeItem.ITEM_OPTDEM
      if parentId is None:
        continue

      item = QTreeWidgetItem(topItems[parentId], [layer.name()])
      isVisible = self.properties[parentId].get(layer.id(), {}).get("visible", False)   #self.iface.legendInterface().isLayerVisible(layer)
      check_state = Qt.Checked if isVisible else Qt.Unchecked
      item.setData(0, Qt.CheckStateRole, check_state)
      item.setData(0, Qt.UserRole, layer.id())
      if parentId == ObjectTreeItem.ITEM_OPTDEM and isVisible:
        optDEMChecked = True

    for item in topItems:
      if item.data(0, Qt.UserRole) != ObjectTreeItem.ITEM_OPTDEM or optDEMChecked:
        tree.expandItem(item)

  def saveProperties(self, item, page):
    properties = page.properties()
    parent = item.parent()
    if parent is None:
      # top item: properties[topItemIndex]
      self.properties[item.data(0, Qt.UserRole)] = properties
    else:
      # layer item: properties[topItemIndex][layerId]
      topItemIndex = parent.data(0, Qt.UserRole)
      self.properties[topItemIndex][item.data(0, Qt.UserRole)] = properties

    if debug_mode:
      qDebug(str(self.properties))

  def currentTemplateChanged(self, index=None):
    cbox = self.ui.comboBox_Template
    templateType = cbox.itemData(cbox.currentIndex(), Qt.UserRole)
    if templateType == self.templateType:
      return

    tree = self.ui.treeWidget
    for i, name in enumerate(ObjectTreeItem.topItemNames):
      hidden = (templateType == "sphere" and name != "Controls")
      tree.topLevelItem(i).setHidden(hidden)

    itemToBeSelected = ObjectTreeItem.ITEM_CONTROLS if templateType == "sphere" else ObjectTreeItem.ITEM_DEM
    tree.setCurrentItem(tree.topLevelItem(itemToBeSelected))

    self.clearMessageBar()
    if templateType != "sphere":
      # show message if crs unit is degrees
      mapSettings = self.iface.mapCanvas().mapSettings() if QGis.QGIS_VERSION_INT >= 20300 else self.iface.mapCanvas().mapRenderer()
      if mapSettings.destinationCrs().mapUnits() in [QGis.Degrees]:
        self.showMessageBar("The unit of current CRS is degrees, so terrain will not appear well.", QgsMessageBar.WARNING)

    self.templateType = templateType

  def currentObjectChanged(self, currentItem, previousItem):
    # save properties of previous item
    if previousItem and self.currentPage:
      self.saveProperties(previousItem, self.currentPage)

    self.currentItem = currentItem
    self.currentPage = None
    # hide all pages
    for page in self.pages.itervalues():
      page.hide()

    parent = currentItem.parent()
    if parent is None:
      topItemIndex = currentItem.data(0, Qt.UserRole)
      pageType = self.topItemPages.get(topItemIndex, ppages.PAGE_NONE)
      page = self.pages.get(pageType, None)
      if page is None:
        return

      page.setup(self.properties[topItemIndex])
      page.show()

    else:
      parentId = parent.data(0, Qt.UserRole)
      layerId = currentItem.data(0, Qt.UserRole)
      if layerId is None:
        return

      layer = QgsMapLayerRegistry.instance().mapLayer(layerId)
      if layer is None:
        return

      layerType = layer.type()
      if layerType == QgsMapLayer.RasterLayer:
        page = self.pages[ppages.PAGE_DEM]
        page.setup(self.properties[parentId].get(layerId, None), layer, False)
      elif layerType == QgsMapLayer.VectorLayer:
        page = self.pages[ppages.PAGE_VECTOR]
        page.setup(self.properties[parentId].get(layerId, None), layer)
      else:
        return

      page.show()

    self.currentPage = page

  def objectItemChanged(self, item, column):
    parent = item.parent()
    if parent is None:
      return

    if item == self.currentItem:
      if self.currentPage:
        # update enablement of property widgets
        self.currentPage.itemChanged(item)
    else:
      # select changed item
      self.ui.treeWidget.setCurrentItem(item)

      # set visible property
      #visible = item.data(0, Qt.CheckStateRole) == Qt.Checked
      #parentId = parent.data(0, Qt.UserRole)
      #layerId = item.data(0, Qt.UserRole)
      #self.properties[parentId].get(layerId, {})["visible"] = visible

  def primaryDEMChanged(self, layerId):
    tree = self.ui.treeWidget
    parent = tree.topLevelItem(ObjectTreeItem.ITEM_OPTDEM)
    tree.blockSignals(True)
    for i in range(parent.childCount()):
      item = parent.child(i)
      isPrimary = item.data(0, Qt.UserRole) == layerId
      item.setDisabled(isPrimary)
    tree.blockSignals(False)

  def numericFields(self, layer):
    # get attributes of a sample feature and create numeric field name list
    numeric_fields = []
    f = QgsFeature()
    layer.getFeatures().nextFeature(f)
    for field in f.fields():
      isNumeric = False
      try:
        float(f.attribute(field.name()))
        isNumeric = True
      except:
        pass
      if isNumeric:
        numeric_fields.append(field.name())
    return numeric_fields

  def progress(self, percentage, statusMsg=None):
    ui = self.ui
    ui.progressBar.setValue(percentage)
    if percentage == 100:
      ui.progressBar.setVisible(False)
      ui.label_Status.setText("")
    else:
      ui.progressBar.setVisible(True)

    if statusMsg is not None:
      ui.label_Status.setText(statusMsg)
      ui.label_Status.repaint()

  def run(self):
    ui = self.ui
    filename = ui.lineEdit_OutputFilename.text()   # ""=Temporary file
    if filename != "" and QFileInfo(filename).exists() and QMessageBox.question(None, "Qgis2threejs", "Output file already exists. Overwrite it?", QMessageBox.Ok | QMessageBox.Cancel) != QMessageBox.Ok:
      return
    self.endPointSelection()

    # save properties of current object
    item = self.ui.treeWidget.currentItem()
    if item and self.currentPage:
      self.saveProperties(item, self.currentPage)

    ui.pushButton_Run.setEnabled(False)
    self.clearMessageBar()
    self.progress(0)

    canvas = self.iface.mapCanvas()
    cbox = self.ui.comboBox_Template
    templateName = cbox.currentText()
    templateType = cbox.itemData(cbox.currentIndex(), Qt.UserRole)
    htmlfilename = ui.lineEdit_OutputFilename.text()

    # world properties
    world = self.properties[ObjectTreeItem.ITEM_WORLD] or {}
    verticalExaggeration = world.get("lineEdit_zFactor", 1.5)
    verticalShift = world.get("lineEdit_zShift", 0)

    # export to javascript (three.js)
    mapTo3d = MapTo3D(canvas, verticalExaggeration=float(verticalExaggeration), verticalShift=float(verticalShift))
    context = OutputContext(templateName, templateType, mapTo3d, canvas, self.properties, self, self.objectTypeManager, self.localBrowsingMode)
    htmlfilename = exportToThreeJS(htmlfilename, context, self.progress)

    self.progress(100)
    ui.pushButton_Run.setEnabled(True)
    if htmlfilename is None:
      return
    self.clearRubberBands()

    # store last selections
    settings = QSettings()
    settings.setValue("/Qgis2threejs/lastTemplate", templateName)
    settings.setValue("/Qgis2threejs/lastControls", context.controls)

    # open browser
    if not tools.openHTMLFile(htmlfilename):
      return
    QDialog.accept(self)

  def reject(self):
    # save properties of current object
    item = self.ui.treeWidget.currentItem()
    if item and self.currentPage:
      self.saveProperties(item, self.currentPage)

    self.endPointSelection()
    self.clearRubberBands()
    QDialog.reject(self)

  def startPointSelection(self):
    canvas = self.iface.mapCanvas()
    if self.previousMapTool != self.mapTool:
      self.previousMapTool = canvas.mapTool()
    canvas.setMapTool(self.mapTool)
    self.pages[ppages.PAGE_DEM].toolButton_PointTool.setVisible(False)

  def endPointSelection(self):
    self.mapTool.reset()
    if self.previousMapTool is not None:
      self.iface.mapCanvas().setMapTool(self.previousMapTool)

  def mapToolSet(self, mapTool):
    return
    #TODO: unstable
    if mapTool != self.mapTool and self.currentPage is not None:
      if self.currentPage.pageType == ppages.PAGE_DEM and self.currentPage.isPrimary:
        self.currentPage.toolButton_PointTool.setVisible(True)

  def createRubberBands(self, quads, point=None):
    self.clearRubberBands()
    # create quads with rubber band
    self.rb_quads = QgsRubberBand(self.iface.mapCanvas(), QGis.Line)
    self.rb_quads.setColor(Qt.blue)
    self.rb_quads.setWidth(1)

    for quad in quads:
      points = []
      extent = quad.extent
      points.append(QgsPoint(extent.xMinimum(), extent.yMinimum()))
      points.append(QgsPoint(extent.xMinimum(), extent.yMaximum()))
      points.append(QgsPoint(extent.xMaximum(), extent.yMaximum()))
      points.append(QgsPoint(extent.xMaximum(), extent.yMinimum()))
      self.rb_quads.addGeometry(QgsGeometry.fromPolygon([points]), None)
      self.log(extent.toString())
    self.log("Quad count: %d" % len(quads))

    # create a point with rubber band
    if point:
      self.rb_point = QgsRubberBand(self.iface.mapCanvas(), QGis.Point)
      self.rb_point.setColor(Qt.red)
      self.rb_point.addPoint(point)

  def clearRubberBands(self):
    # clear quads and point
    if self.rb_quads:
      self.iface.mapCanvas().scene().removeItem(self.rb_quads)
      self.rb_quads = None
    if self.rb_point:
      self.iface.mapCanvas().scene().removeItem(self.rb_point)
      self.rb_point = None

  def browseClicked(self):
    directory = os.path.split(self.ui.lineEdit_OutputFilename.text())[0]
    if directory == "":
      directory = QDir.homePath()
    filename = QFileDialog.getSaveFileName(self, self.tr("Output filename"), directory, "HTML file (*.html *.htm)", options=QFileDialog.DontConfirmOverwrite)
    if filename != "":
      self.ui.lineEdit_OutputFilename.setText(filename)

  def log(self, msg):
    if debug_mode:
      qDebug(msg)
class VoGISProfilToolMainDialog(QDialog):
    def __init__(self, interface, settings):

        self.settings = settings
        self.iface = interface
        self.selectingVisibleRasters = False
        self.thread = None

        QDialog.__init__(self, interface.mainWindow())

        # Set up the user interface from Designer.
        self.ui = Ui_VoGISProfilToolMain()
        self.ui.setupUi(self)

        if self.settings.onlyHektoMode is True:
            self.ui.IDC_widRaster.hide()
            self.adjustSize()

        validator = QIntValidator(-32768, 32768, self)
        self.ui.IDC_tbNoDataExport.setValidator(validator)

        self.ui.IDC_tbFromX.setText('-30000')
        self.ui.IDC_tbFromY.setText('240000')
        self.ui.IDC_tbToX.setText('-20000')
        self.ui.IDC_tbToY.setText('230000')

        self.__addRastersToGui()
        self.__addPolygonsToGui()

        for line_lyr in self.settings.mapData.lines.lines():
            self.ui.IDC_cbLineLayers.addItem(line_lyr.name, line_lyr)

        if self.settings.mapData.lines.count() < 1:
            self.ui.IDC_rbDigi.setChecked(True)
            self.ui.IDC_rbShapeLine.setEnabled(False)

        #Einstellungen fuer Linie zeichen
        self.action = QAction(QIcon(":/plugins/vogisprofiltoolmain/icons/icon.png"), "VoGIS-Profiltool", self.iface.mainWindow())
        self.action.setWhatsThis("VoGIS-Profiltool")
        self.canvas = self.iface.mapCanvas()
        self.tool = ProfiletoolMapTool(self.canvas, self.action)
        self.savedTool = self.canvas.mapTool()
        self.polygon = False
        self.rubberband = QgsRubberBand(self.canvas, self.polygon)
        if QGis.QGIS_VERSION_INT >= 10900:
            #self.rubberband.setBrushStyle()
            self.rubberband.setLineStyle(Qt.SolidLine)
            self.rubberband.setWidth(4.0)
            self.rubberband.setColor(QColor(0, 255, 0))
            #http://www.qgis.org/api/classQgsRubberBand.html#a6f7cdabfcf69b65dfc6c164ce2d01fab
        self.pointsToDraw = []
        self.dblclktemp = None
        self.drawnLine = None

    def accept(self):
        try:
            #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", "ACCEPTED")

            #QgsMessageLog.logMessage('nodata: {0}'.format(self.settings.nodata_value), 'VoGis')
            self.settings.nodata_value = int(self.ui.IDC_tbNoDataExport.text())
            QgsMessageLog.logMessage('maindlg: nodata: {0}'.format(self.settings.nodata_value), 'VoGis')

            if self.settings.onlyHektoMode is True and self.settings.mapData.rasters.count() > 0:
                self.settings.onlyHektoMode = False

            if self.settings.onlyHektoMode is False:
                if self.settings.mapData.rasters.count() < 1:
                    #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", u"Keine Raster vorhanden. Zum Hektometrieren Dialog neu öffnen.")
                    #return
                    retVal = QMessageBox.warning(self.iface.mainWindow(),
                                                 "VoGIS-Profiltool",
                                                 QApplication.translate('code', 'Keine Rasterebene vorhanden oder sichtbar! Nur hektometrieren?', None, QApplication.UnicodeUTF8),
                                                 QMessageBox.Yes | QMessageBox.No,
                                                 QMessageBox.Yes)
                    if retVal == QMessageBox.No:
                        return
                    else:
                        self.settings.onlyHektoMode = True
                        self.settings.createHekto = True

            if self.__getSettingsFromGui() is False:
                return

            if self.settings.onlyHektoMode is False:
                if len(self.settings.mapData.rasters.selectedRasters()) < 1:
                    #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", "Kein Raster selektiert!")
                    #msg =
                    #QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", msg)
                    QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', 'Kein Raster selektiert!', None, QApplication.UnicodeUTF8))
                    return

            QgsMessageLog.logMessage('modeLine!=line: {0}'.format(self.settings.modeLine != enumModeLine.line), 'VoGis')
            QgsMessageLog.logMessage('customLine is None: {0}'.format(self.settings.mapData.customLine is None), 'VoGis')

            if self.settings.modeLine != enumModeLine.line and self.settings.mapData.customLine is None:
                QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', 'Keine Profillinie vorhanden!', None, QApplication.UnicodeUTF8))
                return

            if len(self.settings.mapData.polygons.selected_polygons()) > 0 and len(self.settings.mapData.rasters.selectedRasters()) > 1:
                raster_names = list(raster.name for raster in self.settings.mapData.rasters.selectedRasters())
                sel_raster, ok_clicked = QInputDialog.getItem(
                                                self.iface.mainWindow(),
                                                u'DHM?',
                                                u'Welches DHM soll zur Flächenverschneidung verwendet werden?',
                                                raster_names,
                                                0,
                                                False
                                                )
                if ok_clicked is False:
                    return
                self.settings.intersection_dhm_idx = raster_names.index(sel_raster)

            #self.rubberband.reset(self.polygon)
            #QDialog.accept(self)

            QApplication.setOverrideCursor(Qt.WaitCursor)

            create_profile = CreateProfile(self.iface, self.settings)
            thread = QThread(self)
            create_profile.moveToThread(thread)
            create_profile.finished.connect(self.profiles_finished)
            create_profile.error.connect(self.profiles_error)
            create_profile.progress.connect(self.profiles_progress)
            thread.started.connect(create_profile.create)
            thread.start(QThread.LowestPriority)
            self.thread = thread
            self.create_profile = create_profile
            self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
        except:
            QApplication.restoreOverrideCursor()
            ex = u'{0}'.format(traceback.format_exc())
            msg = 'Unexpected ERROR:\n\n{0}'.format(ex[:2000])
            QMessageBox.critical(self.iface.mainWindow(), "VoGIS-Profiltool", msg)


    def profiles_finished(self, profiles, intersections):
        QApplication.restoreOverrideCursor()
        self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True)
        #self.create_profile.deleteLater()
        self.thread.quit()
        self.thread.wait()
        #self.thread.deleteLater()

        #QGIS 2.0 http://gis.stackexchange.com/a/58754 http://gis.stackexchange.com/a/57090
        self.iface.mainWindow().statusBar().showMessage('VoGIS-Profiltool, {0} Profile'.format(len(profiles)))
        QgsMessageLog.logMessage(u'Profile Count: {0}'.format(len(profiles)), 'VoGis')

        if len(profiles) < 1:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', 'Es konnten keine Profile erstellt werden.', None, QApplication.UnicodeUTF8))
            return

        dlg = VoGISProfilToolPlotDialog(self.iface, self.settings, profiles, intersections)
        dlg.show()
        #result = self.dlg.exec_()
        dlg.exec_()


    def profiles_error(self, exception_string):
        QApplication.restoreOverrideCursor()
        QgsMessageLog.logMessage(u'Error during profile creation: {0}'.format(exception_string), 'VoGis')
        QMessageBox.critical(self.iface.mainWindow(), "VoGIS-Profiltool", exception_string)


    def profiles_progress(self, msg):
        self.iface.mainWindow().statusBar().showMessage(msg)
        self.ui.IDC_lblCreateStatus.setText(msg)
        #QgsMessageLog.logMessage(msg, 'VoGis')
        QApplication.processEvents()


    def reject(self):
        if not self.thread is None:
            if self.thread.isRunning():
                self.create_profile.abort()
                return

        self.rubberband.reset(self.polygon)
        QDialog.reject(self)


    def selectVisibleRasters(self):
        self.refreshRasterList()
        self.selectingVisibleRasters = True
        extCanvas = self.iface.mapCanvas().extent()
        #alle raster in den einstellunge deselektieren
        for r in self.settings.mapData.rasters.rasters():
            r.selected = False
        #alle raster in der ListView deselektieren
        for idx in xrange(self.ui.IDC_listRasters.count()):
            item = self.ui.IDC_listRasters.item(idx)
            item.setCheckState(Qt.Unchecked)
        #Raster im Extent selektieren
        for idx in xrange(self.ui.IDC_listRasters.count()):
            item = self.ui.IDC_listRasters.item(idx)
            if QGis.QGIS_VERSION_INT < 10900:
                raster = item.data(Qt.UserRole).toPyObject()
            else:
                raster = item.data(Qt.UserRole)
            for r in self.settings.mapData.rasters.rasters():
                if extCanvas.intersects(r.grid.extent()):
                    if r.id == raster.id:
                        r.selected = True
                        item.setCheckState(Qt.Checked)
        self.selectingVisibleRasters = False


    def lineLayerChanged(self, idx):
        if self.ui.IDC_rbShapeLine.isChecked() is False:
            self.ui.IDC_rbShapeLine.setChecked(True)
        if QGis.QGIS_VERSION_INT < 10900:
            lineLyr = (self.ui.IDC_cbLineLayers.itemData(self.ui.IDC_cbLineLayers.currentIndex()).toPyObject())
        else:
            lineLyr = (self.ui.IDC_cbLineLayers.itemData(self.ui.IDC_cbLineLayers.currentIndex()))
        lyr = lineLyr.line
        #QgsMessageLog.logMessage('{0}'.format(lyr.selectedFeatureCount()), 'VoGis')
        #QgsMessageLog.logMessage('{0}'.format(dir(lyr)), 'VoGis')
        if hasattr(lyr, 'selectedFeatureCount'):
            if(lyr.selectedFeatureCount() < 1):
                self.ui.IDC_chkOnlySelectedFeatures.setChecked(False)
            else:
                self.ui.IDC_chkOnlySelectedFeatures.setChecked(True)


    def valueChangedEquiDistance(self, val):
        if self.ui.IDC_rbEquiDistance.isChecked() is False:
            self.ui.IDC_rbEquiDistance.setChecked(True)


    def valueChangedVertexCount(self, val):
        if self.ui.IDC_rbVertexCount.isChecked() is False:
            self.ui.IDC_rbVertexCount.setChecked(True)


    def lvRasterItemChanged(self, item):
        if self.selectingVisibleRasters is True:
            return
        if item.checkState() == Qt.Checked:
            selected = True
        if item.checkState() == Qt.Unchecked:
            selected = False

        item_data = item.data(Qt.UserRole)
        if QGis.QGIS_VERSION_INT < 10900:
            raster_lyr = item_data.toPyObject()
        else:
            raster_lyr = item_data
        self.settings.mapData.rasters.getById(raster_lyr.id).selected = selected


    def lvPolygonItemChanged(self, item):
        if item.checkState() == Qt.Checked:
            selected = True
        if item.checkState() == Qt.Unchecked:
            selected = False

        item_data = item.data(Qt.UserRole)
        if QGis.QGIS_VERSION_INT < 10900:
            poly_lyr = item_data.toPyObject()
        else:
            poly_lyr = item_data
        self.settings.mapData.polygons.getById(poly_lyr.id).selected = selected


    def refreshRasterList(self):
        legend = self.iface.legendInterface()
        avail_lyrs = legend.layers()
        raster_coll = RasterCollection()

        for lyr in avail_lyrs:
            if legend.isLayerVisible(lyr):
                lyr_type = lyr.type()
                lyr_name = unicodedata.normalize('NFKD', unicode(lyr.name())).encode('ascii', 'ignore')
                if lyr_type == 1:
                    if lyr.bandCount() < 2:
                        new_raster = Raster(lyr.id(), lyr_name, lyr)
                        raster_coll.addRaster(new_raster)

        self.settings.mapData.rasters = raster_coll
        self.__addRastersToGui()

    def __addRastersToGui(self):
        self.ui.IDC_listRasters.clear()
        check = Qt.Unchecked
        if self.settings.mapData.rasters.count() == 1:
            check = Qt.Checked
            self.settings.mapData.rasters.rasters()[0].selected = True

        for raster_lyr in self.settings.mapData.rasters.rasters():
            item = QListWidgetItem(raster_lyr.name)
            item.setData(Qt.UserRole, raster_lyr)
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(check)
            self.ui.IDC_listRasters.addItem(item)


    def __addPolygonsToGui(self):
        self.ui.IDC_listPolygons.clear()
        check = Qt.Unchecked
        for poly_lyr in self.settings.mapData.polygons.polygons():
            item = QListWidgetItem(poly_lyr.name)
            item.setData(Qt.UserRole, poly_lyr)
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(check)
            self.ui.IDC_listPolygons.addItem(item)


    def drawLine(self):
        if self.ui.IDC_rbDigi.isChecked() is False:
            self.ui.IDC_rbDigi.setChecked(True)
        self.dblckltemp = None
        self.rubberband.reset(self.polygon)
        self.__cleanDigi()
        self.__activateDigiTool()
        self.canvas.setMapTool(self.tool)


    def __createDigiFeature(self, pnts):
        u = Util(self.iface)
        f = u.createQgLineFeature(pnts)
        self.settings.mapData.customLine = f


    def __lineFinished(self, position):
        mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"])
        newPoint = QgsPoint(mapPos.x(), mapPos.y())
        self.pointsToDraw.append(newPoint)
        #launch analyses
        self.iface.mainWindow().statusBar().showMessage(str(self.pointsToDraw))
        if len(self.pointsToDraw) < 2:
            self.__cleanDigi()
            self.pointsToDraw = []
            self.dblclktemp = newPoint
            self.drawnLine = None
            QMessageBox.warning(self, "VoGIS-Profiltool", QApplication.translate('code', 'Profillinie digitalisieren abgebrochen!', None, QApplication.UnicodeUTF8))
        self.drawnLine = self.__createDigiFeature(self.pointsToDraw)
        self.__cleanDigi()

        self.pointsToDraw = []
        self.dblclktemp = newPoint

    def __cleanDigi(self):
        self.pointsToDraw = []
        self.canvas.unsetMapTool(self.tool)
        self.canvas.setMapTool(self.savedTool)

    def __activateDigiTool(self):
        QObject.connect(self.tool, SIGNAL("moved"), self.__moved)
        QObject.connect(self.tool, SIGNAL("rightClicked"), self.__rightClicked)
        QObject.connect(self.tool, SIGNAL("leftClicked"), self.__leftClicked)
        QObject.connect(self.tool, SIGNAL("doubleClicked"), self.__doubleClicked)
        QObject.connect(self.tool, SIGNAL("deactivate"), self.__deactivateDigiTool)

    def __deactivateDigiTool(self):
        QObject.disconnect(self.tool, SIGNAL("moved"), self.__moved)
        QObject.disconnect(self.tool, SIGNAL("leftClicked"), self.__leftClicked)
        QObject.disconnect(self.tool, SIGNAL("rightClicked"), self.__rightClicked)
        QObject.disconnect(self.tool, SIGNAL("doubleClicked"), self.__doubleClicked)
        if QGis.QGIS_VERSION_INT < 10900:
            self.iface.mainWindow().statusBar().showMessage(QString(""))
        else:
            self.iface.mainWindow().statusBar().showMessage('')

    def __moved(self, position):
        if len(self.pointsToDraw) > 0:
            mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"])
            self.rubberband.reset(self.polygon)
            newPnt = QgsPoint(mapPos.x(), mapPos.y())
            if QGis.QGIS_VERSION_INT < 10900:
                for i in range(0, len(self.pointsToDraw)):
                    self.rubberband.addPoint(self.pointsToDraw[i])
                self.rubberband.addPoint(newPnt)
            else:
                pnts = self.pointsToDraw + [newPnt]
                self.rubberband.setToGeometry(QgsGeometry.fromPolyline(pnts),None)


    def __rightClicked(self, position):
        self.__lineFinished(position)

    def __leftClicked(self, position):
        mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"])
        newPoint = QgsPoint(mapPos.x(), mapPos.y())
        #if self.selectionmethod == 0:
        if newPoint == self.dblclktemp:
            self.dblclktemp = None
            return
        else:
            if len(self.pointsToDraw) == 0:
                self.rubberband.reset(self.polygon)
            self.pointsToDraw.append(newPoint)

    def __doubleClicked(self, position):
        pass

    #not in use right now
    def __lineCancel(self):
        pass

    def __getSettingsFromGui(self):
        self.settings.linesExplode = (self.ui.IDC_chkLinesExplode.checkState() == Qt.Checked)
        self.settings.linesMerge = (self.ui.IDC_chkLinesMerge.checkState() == Qt.Checked)
        self.settings.onlySelectedFeatures = (self.ui.IDC_chkOnlySelectedFeatures.checkState() == Qt.Checked)
        self.settings.equiDistance = self.ui.IDC_dblspinDistance.value()
        self.settings.vertexCnt = self.ui.IDC_dblspinVertexCnt.value()
        #self.settings.createHekto = (self.ui.IDC_chkCreateHekto.checkState() == Qt.Checked)
        self.settings.nodesAndVertices = (self.ui.IDC_chkNodesAndVertices.checkState() == Qt.Checked)

        if QGis.QGIS_VERSION_INT < 10900:
            self.settings.mapData.selectedLineLyr = (self.ui.IDC_cbLineLayers.itemData(
                                                     self.ui.IDC_cbLineLayers.currentIndex()
                                                     ).toPyObject()
                                                     )
        else:
            self.settings.mapData.selectedLineLyr = (self.ui.IDC_cbLineLayers.itemData(self.ui.IDC_cbLineLayers.currentIndex()))

        if self.settings.onlySelectedFeatures is True and self.settings.mapData.selectedLineLyr.line.selectedFeatureCount() < 1:
            QMessageBox.warning(self.iface.mainWindow(), "VoGIS-Profiltool", QApplication.translate('code', u'Der gewählte Layer hat keine selektierten Elemente.', None, QApplication.UnicodeUTF8))
            return False

        if self.ui.IDC_rbDigi.isChecked():
            self.settings.modeLine = enumModeLine.customLine
        elif self.ui.IDC_rbShapeLine.isChecked():
            self.settings.modeLine = enumModeLine.line
        else:
            #self.ui.IDC_rbStraigthLine
            self.settings.modeLine = enumModeLine.straightLine

        if self.ui.IDC_rbEquiDistance.isChecked():
            self.settings.modeVertices = enumModeVertices.equiDistant
        else:
            self.settings.modeVertices = enumModeVertices.vertexCnt

        if self.ui.IDC_rbStraigthLine.isChecked():
            ut = Util(self.iface)
            if ut.isFloat(self.ui.IDC_tbFromX.text(), QApplication.translate('code', 'Rechtswert von', None, QApplication.UnicodeUTF8)) is False:
                return False
            else:
                fromX = float(self.ui.IDC_tbFromX.text())
            if ut.isFloat(self.ui.IDC_tbFromY.text(), QApplication.translate('code', 'Hochwert von', None, QApplication.UnicodeUTF8)) is False:
                return False
            else:
                fromY = float(self.ui.IDC_tbFromY.text())
            if ut.isFloat(self.ui.IDC_tbToX.text(), QApplication.translate('code', 'Rechtswert nach', None, QApplication.UnicodeUTF8)) is False:
                return False
            else:
                toX = float(self.ui.IDC_tbToX.text())
            if ut.isFloat(self.ui.IDC_tbToY.text(), QApplication.translate('code', 'Hochwert nach', None, QApplication.UnicodeUTF8)) is False:
                return False
            else:
                toY = float(self.ui.IDC_tbToY.text())

            fromPnt = QgsPoint(fromX, fromY)
            toPnt = QgsPoint(toX, toY)

            self.settings.mapData.customLine = ut.createQgLineFeature([fromPnt, toPnt])

        return True
Example #51
0
class RectangleMapTool(QgsMapToolEmitPoint):
  def __init__(self, canvas):
    self.canvas = canvas
    QgsMapToolEmitPoint.__init__(self, self.canvas)

    self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon)
    self.rubberBand.setColor(QColor(255, 0, 0, 180))
    self.rubberBand.setWidth(1)
    self.reset()

  def reset(self):
    self.startPoint = self.endPoint = None
    self.isEmittingPoint = False
    self.rubberBand.reset(QGis.Polygon)

  def canvasPressEvent(self, e):
    self.startPoint = self.toMapCoordinates(e.pos())
    self.endPoint = self.startPoint
    self.isEmittingPoint = True
    self.showRect(self.startPoint, self.endPoint)

  def canvasReleaseEvent(self, e):
    self.isEmittingPoint = False
    self.emit(SIGNAL("rectangleCreated()"))

  def canvasMoveEvent(self, e):
    if not self.isEmittingPoint:
      return
    self.endPoint = self.toMapCoordinates(e.pos())
    self.showRect(self.startPoint, self.endPoint)

  def showRect(self, startPoint, endPoint):
    self.rubberBand.reset(QGis.Polygon)
    if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
      return

    point1 = QgsPoint(startPoint.x(), startPoint.y())
    point2 = QgsPoint(startPoint.x(), endPoint.y())
    point3 = QgsPoint(endPoint.x(), endPoint.y())
    point4 = QgsPoint(endPoint.x(), startPoint.y())

    self.rubberBand.addPoint(point1, False)
    self.rubberBand.addPoint(point2, False)
    self.rubberBand.addPoint(point3, False)
    self.rubberBand.addPoint(point4, True)	# true to update canvas
    self.rubberBand.show()

  def rectangle(self):
    if self.startPoint == None or self.endPoint == None:
      return None
    #elif self.startPoint.x() == self.endPoint.x() or self.startPoint.y() == self.endPoint.y():
    #  return None

    return QgsRectangle(self.startPoint, self.endPoint)

  def setRectangle(self, rect):
    if rect == self.rectangle():
      return False

    if rect == None:
      self.reset()
    else:
      self.startPoint = QgsPoint(rect.xMaximum(), rect.yMaximum())
      self.endPoint = QgsPoint(rect.xMinimum(), rect.yMinimum())
      self.showRect(self.startPoint, self.endPoint)
    return True
class MapTool(QgsMapTool):
    geometry_changed = pyqtSignal(QgsGeometry, bool)
    tool_deactivated = pyqtSignal()

    def __init__(self, canvas, cursorstyle=Qt.CrossCursor):
        self.canvas = canvas
        QgsMapTool.__init__(self, canvas)
        self.caller = self.sender()
        self.cursorStyle = cursorstyle
        self.active = False
        # get selection color
        selcolor = self.canvas.selectionColor()
        mycolor = QColor(selcolor.red(), selcolor.green(), selcolor.blue(), 40)
        self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)
        self.rb.setStrokeColor(QColor(255, 0, 0, 40))
        self.rb.setFillColor(mycolor)
        self.rb.setLineStyle(Qt.PenStyle(Qt.SolidLine))
        self.rb.setWidth(2)

    def setCursorStyle(self):
        cursor = QCursor()
        cursor.setShape(self.cursorStyle)
        self.setCursor(cursor)

    def activate(self):
        self.caller.setChecked(True)
        self.setCursorStyle()

    def deactivate(self):
        self.canvas.scene().removeItem(self.rb)
        self.tool_deactivated.emit()
        self.caller.setChecked(False)
        QgsMapTool.deactivate(self)

    def setGeometry(self, geo):
        self.rb.setToGeometry(geo)

    def canvasReleaseEvent(self, mouseEvent):
        if mouseEvent.button() == Qt.LeftButton:
            if not self.active:
                self.active = True
                self.geometry_changed.emit(QgsGeometry(), False)
                self.rb.reset(QgsWkbTypes.PolygonGeometry)
            self.rb.addPoint(mouseEvent.mapPoint())
            if self.rb.numberOfVertices() > 2:
                self.geometry_changed.emit(self.rb.asGeometry(), False)
        elif mouseEvent.button() == Qt.RightButton:
            if self.rb.numberOfVertices() > 3:
                self.active = False
                self.rb.removeLastPoint()
                self.rb.closePoints(
                )  #Ensures that a polygon geometry is closed and that the last vertex equals the first vertex
                geo = self.rb.asGeometry()
                self.geometry_changed.emit(geo, True)
            else:
                self.rb.reset(QgsWkbTypes.PolygonGeometry)

    def canvasMoveEvent(self, mouseEvent):
        if self.rb.numberOfVertices() > 1 and self.active:
            self.rb.removeLastPoint()
            self.rb.addPoint(mouseEvent.mapPoint())
        pass
Example #53
0
class RectangleMapTool(QgsMapTool):
    def __init__(self, canvas, callback):
        self.canvas = canvas
        QgsMapTool.__init__(self, self.canvas)
        self.callback = callback
        self.rubberBand = QgsRubberBand(self.canvas, True)
        self.rubberBand.setColor(QColor(227, 26, 28, 255))
        self.rubberBand.setWidth(5)
        self.rubberBand.setLineStyle(Qt.PenStyle(Qt.DashLine))
        self.reset()

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBand.reset(True)

    def canvasPressEvent(self, e):
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True
        self.showRect(self.startPoint, self.endPoint)

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False
        r = self.rectangle()
        if r is not None:
            # print "Rectangle:", r.xMinimum(), r.yMinimum(), r.xMaximum(), r.yMaximum()
            self.rubberBand.hide()
            self.callback(r)
            # self.deactivate()
        return None

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return
        self.endPoint = self.toMapCoordinates(e.pos())
        self.showRect(self.startPoint, self.endPoint)

    def showRect(self, startPoint, endPoint):
        self.rubberBand.reset(True)
        if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
            return

        point1 = QgsPoint(startPoint.x(), startPoint.y())
        point2 = QgsPoint(startPoint.x(), endPoint.y())
        point3 = QgsPoint(endPoint.x(), endPoint.y())
        point4 = QgsPoint(endPoint.x(), startPoint.y())

        self.rubberBand.addPoint(point1, False)
        self.rubberBand.addPoint(point2, False)
        self.rubberBand.addPoint(point3, False)
        self.rubberBand.addPoint(point4, False)
        self.rubberBand.addPoint(point1, True)  # true to update canvas
        self.rubberBand.show()

    def rectangle(self):
        if self.startPoint is None or self.endPoint is None:
            return None
        elif self.startPoint.x() == self.endPoint.x() or self.startPoint.y(
        ) == self.endPoint.y():
            return None
        return QgsRectangle(self.startPoint, self.endPoint)

    def deactivate(self):
        super(RectangleMapTool, self).deactivate()
        self.emit(QtCore.SIGNAL("deactivated()"))
Example #54
0
class DistanceMapTool(QgsMapTool):
    def __init__(self, iface):
        self.iface = iface
        self.line_layer = None
        self.settings = MySettings()
        QgsMapTool.__init__(self, iface.mapCanvas())

    def activate(self):
        QgsMapTool.activate(self)
        self.line_layer = MemoryLayers(self.iface).line_layer
        self.rubber = QgsRubberBand(self.canvas(), QGis.Point)
        self.rubber.setColor(self.settings.value("rubberColor"))
        self.rubber.setIcon(self.settings.value("rubberIcon"))
        self.rubber.setIconSize(self.settings.value("rubberSize"))
        self.messageWidget = self.iface.messageBar().createMessage("Intersect It", "Not snapped.")
        self.messageWidgetExist = True
        self.messageWidget.destroyed.connect(self.messageWidgetRemoved)

    def deactivate(self):
        self.iface.messageBar().popWidget(self.messageWidget)
        self.rubber.reset()
        QgsMapTool.deactivate(self)

    def messageWidgetRemoved(self):
        self.messageWidgetExist = False

    def displaySnapInfo(self, match=None):
        if not self.messageWidgetExist:
            return
        if match is None:
            message = "No snap"
        else:
            message = 'Snapped to: <b>{}</b>'.format(match.layer())
        self.messageWidget.setText(message)

    def canvasMoveEvent(self, mouseEvent):
        match = self.snap_to_vertex(mouseEvent.pos())
        self.rubber.reset(QGis.Point)
        if match.type() == QgsPointLocator.Vertex and match.layer() != self.line_layer:
            self.rubber.addPoint(match.point())
        self.displaySnapInfo(match)

    def canvasPressEvent(self, mouseEvent):
        if mouseEvent.button() != Qt.LeftButton:
            return
        match = self.snap_to_vertex(mouseEvent.pos())
        if match.type() != QgsPointLocator.Vertex and match.layer() != self.line_layer:
            point = self.toMapCoordinates(mouseEvent.pos())
        else:
            point = match.point()
        self.rubber.addPoint(point)
        distance = Distance(self.iface, point, 1)
        dlg = DistanceDialog(distance, self.canvas())
        if dlg.exec_():
            distance.save()
        self.rubber.reset()

    def snap_to_vertex(self, pos):
        """ Temporarily override snapping config and snap to vertices and edges
         of any editable vector layer, to allow selection of node for editing
         (if snapped to edge, it would offer creation of a new vertex there).
        """
        map_point = self.toMapCoordinates(pos)
        tol = QgsTolerance.vertexSearchRadius(self.canvas().mapSettings())
        snap_type = QgsPointLocator.Type(QgsPointLocator.Vertex)

        snap_layers = []
        for layer in self.canvas().layers():
            if not isinstance(layer, QgsVectorLayer):
                continue
            snap_layers.append(QgsSnappingUtils.LayerConfig(
                layer, snap_type, tol, QgsTolerance.ProjectUnits))

        snap_util = self.canvas().snappingUtils()
        old_layers = snap_util.layers()
        old_mode = snap_util.snapToMapMode()
        old_inter = snap_util.snapOnIntersections()
        snap_util.setLayers(snap_layers)
        snap_util.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced)
        snap_util.setSnapOnIntersections(True)
        m = snap_util.snapToMap(map_point)
        snap_util.setLayers(old_layers)
        snap_util.setSnapToMapMode(old_mode)
        snap_util.setSnapOnIntersections(old_inter)
        return m
Example #55
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 #56
0
class SelectMapTool(QgsMapToolEmitPoint):
    features_selected_signal = pyqtSignal()
    selected_feature_ids = list()

    def __init__(self, canvas, layer, multi=True):
        self.canvas = canvas
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self._multi = multi
        self._layer = layer

        # Cursor
        cursor = QCursor()
        cursor.setShape(Qt.CrossCursor)
        self.setCursor(cursor)

        # RubberBand Style
        self.rubberBand = QgsRubberBand(self.canvas, True)
        self.rubberBand.setBrushStyle(Qt.Dense4Pattern)
        self.rubberBand.setColor(QColor(255, 181, 92))
        self.rubberBand.setStrokeColor(QColor(232, 137, 72))
        self.rubberBand.setWidth(0.2)
        self.reset()

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBand.reset(True)

    def canvasPressEvent(self, e):
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True

    def canvasReleaseEvent(self, e):
        if e.button() & Qt.LeftButton:
            self.isEmittingPoint = False
            self.show_rubber_band()

            if self._multi and (e.modifiers() & Qt.ControlModifier
                                or e.modifiers() & Qt.ShiftModifier):
                if self.rubberBand.asGeometry().type(
                ) == QgsWkbTypes.PolygonGeometry:
                    self.reset()
                    return
                else:
                    id_features_intersect = self.ids_features_intersect()

                # if Control or Shift are selected, keeps the previous selection
                for id_feature_intersect in id_features_intersect:
                    # toggle selected feature
                    if id_feature_intersect not in self.selected_feature_ids:
                        self.selected_feature_ids.append(id_feature_intersect)
                    else:
                        self.selected_feature_ids.remove(id_feature_intersect)
            else:
                id_features_intersect = self.ids_features_intersect()
                # Clear selected features if Control or Shift are not selected
                self.selected_feature_ids = id_features_intersect

            self.select_features()
        elif e.button() & Qt.RightButton:
            # emit the signal when at least one element has been selected
            if len(self._layer.selectedFeatures()):
                self.features_selected_signal.emit()
                self.reset()

    def canvasDoubleClickEvent(self, e):
        self.canvasPressEvent(e)

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return
        self.endPoint = self.toMapCoordinates(e.pos())
        self.show_rubber_band()

    def show_rubber_band(self):
        self.create_rubber_band()
        if self.rubberBand:
            self.rubberBand.show()

    def create_rubber_band(self):
        self.rubberBand.reset(True)

        if self.startPoint is None and self.endPoint is None:
            return None
        elif self.startPoint.x() == self.endPoint.x() or self.startPoint.y(
        ) == self.endPoint.y():
            self.rubberBand.reset(QgsWkbTypes.PointGeometry)
            self.rubberBand.addPoint(self.startPoint,
                                     True)  # true to update canvas
        else:
            self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)

            point1 = QgsPointXY(self.startPoint.x(), self.startPoint.y())
            point2 = QgsPointXY(self.startPoint.x(), self.endPoint.y())
            point3 = QgsPointXY(self.endPoint.x(), self.endPoint.y())
            point4 = QgsPointXY(self.endPoint.x(), self.startPoint.y())

            self.rubberBand.addPoint(point1, False)
            self.rubberBand.addPoint(point2, False)
            self.rubberBand.addPoint(point3, False)
            self.rubberBand.addPoint(point4, True)  # true to update canvas

            # Approximate polygon to point when it's too small related to the scale
            if (self.rubberBand.asGeometry().area() /
                    self.canvas.extent().area()) * 1000000 < 50:
                self.rubberBand.reset(QgsWkbTypes.PointGeometry)
                self.rubberBand.addPoint(self.startPoint,
                                         True)  # true to update canvas

    def ids_features_intersect(self):
        index = QgsSpatialIndex(self._layer)
        bbox = self.rubberBand.asGeometry().boundingBox()

        candidate_features = self._layer.getFeatures(index.intersects(bbox))
        geom = self.rubberBand.asGeometry()
        centroid = geom

        if not self._multi and geom.type() == QgsWkbTypes.PolygonGeometry:
            centroid = geom.centroid()

        features_selected = []
        distances_features_selected = dict()
        for candidate_feature in candidate_features:
            if candidate_feature.geometry().intersects(geom):
                features_selected.append(candidate_feature.id())
                # Calculate the distance to the centroid
                distances_features_selected[candidate_feature.id(
                )] = candidate_feature.geometry().distance(centroid)

        if not self._multi and geom.type() == QgsWkbTypes.PolygonGeometry:
            if features_selected:
                # Get the key corresponding to the minimum value within a dictionary
                features_selected = [
                    min(distances_features_selected,
                        key=distances_features_selected.get)
                ]

        return features_selected

    def select_features(self):
        # show features selected
        self._layer.selectByIds(self.selected_feature_ids)
        self.reset()

    def deactivate(self):
        QgsMapTool.deactivate(self)
        self.deactivated.emit()
class RectangleMapTool(QgsMapToolEmitPoint):
    """
    Map tool that lets the user define the analysis extents.
    """
    rectangle_created = pyqtSignal()
    deactivated = pyqtSignal()

    def __init__(self, canvas):
        """Constructor for the map tool.

        :param canvas: Canvas that tool will interact with.
        :type canvas: QgsMapCanvas
        """
        self.canvas = canvas
        self.start_point = None
        self.end_point = None
        self.is_emitting_point = False

        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rubber_band = QgsRubberBand(self.canvas, geometryType=QGis.Line)
        self.rubber_band.setColor(QColor(0, 0, 240, 100))
        # Needs QGIS 2.6
        # self.rubber_band.setFillColor(QColor(0, 0, 240, 0))
        self.rubber_band.setWidth(1)

        self.reset()

    def reset(self):
        """
        Clear the rubber band for the analysis extents.
        """
        self.start_point = self.end_point = None
        self.is_emitting_point = False
        self.rubber_band.reset(QGis.Polygon)

    def canvasPressEvent(self, e):
        """
        Handle canvas press events so we know when user is capturing the rect.

        :param e: A Qt event object.
        :type: QEvent
        """
        self.start_point = self.toMapCoordinates(e.pos())
        self.end_point = self.start_point
        self.is_emitting_point = True

        self.show_rectangle(self.start_point, self.end_point)

    def canvasReleaseEvent(self, e):
        """
        Handle canvas release events  has finished capturing e

        :param e: A Qt event object.
        :type: QEvent
        """
        _ = e
        self.is_emitting_point = False
        self.rectangle_created.emit()

    def canvasMoveEvent(self, e):
        """

        :param e:
        :return:
        """
        if not self.is_emitting_point:
            return

        self.end_point = self.toMapCoordinates(e.pos())
        self.show_rectangle(self.start_point, self.end_point)

    def show_rectangle(self, start_point, end_point):
        """
        Show the rectangle on the canvas.

        :param start_point: QGIS Point object representing the origin (
            top left).
        :type start_point: QgsPoint

        :param end_point: QGIS Point object representing the contra-origin (
            bottom right).
        :type end_point: QgsPoint

        :return:
        """
        self.rubber_band.reset(QGis.Polygon)
        if (start_point.x() == end_point.x() or
                start_point.y() == end_point.y()):
            return

        point1 = start_point
        point2 = QgsPoint(end_point.x(), start_point.y())
        point3 = end_point
        point4 = QgsPoint(start_point.x(), end_point.y())

        update_canvas = False
        self.rubber_band.addPoint(point1, update_canvas)
        self.rubber_band.addPoint(point2, update_canvas)
        self.rubber_band.addPoint(point3, update_canvas)
        self.rubber_band.addPoint(point4, update_canvas)
        # noinspection PyArgumentEqualDefault
        # no False so canvas will update
        # close the polygon otherwise it shows as a filled rect
        self.rubber_band.addPoint(point1)
        self.rubber_band.show()

    def rectangle(self):
        """
        Accessor for the rectangle.

        :return: A rectangle showing the designed extent.
        :rtype: QgsRectangle
        """
        if self.start_point is None or self.end_point is None:
            return None
        elif self.start_point.x() == self.end_point.x() or \
                self.start_point.y() == self.end_point.y():
            return None

        return QgsRectangle(self.start_point, self.end_point)

    def set_rectangle(self, rectangle):
        """
        Set the rectangle for the selection.
        :param rectangle:
        :return:
        """
        if rectangle == self.rectangle():
            return False

        if rectangle is None:
            self.reset()
        else:
            self.start_point = QgsPoint(
                rectangle.xMinimum(), rectangle.yMinimum())
            self.end_point = QgsPoint(
                rectangle.xMaximum(), rectangle.yMaximum())
            self.show_rectangle(self.start_point, self.end_point)
        return True

    def deactivate(self):
        """
        Disable the tool.
        """
        QgsMapTool.deactivate(self)
        self.deactivated.emit()
Example #58
0
class RectangleMapTool(QgsMapToolEmitPoint):

    rectangleCreated = pyqtSignal()
    deactivated = pyqtSignal()

    def __init__(self, canvas):
        self.canvas = canvas
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rubberBand = QgsRubberBand(self.canvas,
                                        QgsWkbTypes.PolygonGeometry)
        self.rubberBand.setColor(QColor(255, 0, 0, 100))
        self.rubberBand.setWidth(2)

        self.reset()

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)

    def canvasPressEvent(self, e):
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True

        self.showRect(self.startPoint, self.endPoint)

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False
        if self.rectangle() is not None:
            self.rectangleCreated.emit()

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return

        self.endPoint = self.toMapCoordinates(e.pos())
        self.showRect(self.startPoint, self.endPoint)

    def showRect(self, startPoint, endPoint):
        self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
        if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
            return

        point1 = QgsPointXY(startPoint.x(), startPoint.y())
        point2 = QgsPointXY(startPoint.x(), endPoint.y())
        point3 = QgsPointXY(endPoint.x(), endPoint.y())
        point4 = QgsPointXY(endPoint.x(), startPoint.y())

        self.rubberBand.addPoint(point1, False)
        self.rubberBand.addPoint(point2, False)
        self.rubberBand.addPoint(point3, False)
        # True to update canvas
        self.rubberBand.addPoint(point4, True)
        self.rubberBand.show()

    def rectangle(self):
        if self.startPoint is None or self.endPoint is None:
            return None
        elif self.startPoint.x() == self.endPoint.x() or \
                self.startPoint.y() == self.endPoint.y():
            return None

        return QgsRectangle(self.startPoint, self.endPoint)

    def setRectangle(self, rect):
        if rect == self.rectangle():
            return False

        if rect is None:
            self.reset()
        else:
            self.startPoint = QgsPointXY(rect.xMaximum(), rect.yMaximum())
            self.endPoint = QgsPointXY(rect.xMinimum(), rect.yMinimum())
            self.showRect(self.startPoint, self.endPoint)
        return True

    def deactivate(self):
        QgsMapTool.deactivate(self)
        self.deactivated.emit()
class RectangleMapTool(QgsMapToolEmitPoint):

    rectangleCreated = pyqtSignal()
    deactivated = pyqtSignal()

    def __init__(self, canvas):
        self.canvas = canvas
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)
        self.rubberBand.setColor(QColor(255, 0, 0, 100))
        self.rubberBand.setWidth(2)

        self.reset()

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)

    def canvasPressEvent(self, e):
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True

        self.showRect(self.startPoint, self.endPoint)

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False
        if self.rectangle() is not None:
            self.rectangleCreated.emit()

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return

        self.endPoint = self.toMapCoordinates(e.pos())
        self.showRect(self.startPoint, self.endPoint)

    def showRect(self, startPoint, endPoint):
        self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)
        if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
            return

        point1 = QgsPointXY(startPoint.x(), startPoint.y())
        point2 = QgsPointXY(startPoint.x(), endPoint.y())
        point3 = QgsPointXY(endPoint.x(), endPoint.y())
        point4 = QgsPointXY(endPoint.x(), startPoint.y())

        self.rubberBand.addPoint(point1, False)
        self.rubberBand.addPoint(point2, False)
        self.rubberBand.addPoint(point3, False)
        # True to update canvas
        self.rubberBand.addPoint(point4, True)
        self.rubberBand.show()

    def rectangle(self):
        if self.startPoint is None or self.endPoint is None:
            return None
        elif self.startPoint.x() == self.endPoint.x() or \
                self.startPoint.y() == self.endPoint.y():
            return None

        return QgsRectangle(self.startPoint, self.endPoint)

    def setRectangle(self, rect):
        if rect == self.rectangle():
            return False

        if rect is None:
            self.reset()
        else:
            self.startPoint = QgsPointXY(rect.xMaximum(), rect.yMaximum())
            self.endPoint = QgsPointXY(rect.xMinimum(), rect.yMinimum())
            self.showRect(self.startPoint, self.endPoint)
        return True

    def deactivate(self):
        QgsMapTool.deactivate(self)
        self.deactivated.emit()
Example #60
0
class SelectDownloadExtentMapTool(QgsMapTool):
    def __init__(self, canvas, dialog):
        self.canvas = canvas
        self.dialog = dialog
        QgsMapTool.__init__(self, self.canvas)
        self.setCursor(Qt.CrossCursor)
        self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon)
        self.rubberBand.setColor(Qt.red)
        self.rubberBand.setWidth(1)
        self.reset()

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBand.reset(QGis.Polygon)

    def canvasPressEvent(self, e):
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True
        self.showRect(self.startPoint, self.endPoint)

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False
        self.dialog.setExtent(self.rectangle())
        self.dialog.showNormal()
        self.dialog.raise_()
        self.dialog.activateWindow()
        self.reset()

    def canvasMoveEvent(self, e):
        if not self.isEmittingPoint:
            return

        self.endPoint = self.toMapCoordinates(e.pos())
        self.showRect(self.startPoint, self.endPoint)

    def showRect(self, startPoint, endPoint):
        self.rubberBand.reset(QGis.Polygon)
        if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
            return

        point1 = QgsPoint(startPoint.x(), startPoint.y())
        point2 = QgsPoint(startPoint.x(), endPoint.y())
        point3 = QgsPoint(endPoint.x(), endPoint.y())
        point4 = QgsPoint(endPoint.x(), startPoint.y())

        self.rubberBand.addPoint(point1, False)
        self.rubberBand.addPoint(point2, False)
        self.rubberBand.addPoint(point3, False)
        self.rubberBand.addPoint(point4, True)  # true to update canvas
        self.rubberBand.show()

    def rectangle(self):
        if self.startPoint is None or self.endPoint is None:
            return None
        elif self.startPoint.x() == self.endPoint.x() or self.startPoint.y(
        ) == self.endPoint.y():
            return None

        return QgsRectangle(self.startPoint, self.endPoint)