class LineDrawer(QgsMapToolEmitPoint):

    def __init__(self, canvas):
        # call the parent constructor
        QgsMapToolEmitPoint.__init__(self, canvas)
        # store the passed canvas
        self.canvas = canvas

        # flag to know whether the tool is performing a drawing operation 
        self.isDrawing = False

        # create and setup the rubber band to display the line
        self.rubberBand = QgsRubberBand( self.canvas, False )    # False = not a polygon = a line
        self.rubberBand.setColor( Qt.red )
        self.rubberBand.setWidth( 1 )


    def clear(self):
        self.rubberBand.reset( False )    # False = not a polygon = a line

    def delete(self):
        self.canvas.scene().removeItem( self.rubberBand )

    def canvasPressEvent(self, e):
        # which the mouse button?
        if e.button() == Qt.LeftButton:
            # left click

            # if it's the first left click, clear the rubberband 
            if not self.isDrawing:
                self.clear()

            # we are drawing now
            self.isDrawing = True

            # convert the clicked position to map coordinates
            point = self.toMapCoordinates( e.pos() )
            # add a new point to the rubber band
            self.rubberBand.addPoint( point, True )    # True = display updates on the canvas
            # and finally show the rubber band
            self.rubberBand.show()

        elif e.button() == Qt.RightButton:
            # right click, stop drawing
            self.isDrawing = False
            # emit a signal
            self.emit( SIGNAL("editingFinished()") )

    def canvasMoveEvent(self, e):
        # check if it's already drawing
        if not self.isDrawing:
            return

        # convert the mouse position to map coordinates
        point = self.toMapCoordinates( e.pos() )
        # move the last point to the new coordinates
        self.rubberBand.movePoint( point )

    def geometry(self):
        return self.rubberBand.asGeometry()
Example #2
0
    def _draw_rubberband(self, geometry, colour, width):
        """Draw a rubber band on the canvas.

        .. versionadded: 2.2.0

        :param geometry: Extent that the rubber band should be drawn for.
        :type geometry: QgsGeometry

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

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

        :returns: Rubber band that should be set to the extent.
        :rtype: QgsRubberBand
        """
        # noinspection PyArgumentList
        rubber_band = QgsRubberBand(
            self._map_canvas, geometryType=QGis.Polygon)
        rubber_band.setBrushStyle(Qt.NoBrush)
        rubber_band.setColor(colour)
        rubber_band.setWidth(width)
        rubber_band.setToGeometry(geometry, None)
        return rubber_band
Example #3
0
    def highlight():
      rb = QgsRubberBand( self.canvas, QGis.Polygon)
      rb.setBorderColor( QColor( 255,  0, 0 ) )
      rb.setWidth( 2 )
      rb.setToGeometry( geomRB, None )

      return rb
Example #4
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
	def loadLines(self, lines, points, markers, suffix):
		no = self.project.readEntry("TUVIEW", "lines{0}no".format(suffix))[0]
		if no:
			no = int(no)
			for i in range(no):
				a = self.project.readEntry("TUVIEW", 'lines{0}x{1}'.format(suffix, i))[0]
				a = a.split('~~')
				b = self.project.readEntry("TUVIEW", 'lines{0}y{1}'.format(suffix, i))[0]
				b = b.split('~~')
				points.clear()
				for j in range(len(a)):
					x = float(a[j])
					y = float(b[j])
					point = QgsPoint(x, y)
					points.append(point)
					if i + 1 == no:
						marker = QgsVertexMarker(self.tuView.canvas)
						if suffix == 'cs':
							marker.setColor(Qt.red)
							marker.setIconSize(10)
							marker.setIconType(QgsVertexMarker.ICON_BOX)
						else:  # 'q'
							marker.setColor(Qt.blue)
							marker.setIconSize(12)
							marker.setIconType(QgsVertexMarker.ICON_DOUBLE_TRIANGLE)
						marker.setCenter(QgsPointXY(point))
						markers.append(marker)
				line = QgsRubberBand(self.tuView.canvas, False)
				line.setWidth(2)
				if suffix == 'cs':
					line.setColor(QColor(Qt.red))
				else:  # 'q'
					line.setColor(QColor(Qt.blue))
				line.setToGeometry(QgsGeometry.fromPolyline(points), None)
				lines.append(line)
Example #6
0
class QgepMapTool( QgsMapTool ):
    '''
    Base class for all the map tools
    '''
    
    highLightedPoints = []
    logger = logging.getLogger( __name__ )
    
    def __init__( self, iface, button ):
        QgsMapTool.__init__( self, iface.mapCanvas() )
        self.canvas = iface.mapCanvas()
        self.cursor = QCursor( Qt.CrossCursor )
        self.button = button
        self.msgBar = iface.messageBar()

        settings = QSettings()
        currentProfileColor = settings.value( "/QGEP/CurrentProfileColor", u'#FF9500' )
        
        self.rubberBand = QgsRubberBand( self.canvas )
        self.rubberBand.setColor( QColor( currentProfileColor ) )
        self.rubberBand.setWidth( 3 )

    # Gets called when the tool is activated
    def activate( self ):
        QgsMapTool.activate( self )
        self.canvas.setCursor( self.cursor )
        self.button.setChecked( True )

    # Gets called whenever the tool is deactivated directly or indirectly
    def deactivate( self ):
        QgsMapTool.deactivate( self )
        self.button.setChecked( False )

    def isZoomTool( self ):
        return False

    def setCursor( self, cursor ):
        self.cursor = QCursor( cursor )

    #===========================================================================
    # Events
    #===========================================================================
    
    def canvasMoveEvent( self, event ):
        try:
            self.mouseMoved( event )
        except AttributeError:
            pass

    def canvasReleaseEvent( self, event ):
        if event.button() == Qt.RightButton:
            self.rightClicked ( event )
        else:
            self.leftClicked( event )

    def canvasDoubleClickEvent( self, event ):
        try:
            self.doubleClicked( event )
        except AttributeError:
            pass
 def getSnapRubberBand(self):
     rubberBand = QgsRubberBand(self.canvas, geometryType = QGis.Point)
     rubberBand.setFillColor(QColor(255, 0, 0, 40))
     rubberBand.setBorderColor(QColor(255, 0, 0, 200))
     rubberBand.setWidth(2)
     rubberBand.setIcon(QgsRubberBand.ICON_X)
     return rubberBand        
    def zoomAndShowWKT(self, wtk):
        geom = QgsGeometry.fromWkt(wtk)
        canvas = self.iface.mapCanvas() 
        self.clear()

        r = QgsRubberBand(canvas, geom.type() == 3 )
        r.setToGeometry(geom, None)
        r.setColor(QColor(0, 0, 255))
        r.setFillColor(QColor(0, 0, 255, 50))
        r.setWidth(3)

        pt = geom.pointOnSurface().asPoint()
        m = QgsVertexMarker(canvas)
        m.setCenter( pt )
        m.setColor(QColor(0, 0, 255))
        m.setIconSize(5)
        m.setIconType(QgsVertexMarker.ICON_BOX)  
        m.setPenWidth(3)

        if geom.type() == 3 or geom.type() == 2:
           rec = geom.boundingBox()
           canvas.setExtent(rec)
        else:
           self.moveMapTo( pt[0], pt[1], 0)

        self.graphics.append(r) 
        self.graphics.append(m) 
        self._refresh_layers()
class PlaceMarkerMapTool(QgsMapToolEmitPoint):
    '''
    classdocs
    '''

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

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

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

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

    def deactivate(self):
        self.reset()
        super(PlaceMarkerMapTool, self).deactivate()
class GetPointMapTool(QgsMapToolEmitPoint):

    coordCaptured = ""

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

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

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

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


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

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

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

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


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


        self.rubberBand.addPoint(point1, False)

        self.rubberBand.show()

    def pointdef(self):

        return QgsPoint(self.point)
 def addGraphic(self, geom ):
     canvas = self.iface.mapCanvas()      
     rBand = QgsRubberBand(canvas, True) 
     self.graphics.append( rBand )
     rBand.setToGeometry( geom, None )
     rBand.setColor(QtGui.QColor(0,0,255, 70))
     if QGis.QGIS_VERSION_INT >= 20600:
         rBand.setBorderColor( QtGui.QColor(0,0,250, 220) )
     rBand.setWidth(3)
Example #12
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 )
 def onClickedHighlight(self):
   def removeRB():
     rb.reset( True )
     self.qgisCanvas.scene().removeItem( rb )
   
   rb = QgsRubberBand( self.qgisCanvas, QGis.Polygon)
   rb.setBorderColor( QColor( 255,  0, 0 ) )
   rb.setWidth( 2 )
   rb.setToGeometry( QgsGeometry.fromRect( self.canvas.extent() ), None )
   QTimer.singleShot( 2000, removeRB )
Example #14
0
 def _setRubberBandMarker(self, geom):
     m = QgsRubberBand(self.qgisIface.mapCanvas(), False)  # not polygon
     if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry:
         linegeom = geom
     elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PolygonGeometry:
         linegeom = QgsGeometry.fromPolylineXY(geom.asPolygon()[0])
     m.setToGeometry(linegeom, None)
     m.setColor(QColor(self.config['rubber_color']))
     m.setWidth(self.config['rubber_width'])
     return m
 def initRubberLayer(self):
     if self.rubberLayer:
         rb = self.rubberLayer
         rb.reset(True)
     else:
         rb = QgsRubberBand(self.iface.mapCanvas(), True)
     rb.setColor(QColor(255, 0, 255, 255))
     rb.setWidth(3)
     rb.setFillColor(QColor(255, 0, 255, 50))
     self.rubberLayer = rb
 def getRubberBand(self):
     geomType = self.iface.activeLayer().geometryType()
     if geomType == QGis.Polygon:
         rubberBand = QgsRubberBand(self.canvas, True)
         rubberBand.setFillColor(QColor(255, 0, 0, 40))
     elif geomType == QGis.Line:
         rubberBand = QgsRubberBand(self.canvas, False)
     rubberBand.setBorderColor(QColor(255, 0, 0, 200))
     rubberBand.setWidth(2)
     return rubberBand
Example #17
0
class CurrentSelection(QgsRubberBand):
    """
    Position marker for the current location in the viewer.
    """

    class AniObject(QObject):
        def __init__(self, band):
            super(CurrentSelection.AniObject, self).__init__()
            self.color = QColor()

        @pyqtProperty(int)
        def alpha(self):
            return self.color.alpha()

        @alpha.setter
        def alpha(self, value):
            self.color.setAlpha(value)

    def __init__(self, canvas):
        super(CurrentSelection, self).__init__(canvas)
        self.outline = QgsRubberBand(canvas)
        self.outline.setBrushStyle(Qt.NoBrush)
        self.outline.setWidth(5)
        self.outline.setIconSize(30)
        self.aniobject = CurrentSelection.AniObject(self)
        self.anim = QPropertyAnimation(self.aniobject, "alpha")
        self.anim.setDuration(500)
        self.anim.setStartValue(50)
        self.anim.setEndValue(100)
        self.anim.valueChanged.connect(self.value_changed)

    def setOutlineColour(self, color):
        self.outline.setColor(color)

    def setToGeometry(self, geom, layer):
        super(CurrentSelection, self).setToGeometry(geom, layer)
        self.outline.setToGeometry(geom, layer)
        self.anim.stop()
        self.anim.start()

    def reset(self, geomtype=QGis.Line):
        super(CurrentSelection, self).reset(geomtype)
        self.outline.reset(geomtype)
        self.anim.stop()

    def value_changed(self, value):
        self.setColor(self.aniobject.color)
        self.update()

    def setColor(self, color):
        self.aniobject.color = color
        super(CurrentSelection, self).setColor(color)
Example #18
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 #19
0
 def _createRubberBand(self, geometryType, moveBand=False):
     settings = QSettings()
     rb = QgsRubberBand(self.canvas(), geometryType)
     rb.setWidth(int(settings.value('/qgis/digitizing/line_width', 1)))
     color = QColor(int(settings.value('/qgis/digitizing/line_color_red', 255)),
                    int(settings.value('/qgis/digitizing/line_color_green', 0)),
                    int(settings.value('/qgis/digitizing/line_color_blue', 0)))
     myAlpha = int(settings.value('/qgis/digitizing/line_color_alpha', 200)) / 255.0
     if (moveBand):
         myAlpha = myAlpha * float(settings.value('/qgis/digitizing/line_color_alpha_scale', 0.75))
         rb.setLineStyle(Qt.DotLine)
     if (geometryType == QGis.Polygon):
         color.setAlphaF(myAlpha)
     color.setAlphaF(myAlpha)
     rb.setColor(color)
     rb.show()
     return rb
Example #20
0
class lineTool(QgsMapTool):
    def __init__(self, iface, callback):
        QgsMapTool.__init__(self,iface.mapCanvas())
        self.iface  = iface
        self.canvas = iface.mapCanvas()
        self.cursor = QCursor(Qt.CrossCursor)
        self.callback   = callback
        
        self.rubberBand = QgsRubberBand(self.canvas, False)
        self.points  = []
        self.rubberBand.setColor(Qt.red)
        self.rubberBand.setWidth(1.6)

    def canvasReleaseEvent(self,event):
        if event.button() == Qt.RightButton:
          self.points.append(QgsPoint( self.toMapCoordinates( event.pos()) ) )
          if len(self.points) <= 1 :return
        
          self.rubberBand.setToGeometry( QgsGeometry.fromPolyline(self.points), None )
          self.callback( self.rubberBand )
          QgsMapTool.deactivate(self)
        else:
          self.points.append(QgsPoint( self.toMapCoordinates(event.pos()) ) )
          if len(self.points) <= 1 : return
          self.rubberBand.setToGeometry( QgsGeometry.fromPolyline(self.points), None )

    def canvasDoubleClickEvent(self,event):
        self.points.append(QgsPoint( self.toMapCoordinates( event.pos()) ))
        if len(self.points) <= 1 : return
      
        self.rubberBand.setToGeometry( QgsGeometry.fromPolyline(self.points), None )
        self.callback( self.rubberBand )
        QgsMapTool.deactivate(self)
    
    def activate(self):
      QgsMapTool.activate(self)
      self.canvas.setCursor(self.cursor)

    def isZoomTool(self):
        return False

    def setCursor(self,cursor):
        self.cursor = QCursor(cursor)
Example #21
0
 def createMoveTrack(self, line=False, color=QColor(255, 71, 25, 170), width=0.2):
     '''Create move track.
     
         :param line: Flag indicating if geometry to draw is a line (True)
             or a polygon(False).
         :type line: bool
     
         :param color: Color of line.
         :type color: QColor
         
         :param width: Width of line.
         :type width: int
         
         :return: Created rubber band. 
         :rtype: QgsRubberBand
     '''
     
     moveTrack = QgsRubberBand(self.canvas, line)
     moveTrack.setColor(color)
     moveTrack.setWidth(width)
     return moveTrack
 def highlight(self,geometry):
     def processEvents():
         try:
             qApp.processEvents()
         except:
             QApplication.processEvents()
             
     highlight = QgsRubberBand(self.canvas, geometry.type())
     highlight.setColor(QColor("#36AF6C"))
     highlight.setFillColor(QColor("#36AF6C"))
     highlight.setWidth(2)
     highlight.setToGeometry(geometry,self.canvas.currentLayer())
     processEvents()
     sleep(.1)
     highlight.hide()
     processEvents()
     sleep(.1)
     highlight.show()
     processEvents()
     sleep(.1)
     highlight.reset()
     processEvents()
Example #23
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 #24
0
class RotateRasterMapTool(QgsMapToolEmitPoint):
    def __init__(self, iface):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rasterShadow = RasterShadowMapCanvasItem(self.canvas)

        self.rubberBandExtent = QgsRubberBand(self.canvas,
                                              QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.setColor(Qt.red)
        self.rubberBandExtent.setWidth(1)

        # In case of rotation around pressed point (ctrl)
        # Use rubberBand for displaying an horizontal line.
        self.rubberBandDisplacement = QgsRubberBand(self.canvas,
                                                    QgsWkbTypes.LineGeometry)
        self.rubberBandDisplacement.setColor(Qt.red)
        self.rubberBandDisplacement.setWidth(1)

        self.reset()

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

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()
        self.layer = None

    def canvasPressEvent(self, e):
        self.startY = e.pos().y()
        self.endY = self.startY
        self.isEmittingPoint = True
        self.height = self.canvas.height()

        modifiers = QApplication.keyboardModifiers()
        self.isRotationAroundPoint = bool(modifiers & Qt.ControlModifier)
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint

        self.isLayerVisible = isLayerVisible(self.iface, self.layer)
        setLayerVisible(self.iface, self.layer, False)

        rotation = self.computeRotation()
        self.showRotation(rotation)

        self.layer.history.append({
            "action": "rotation",
            "rotation": self.layer.rotation,
            "center": self.layer.center
        })  # rotation set

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()

        rotation = self.computeRotation()
        if self.isRotationAroundPoint:
            self.layer.moveCenterFromPointRotate(self.startPoint, rotation, 1,
                                                 1)
        val = self.layer.rotation + rotation

        self.layer.setRotation(val)

        setLayerVisible(self.iface, self.layer, self.isLayerVisible)
        self.layer.repaint()

        self.layer.commitTransformParameters()

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

        self.endY = e.pos().y()
        rotation = self.computeRotation()
        self.showRotation(rotation)

        self.endPoint = self.toMapCoordinates(e.pos())

    def computeRotation(self):
        if self.isRotationAroundPoint:
            dX = self.endPoint.x() - self.startPoint.x()
            dY = self.endPoint.y() - self.startPoint.y()
            return math.degrees(math.atan2(-dY, dX))
        else:
            dY = self.endY - self.startY
            return 90.0 * dY / self.height

    def showRotation(self, rotation):
        if self.isRotationAroundPoint:
            cornerPoints = self.layer.transformedCornerCoordinatesFromPoint(
                self.startPoint, rotation, 1, 1)

            self.rasterShadow.reset(self.layer)
            self.rasterShadow.setDeltaRotationFromPoint(
                rotation, self.startPoint, True)
            self.rasterShadow.show()

            self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
            point0 = QgsPointXY(self.startPoint.x() + 10, self.startPoint.y())
            point1 = QgsPointXY(self.startPoint.x(), self.startPoint.y())
            point2 = QgsPointXY(self.endPoint.x(), self.endPoint.y())
            self.rubberBandDisplacement.addPoint(point0, False)
            self.rubberBandDisplacement.addPoint(point1, False)
            self.rubberBandDisplacement.addPoint(point2,
                                                 True)  # true to update canvas
            self.rubberBandDisplacement.show()
        else:
            center, originalRotation, xScale, yScale = \
                self.layer.transformParameters()
            newRotation = rotation + originalRotation
            cornerPoints = self.layer.transformedCornerCoordinates(
                center, newRotation, xScale, yScale)

            self.rasterShadow.reset(self.layer)
            self.rasterShadow.setDeltaRotation(rotation, True)
            self.rasterShadow.show()

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        for point in cornerPoints:
            self.rubberBandExtent.addPoint(point, False)
        # for closing
        self.rubberBandExtent.addPoint(cornerPoints[0], True)
        self.rubberBandExtent.show()
Example #25
0
class ProfileTool(QgsMapTool):
    """ Narzędzie do tworzenia krzywej """

    def __init__(self, parent):
        canvas = iface.mapCanvas()
        super(ProfileTool, self).__init__(canvas)
        
        set_cursor(self)
        self.editing = False
        self.parent = parent
        self.task = None

        self.tempGeom = QgsRubberBand(canvas, QgsWkbTypes.LineGeometry)
        self.tempGeom.setColor(QColor('red'))
        self.tempGeom.setWidth(2)

        self.tempLine = QgsRubberBand(canvas, QgsWkbTypes.LineGeometry)
        self.tempLine.setColor(QColor('red'))
        self.tempLine.setWidth(2)
        self.tempLine.setLineStyle(Qt.DotLine)

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Delete:
            pointsCount = self.tempLine.numberOfVertices() 
            if pointsCount > 2 and self.editing:
                self.tempGeom.removePoint(pointsCount-2)
                self.tempLine.removePoint(pointsCount-2)
                len_m = self.calculateDistance(self.tempGeom.asGeometry())
                self.parent.dsbLineLength.setValue(len_m)
                if self.tempGeom.numberOfVertices() == 1:
                    self.tempGeom.reset(QgsWkbTypes.LineGeometry)
                    self.tempLine.reset(QgsWkbTypes.LineGeometry)
                    self.parent.dsbLineLength.setValue(0)           
            else:
                self.reset()
        elif e.key() == Qt.Key_Escape:
            self.reset()

    def canvasMoveEvent(self, e):
        #Poruszanie" wierzchołkiem linii tymczasowej zgodnie z ruchem myszki
        if self.tempGeom.numberOfVertices()>1:
            point = e.snapPoint()
            self.tempLine.movePoint(point)

    def canvasReleaseEvent(self, e):
        point = e.snapPoint()
        if self.task:
            self.parent.on_message.emit('Trwa genrowanie profilu. Aby wygenerować następny poczekaj na pobranie danych', Qgis.Warning, 4)
            return
        if e.button() == int(Qt.LeftButton):
            #Dodawanie kolejnych wierzchołków
            if not self.editing:
                #Nowy obiekt, pierwszy wierzchołek
                self.tempLine.reset(QgsWkbTypes.LineGeometry)
                self.tempGeom.reset(QgsWkbTypes.LineGeometry)
                self.editing = True
            self.tempGeom.addPoint(point)
            self.tempLine.addPoint(point)
            len_m = self.calculateDistance(self.tempGeom.asGeometry())
            self.parent.dsbLineLength.setValue(len_m)
        elif e.button() == int(Qt.RightButton):
            if self.tempGeom.numberOfVertices() < 2:
                return
            #Zakończenie rysowania obiektu
            self.tempLine.reset()
            self.editing = False
            geometry = self.tempGeom.asGeometry()
            errors = geometry.validateGeometry()
            if errors:
            #Niepoprawna geometria                    
                for error in errors:
                    if self.tempGeom.numberOfVertices() > 2:
                        self.parent.on_message.emit('Niepoprawna geometria', Qgis.Critical, 4)
                    self.tempGeom.reset()
                return
            self.get_interval()

    def get_interval(self):
        interval, ok = QInputDialog.getDouble(self.parent, 'Podaj interwał', 'Interwał [m]:')
        if not ok:
            self.reset()
            return
        geom = self.tempGeom.asGeometry()
        
        activeCrs = QgsProject.instance().crs().authid()
        fromCrs = QgsCoordinateReferenceSystem(activeCrs)
        toCrs = QgsCoordinateReferenceSystem(2180)
        transformation = QgsCoordinateTransform(fromCrs, toCrs, QgsProject.instance())
        geom.transform(transformation)
        
        meters_len = geom.length()
        if meters_len <= interval:
            self.parent.on_message.emit('Długość linii krótsza lub równa podanemu interwałowi', Qgis.Critical, 5)
            self.reset()
            return
        try:
            num_points = meters_len/interval
        except ZeroDivisionError:
            self.parent.on_message.emit('Interwał musi być większy od 0', Qgis.Critical, 4)
            self.reset()
            return
        points_on_line = []
        max_interval = 0
        intervals = []
        for i in range(int(num_points)+1):
            pt = geom.interpolate(float(max_interval))
            points_on_line.append(pt)
            intervals.append(max_interval)
            max_interval += interval
        data = {'points':points_on_line, 'intervals':intervals}
        self.task = QgsTask.fromFunction('Pobieranie wysokości dla przekroju...', self.generateProfileFromPoints, data=data)
        QgsApplication.taskManager().addTask(self.task)

    def generateProfileFromPoints(self, task: QgsTask, data):
        points_on_line = data.get('points')
        intervals = data.get('intervals')
        heights = []
        total = 100/len(points_on_line)
        for idx, pt in enumerate(points_on_line):
            height = self.parent.getHeight(pt, special=True)
            heights.append(height)
        try:
            self.task.setProgress( idx*total )
        except AttributeError as e:
            pass
        if heights and intervals:   
            self.fillTable(heights, intervals)
        self.parent.on_message.emit('Pomyślnie wygenerowano profil', Qgis.Success, 4)
        self.task = None

    def fillTable(self, heights, intervals):
        for idx, interval in enumerate(intervals):
            self.parent.twData.setRowCount(idx+1)
            self.parent.twData.setItem(idx, 0, QTableWidgetItem(f'{interval}'))
            self.parent.twData.setItem(idx, 1, QTableWidgetItem(heights[idx]))

    def calculateDistance(self, geometry):
        distanceArea = QgsDistanceArea()
        distanceArea.setEllipsoid('GRS80')
        distanceArea.setSourceCrs(QgsProject.instance().crs(), QgsCoordinateTransformContext())
        length = distanceArea.measureLength(geometry)
        result = distanceArea.convertLengthMeasurement(length, QgsUnitTypes.DistanceMeters)
        return result
        
    def reset(self):
        self.tempLine.reset(QgsWkbTypes.LineGeometry)
        self.tempGeom.reset(QgsWkbTypes.LineGeometry)
        self.parent.dsbLineLength.setValue(0)
        self.parent.twData.setRowCount(0)

    def deactivate(self):
        self.reset()
        self.parent.dsbLineLength.setEnabled(False) 
        self.button().setChecked(False)
Example #26
0
class QGISRedMoveVertexsTool(QgsMapTool):
    ownMainLayers = ["Pipes", "Valves", "Pumps"]

    def __init__(self, button, iface, projectDirectory, netwName):
        QgsMapTool.__init__(self, iface.mapCanvas())
        self.iface = iface
        self.ProjectDirectory = projectDirectory
        self.NetworkName = netwName
        self.toolbarButton = button

        self.snapper = None
        self.vertexMarker = QgsVertexMarker(self.iface.mapCanvas())
        self.vertexMarker.setColor(QColor(255, 87, 51))
        self.vertexMarker.setIconSize(15)
        self.vertexMarker.setIconType(QgsVertexMarker.ICON_BOX)  # or ICON_CROSS, ICON_X
        self.vertexMarker.setPenWidth(3)
        self.vertexMarker.hide()

        self.mouseClicked = False
        self.clickedPoint = None
        self.objectSnapped = None
        self.selectedFeature = None
        self.selectedLayer = None
        self.newPositionVector = QgsVector(0, 0)
        self.rubberBand = None
        self.newVertexMarker = QgsVertexMarker(self.iface.mapCanvas())
        self.newVertexMarker.setColor(QColor(55, 198, 5))
        self.newVertexMarker.setIconSize(15)
        self.newVertexMarker.setIconType(QgsVertexMarker.ICON_BOX)  # or ICON_CROSS, ICON_X
        self.newVertexMarker.setPenWidth(3)
        self.newVertexMarker.hide()

    def activate(self):
        cursor = QCursor()
        cursor.setShape(Qt.ArrowCursor)
        self.iface.mapCanvas().setCursor(cursor)

        myLayers = []
        # Editing
        layers = self.getLayers()
        for layer in layers:
            openedLayerPath = self.getLayerPath(layer)
            for name in self.ownMainLayers:
                layerPath = self.generatePath(self.ProjectDirectory, self.NetworkName + "_" + name + ".shp")
                if openedLayerPath == layerPath:
                    myLayers.append(layer)
                    if not layer.isEditable():
                        layer.startEditing()
        # Snapping
        self.snapper = QgsMapCanvasSnappingUtils(self.iface.mapCanvas())
        self.snapper.setMapSettings(self.iface.mapCanvas().mapSettings())
        config = QgsSnappingConfig(QgsProject.instance())
        config.setType(2)  # Vertex
        config.setMode(2)  # All layers
        config.setTolerance(1)
        config.setUnits(2)  # Pixels
        config.setEnabled(True)
        self.snapper.setConfig(config)

    def deactivate(self):
        self.toolbarButton.setChecked(False)
        # End Editing
        layers = self.getLayers()
        for layer in layers:
            openedLayerPath = self.getLayerPath(layer)
            for name in self.ownMainLayers:
                layerPath = self.generatePath(self.ProjectDirectory, self.NetworkName + "_" + name + ".shp")
                if openedLayerPath == layerPath:
                    if layer.isModified():
                        layer.commitChanges()
                    else:
                        layer.rollBack()

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    """Methods"""
    def getUniformedPath(self, path):
        return QGISRedUtils().getUniformedPath(path)

    def getLayerPath(self, layer):
        return QGISRedUtils().getLayerPath(layer)

    def generatePath(self, folder, fileName):
        return QGISRedUtils().generatePath(folder, fileName)

    def getLayers(self):
        return QGISRedUtils().getLayers()

    def areOverlapedPoints(self, point1, point2):
        tolerance = 0.1
        if point1.distance(point2) < tolerance:
            return True
        else:
            return False

    def isInPath(self, point1, point2, myPoint):
        width = point2.x() - point1.x()
        height = point2.y() - point1.y()
        widthM = myPoint.x() - point1.x()
        heightM = myPoint.y() - point1.y()
        if abs(width) >= abs(height):
            yEst = widthM * height / width + point1.y()
            if abs(yEst - myPoint.y()) < 1E-9:
                return True
        else:
            xEst = heightM * width / height + point1.x()
            if abs(xEst - myPoint.x()) < 1E-9:
                return True
        return False

    def createRubberBand(self, points):
        myPoints = points
        if isinstance(points[0], QgsPointXY):
            myPoints = []
            for p in points:
                myPoints.append(QgsPoint(p.x(), p.y()))
        self.rubberBand = QgsRubberBand(self.iface.mapCanvas(), False)
        self.rubberBand.setToGeometry(QgsGeometry.fromPolyline(myPoints), None)
        self.rubberBand.setColor(QColor(55, 198, 5))
        self.rubberBand.setWidth(1)
        self.rubberBand.setLineStyle(Qt.DashLine)
        self.newVertexMarker.setCenter(
            QgsPointXY(points[0].x(), points[0].y()))
        self.newVertexMarker.show()

    def updateRubberBand(self):
        newX = self.clickedPoint.x() + self.newPositionVector.x()
        newY = self.clickedPoint.y() + self.newPositionVector.y()
        self.rubberBand.movePoint(1, QgsPointXY(newX, newY))
        self.newVertexMarker.setCenter(QgsPointXY(newX, newY))

    def moveVertexLink(self, layer, feature, newPosition, vertexIndex):
        if layer.isEditable():
            layer.beginEditCommand("Update link geometry")
            try:
                edit_utils = QgsVectorLayerEditUtils(layer)
                edit_utils.moveVertex(newPosition.x(), newPosition.y(), feature.id(), vertexIndex)
            except Exception as e:
                layer.destroyEditCommand()
                raise e
            layer.endEditCommand()

    def deleteVertexLink(self, layer, feature, vertexIndex):
        if layer.isEditable():
            layer.beginEditCommand("Update link geometry")
            try:
                edit_utils = QgsVectorLayerEditUtils(layer)
                edit_utils.deleteVertex(feature.id(), vertexIndex)
            except Exception as e:
                layer.destroyEditCommand()
                raise e
            layer.endEditCommand()

    def insertVertexLink(self, layer, feature, newPoint):
        if layer.isEditable():
            layer.beginEditCommand("Update link geometry")
            vertex = -1
            if layer.geometryType() == 1:  # Line
                featureGeometry = self.selectedFeature.geometry()
                if featureGeometry.isMultipart():
                    parts = featureGeometry.get()
                    for part in parts:  # only one part
                        for i in range(len(part)-1):
                            if self.isInPath(QgsPointXY(part[i].x(), part[i].y()),
                                             QgsPointXY(part[i+1].x(), part[i+1].y()), newPoint):
                                vertex = i+1
            try:
                edit_utils = QgsVectorLayerEditUtils(layer)
                edit_utils.insertVertex(
                    newPoint.x(), newPoint.y(), feature.id(), vertex)
            except Exception as e:
                layer.destroyEditCommand()
                raise e
            layer.endEditCommand()

    """Events"""
    def canvasPressEvent(self, event):
        if self.objectSnapped is None:
            self.clickedPoint = None
            return

        if event.button() == Qt.RightButton:
            self.mouseClicked = False
            self.clickedPoint = None

        if event.button() == Qt.LeftButton:
            self.clickedPoint = self.objectSnapped.point()
            if self.vertexIndex == -1:
                return
            self.mouseClicked = True
            self.createRubberBand(
                [self.objectSnapped.point(), self.objectSnapped.point()])

    def canvasMoveEvent(self, event):
        mousePoint = self.toMapCoordinates(event.pos())
        # Mouse not clicked
        if not self.mouseClicked:
            matchSnapper = self.snapper.snapToMap(mousePoint)
            if matchSnapper.isValid():
                valid = False
                layer = matchSnapper.layer()
                snapLayerPath = self.getLayerPath(layer)
                for name in self.ownMainLayers:
                    layerPath = self.generatePath(self.ProjectDirectory, self.NetworkName + "_" + name + ".shp")
                    if snapLayerPath == layerPath:
                        valid = True
                if valid:
                    self.objectSnapped = matchSnapper
                    self.selectedLayer = layer

                    vertex = matchSnapper.point()
                    featureId = matchSnapper.featureId()
                    request = QgsFeatureRequest().setFilterFid(featureId)
                    nodes = list(layer.getFeatures(request))
                    self.selectedFeature = QgsFeature(nodes[0])
                    # #Ver aquí si es el nudo inicial y final
                    middleNode = False
                    self.vertexIndex = -1
                    if layer.geometryType() == 1:  # Line
                        featureGeometry = self.selectedFeature.geometry()
                        if featureGeometry.isMultipart():
                            parts = featureGeometry.get()
                            for part in parts:  # only one part
                                if middleNode:
                                    break
                                i = -1
                                for v in part:
                                    i = i+1
                                    if i == 0 or i == len(part)-1:
                                        continue
                                    matchedPoint = QgsPointXY(vertex.x(), vertex.y())
                                    if self.areOverlapedPoints(QgsGeometry.fromPointXY(matchedPoint),
                                                               QgsGeometry.fromPointXY(QgsPointXY(v.x(), v.y()))):
                                        middleNode = True
                                        self.vertexIndex = i
                                        break
                    if middleNode:
                        self.vertexMarker.setCenter(
                            QgsPointXY(vertex.x(), vertex.y()))
                        self.vertexMarker.show()
                    else:
                        self.vertexMarker.hide()
                else:
                    self.objectSnapped = None
                    self.selectedFeature = None
                    self.selectedLayer = None
                    self.vertexMarker.hide()
            else:
                self.objectSnapped = None
                self.selectedFeature = None
                self.selectedLayer = None
                self.vertexMarker.hide()
        # Mouse clicked
        else:
            # # Update rubber band
            if self.objectSnapped is not None and self.rubberBand is not None:
                snappedPoint = self.objectSnapped.point()
                self.newPositionVector = QgsVector(mousePoint.x() - snappedPoint.x(), mousePoint.y() - snappedPoint.y())
                self.updateRubberBand()

    def canvasReleaseEvent(self, event):
        mousePoint = self.toMapCoordinates(event.pos())
        if self.mouseClicked:
            if event.button() == 1:
                self.mouseClicked = False
                if self.objectSnapped is not None:
                    self.moveVertexLink(self.selectedLayer, self.selectedFeature, mousePoint, self.vertexIndex)
        elif event.button() == 2:
            if self.objectSnapped is not None:
                self.deleteVertexLink(self.selectedLayer, self.selectedFeature, self.vertexIndex)
        elif event.button() == 1:
            if self.objectSnapped is not None:
                self.insertVertexLink(self.selectedLayer, self.selectedFeature, self.objectSnapped.point())
        self.objectSnapped = None
        self.selectedFeature = None
        self.selectedLayer = None
        self.vertexIndex = -1
        self.iface.mapCanvas().refresh()
        # Remove vertex marker and rubber band
        self.vertexMarker.hide()
        self.iface.mapCanvas().scene().removeItem(self.rubberBand)
        self.newVertexMarker.hide()
Example #27
0
class InfoTool(QgsMapTool):
    def __init__(self, canvas, snapradius=2):
        super(InfoTool, self).__init__(canvas)
        self.canvas = canvas
        self.radius = snapradius

        self.selectband = QgsRubberBand(self.canvas,
                                        QgsWkbTypes.PolygonGeometry)
        self.selectrect = QRect()
        self.dragging = False
        self.selectionlayers = {}

    def getFeatures(self, rect):
        # The MS SQL driver seems to crash with a empty rectangle.
        # Need to check QGIS to patch issue
        if rect.isEmpty():
            return

        for layer in self.selectionlayers.values():
            if (not layer.type() == QgsMapLayer.VectorLayer
                    or layer.geometryType() == QgsWkbTypes.NoGeometry):
                continue

            layerrect = self.toLayerCoordinates(layer, rect)
            rq = QgsFeatureRequest().setFilterRect(layerrect)\
                .setFlags(QgsFeatureRequest.ExactIntersect)
            features = []
            for feature in layer.getFeatures(rq):
                if feature.isValid():
                    features.append(feature)

            yield layer, features

    def toSearchRect(self, point):
        size = 20
        rect = QRectF()
        rect.setLeft(point.x() - size)
        rect.setRight(point.x() + size)
        rect.setTop(point.y() - size)
        rect.setBottom(point.y() + size)

        transform = self.canvas.getCoordinateTransform()
        ll = transform.toMapCoordinates(rect.left(), rect.bottom())
        ur = transform.toMapCoordinates(rect.right(), rect.top())

        rect = QgsRectangle(ur, ll)
        return rect

    def canvasPressEvent(self, event):
        self.dragging = False
        self.selectrect.setRect(0, 0, 0, 0)

        self.selectband = QgsRubberBand(self.canvas,
                                        QgsWkbTypes.PolygonGeometry)
        self.selectband.setColor(QColor.fromRgb(0, 0, 255, 65))
        self.selectband.setWidth(5)

    def canvasMoveEvent(self, event):
        if not event.buttons() == Qt.LeftButton:
            return

        if not self.dragging:
            self.selectrect.setTopLeft(event.pos())
            self.dragging = True
        self.selectrect.setBottomRight(event.pos())

        maptoolutils.setRubberBand(self.canvas, self.selectrect,
                                   self.selectband)

    def canvasReleaseEvent(self, event):
        if self.dragging:
            geometry = self.selectband.asGeometry()
            if not geometry:
                return

            rect = geometry.boundingBox()
        else:
            rect = self.toSearchRect(event.pos())

        self.dragging = False
        self.selectband.reset()

        results = OrderedDict((l, f) for l, f in self.getFeatures(rect))

        RoamEvents.selectioncleared.emit()
        RoamEvents.selectionchanged.emit(results)
class SelectFeaturesTool(QgsMapTool):
    selection_clicked = pyqtSignal(list)

    def __init__(self, mission_track, canvas):
        QgsMapTool.__init__(self, canvas)
        self.setCursor(Qt.ArrowCursor)
        self.mission_track = mission_track
        self.layer = self.mission_track.get_mission_layer()
        self.rubber_band = None
        self.rubber_band_points = None
        self.selection_polygon = []
        self.indexes_within_list = []
        self.band_finished = True
        self.mCtrl = False
        self.p0, self.p1, self.p2, self.p3 = None, None, None, None
        self.mission_track.mission_changed.connect(self.update_rubber_band)
        self.mission_track.step_removed.connect(self.remove_rubber_band)
        self.wp = self.mission_track.find_waypoints_in_mission()
        self.layer.startEditing()
        self.rubber_band_vs_track_indexes = {}
        self.rubber_band_points = QgsRubberBand(self.canvas(),
                                                QgsWkbTypes.PointGeometry)
        self.rubber_band_points.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.rubber_band_points.setIconSize(10)
        self.rubber_band_points.setColor(QColor("green"))
        self.rubber_band_vertex_counter = 0

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Control:
            self.mCtrl = True

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Control:
            self.mCtrl = False
        if event.key() == Qt.Key_Escape:
            self.p0, self.p1, self.p2, self.p3 = None, None, None, None
            if self.rubber_band:
                self.rubber_band.reset(True)
            self.close_polygon_band()
            self.band_finished = True
            self.canvas().refresh()
            return

    def canvasPressEvent(self, event):
        if event.button() == Qt.LeftButton:
            point = self.toMapCoordinates(event.pos())
            # check if we have clicked on a vertex
            tolerance = self.calc_tolerance()
            vertex = self.find_vertex_at(event.pos(), tolerance)
            if self.mCtrl and vertex is not None:
                # if we have clicked on a vertex, identify which one
                # check if was already in the selection list
                if vertex not in self.indexes_within_list:
                    # add it
                    self.indexes_within_list.append(vertex)
                    self.update_rubber_band()
                else:
                    # remove it
                    self.indexes_within_list.remove(vertex)
                    self.update_rubber_band()

                self.band_finished = True
            elif vertex is None:
                # if we have not clicked on a vertex and there's no polygon band, start it
                if not len(self.selection_polygon
                           ) and self.band_finished and not self.mCtrl:
                    self.selection_clicked.emit(list())
                    self.band_finished = False
                    self.rubber_band = QgsRubberBand(
                        self.canvas(), QgsWkbTypes.PolygonGeometry)
                    self.rubber_band.setWidth(2)
                    select_green = QColor("green")
                    select_green.setAlpha(128)
                    self.rubber_band.setColor(select_green)

                    if event.button() == Qt.LeftButton:
                        # Left click -> add vertex
                        self.p0 = QgsPointXY(point.x(), point.y())
                        self.selection_polygon.append(self.p0)
                elif len(self.selection_polygon) == 1 and not self.mCtrl:
                    if event.button() == Qt.LeftButton:
                        # Left click -> add vertex
                        self.p2 = QgsPointXY(point.x(), point.y())
                        self.p1 = QgsPointXY(self.p2.x(), self.p0.y())
                        self.p3 = QgsPointXY(self.p0.x(), self.p2.y())
                        self.selection_polygon.append(self.p1)
                        self.selection_polygon.append(self.p2)
                        self.selection_polygon.append(self.p3)
                        self.band_finished = True
                        self.set_selection()
                        self.close_polygon_band()

            self.selection_clicked.emit(self.indexes_within_list)

    def find_vertex_at(self, pos, tolerance):
        """
        get the vertex that is closer to the clicked point


        :param pos: The point that we've clicked
        :param tolerance: The tolerance of pos
        :return: vertex or None
        """
        if len(self.wp) > 0:
            dist_to_vertex = []
            for v in range(0, len(self.wp)):
                a1 = self.toCanvasCoordinates(QgsPointXY(self.wp[v]))
                dist_to_vertex.append(
                    math.sqrt((pos.x() - a1.x())**2 + (pos.y() - a1.y())**2))

            vertex = dist_to_vertex.index(min(dist_to_vertex))
            if min(dist_to_vertex) > tolerance:
                return None
            else:
                return vertex
        else:
            return None

    def calc_tolerance(self):
        """
        Compute the tolerance on canvas

        :return: tolerance
        """
        # 2% of tolerance
        width_tolerance = 0.02 * self.canvas().width()
        height_tolerance = 0.02 * self.canvas().height()
        if width_tolerance < height_tolerance:
            tolerance = width_tolerance
        else:
            tolerance = height_tolerance
        return tolerance

    def canvasMoveEvent(self, event):

        if not self.band_finished and not self.mCtrl:
            self.p2 = self.toMapCoordinates(event.pos())
            self.p1 = QgsPointXY(self.p2.x(), self.p0.y())
            self.p3 = QgsPointXY(self.p0.x(), self.p2.y())

            self.selection_polygon.append(self.p1)
            self.selection_polygon.append(self.p2)
            self.selection_polygon.append(self.p3)
            self.rubber_band.setToGeometry(
                QgsGeometry.fromPolygonXY([self.selection_polygon]), None)
            self.selection_polygon.pop()
            self.selection_polygon.pop()
            self.selection_polygon.pop()

    def set_selection(self):
        """
        Set vertices highlight according to polygon
        """
        # Check which features are within the polygon
        mission_track = self.layer.getFeatures()  # get mission track feature

        for f in mission_track:  # loop although mission layer only has one feature
            vertices_it = f.geometry().vertices()
        polygon_geom = QgsGeometry.fromPolygonXY([self.selection_polygon])
        vertices_within_list = []
        # self.indexes_within_list = []
        vertex_index = 0

        # Highlight them using a point rubber band
        self.rubber_band_vertex_counter = 0
        for v in vertices_it:
            point_geom = QgsGeometry.fromPointXY(QgsPointXY(v.x(), v.y()))
            if point_geom.within(polygon_geom):
                vertices_within_list.append(v)
                if not (vertex_index in self.indexes_within_list
                        ):  # only add if not already present
                    self.indexes_within_list.append(vertex_index)
                    self.rubber_band_points.addPoint(QgsPointXY(v.x(), v.y()))
                    self.rubber_band_vertex_counter = self.rubber_band_vertex_counter + 1
                    self.rubber_band_vs_track_indexes[
                        vertex_index] = self.rubber_band_vertex_counter - 1
            vertex_index = vertex_index + 1

    def update_rubber_band(self):
        if self.rubber_band_points:
            self.rubber_band_points.reset(QgsWkbTypes.PointGeometry)
            self.rubber_band_vs_track_indexes = {}
            self.rubber_band_vertex_counter = 0
        self.wp = self.mission_track.find_waypoints_in_mission()
        if len(self.indexes_within_list) > 0:

            selected_vertices = self.mission_track.find_waypoints_in_mission(
                self.indexes_within_list)
            for v in selected_vertices:
                vertex_index = 0
                for point in self.wp:
                    if v == point:
                        pc = self.toLayerCoordinates(self.layer, QgsPointXY(v))
                        self.rubber_band_points.addPoint(pc)
                        self.rubber_band_vertex_counter = self.rubber_band_vertex_counter + 1
                        self.rubber_band_vs_track_indexes[
                            vertex_index] = self.rubber_band_vertex_counter - 1
                    vertex_index = vertex_index + 1

        self.set_geometry()

    def remove_rubber_band(self, wp):
        # if self.rubber_band_points:
        #    self.rubber_band_points.reset(QgsWkbTypes.PointGeometry)
        self.indexes_within_list.remove(wp)
        self.update_rubber_band()

    def set_geometry(self):
        """
        Save rubber band to geometry of the layer
        """
        if self.layer.featureCount() == 0:
            # no feature yet created
            f = QgsFeature()
            if len(self.wp) == 1:
                f.setGeometry(
                    QgsGeometry.fromPointXY(
                        QgsPointXY(self.wp[0].x(), self.wp[0].y())))
            else:
                f.setGeometry(QgsGeometry.fromPolyline(self.wp))
            # self.layer.dataProvider().addFeatures([f])
            self.layer.addFeatures([f])
        else:
            # mission feature present, edit geometry
            feats = self.layer.getFeatures()
            for f in feats:
                if len(self.wp) == 1:
                    self.layer.changeGeometry(
                        f.id(),
                        QgsGeometry.fromPointXY(
                            QgsPointXY(self.wp[0].x(), self.wp[0].y())))
                else:
                    self.layer.changeGeometry(
                        f.id(), QgsGeometry.fromPolyline(self.wp))
        self.layer.commitChanges()
        self.layer.startEditing()

    def close_polygon_band(self):
        self.selection_polygon = []
        if self.rubber_band is not None:
            self.rubber_band.reset()
            self.canvas().scene().removeItem(self.rubber_band)
        self.rubber_band = None

    def close_highlight_band(self):
        self.rubber_band_points.reset()
        self.canvas().scene().removeItem(self.rubber_band_points)
        self.rubber_band_points = None

    def deactivate(self):
        if self.rubber_band:
            self.close_polygon_band()
        if self.rubber_band_points:
            self.close_highlight_band()

        try:
            self.mission_track.mission_changed.disconnect(
                self.update_rubber_band)
            self.mission_track.step_removed.disconnect(self.remove_rubber_band)
        except:
            logger.info("no connected to signal")
        self.layer.commitChanges()
Example #29
0
class AdvancedIntersectionMapTool(QgsMapTool):
    def __init__(self, iface):
        self.iface = iface
        self.mapCanvas = iface.mapCanvas()
        QgsMapTool.__init__(self, self.mapCanvas)
        self.settings = MySettings()
        self.rubber = QgsRubberBand(self.mapCanvas)

        self.tolerance = self.settings.value("selectTolerance")
        units = self.settings.value("selectUnits")
        if units == "pixels":
            self.tolerance *= self.mapCanvas.mapUnitsPerPixel()

    def activate(self):
        QgsMapTool.activate(self)
        self.rubber.setWidth(self.settings.value("rubberWidth"))
        self.rubber.setColor(self.settings.value("rubberColor"))
        line_layer = MemoryLayers(self.iface).line_layer()
        # unset this tool if the layer is removed
        line_layer.layerDeleted.connect(self.unsetMapTool)
        self.layerId = line_layer.id()
        # create snapper for this layer
        self.snapLayer = QgsSnapper.SnapLayer()
        self.snapLayer.mLayer = line_layer
        self.snapLayer.mSnapTo = QgsSnapper.SnapToVertexAndSegment
        self.snapLayer.mTolerance = self.settings.value("selectTolerance")
        if self.settings.value("selectUnits") == "map":
            self.snapLayer.mUnitType = QgsTolerance.MapUnits
        else:
            self.snapLayer.mUnitType = QgsTolerance.Pixels

    def unsetMapTool(self):
        self.mapCanvas.unsetMapTool(self)

    def deactivate(self):
        self.rubber.reset()
        line_layer = QgsMapLayerRegistry.instance().mapLayer(self.layerId)
        if line_layer is not None:
            line_layer.layerDeleted.disconnect(self.unsetMapTool)
        QgsMapTool.deactivate(self)

    def canvasMoveEvent(self, mouseEvent):
        # put the observations within tolerance in the rubber band
        self.rubber.reset()
        for f in self.getFeatures(mouseEvent.pos()):
            self.rubber.addGeometry(f.geometry(), None)

    def canvasPressEvent(self, mouseEvent):
        pos = mouseEvent.pos()
        observations = self.getFeatures(pos)
        point = self.toMapCoordinates(pos)
        self.doIntersection(point, observations)

    def getFeatures(self, pixPoint):
        snapper = QgsSnapper(self.mapCanvas.mapRenderer())
        snapper.setSnapLayers([self.snapLayer])
        snapper.setSnapMode(QgsSnapper.SnapWithResultsWithinTolerances)
        ok, snappingResults = snapper.snapPoint(pixPoint, [])
        # output snapped features
        features = []
        alreadyGot = []
        for result in snappingResults:
            featureId = result.snappedAtGeometry
            f = QgsFeature()
            if featureId not in alreadyGot:
                if result.layer.getFeatures(QgsFeatureRequest().setFilterFid(
                        featureId)).nextFeature(f) is not False:
                    features.append(QgsFeature(f))
                    alreadyGot.append(featureId)
        return features

    def doIntersection(self, initPoint, observations):
        nObs = len(observations)
        if nObs < 2:
            return
        self.rubber.reset()
        self.dlg = IntersectionDialog(self.iface, observations, initPoint)
        if not self.dlg.exec_() or self.dlg.solution is None:
            return
        intersectedPoint = self.dlg.solution
        self.saveIntersectionResult(self.dlg.report, intersectedPoint)
        self.saveDimension(intersectedPoint, self.dlg.observations)

    def saveIntersectionResult(self, report, intersectedPoint):
        # save the intersection result (point) and its report
        # check first
        while True:
            if not self.settings.value("advancedIntersectionWritePoint"):
                break  # if we do not place any point, skip
            layerid = self.settings.value("advancedIntersectionLayer")
            message = QCoreApplication.translate(
                "IntersectIt", "To place the intersection solution,"
                " you must select a layer in the settings.")
            status, intLayer = self.checkLayerExists(layerid, message)
            if status == 2:
                continue
            if status == 3:
                return
            if self.settings.value("advancedIntersectionWriteReport"):
                reportField = self.settings.value("reportField")
                message = QCoreApplication.translate(
                    "IntersectIt",
                    "To save the intersection report, please select a field for it."
                )
                status = self.checkFieldExists(intLayer, reportField, message)
                if status == 2:
                    continue
                if status == 3:
                    return
            break
        # save the intersection results
        if self.settings.value("advancedIntersectionWritePoint"):
            f = QgsFeature()
            f.setGeometry(QgsGeometry().fromPoint(intersectedPoint))
            if self.settings.value("advancedIntersectionWriteReport"):
                irep = intLayer.dataProvider().fieldNameIndex(reportField)
                f.addAttribute(irep, report)
            intLayer.dataProvider().addFeatures([f])
            intLayer.updateExtents()
            self.mapCanvas.refresh()

    def saveDimension(self, intersectedPoint, observations):
        # check that dimension layer and fields have been set correctly
        if not self.settings.value(
                "dimensionDistanceWrite") and not self.settings.value(
                    "dimensionOrientationWrite"):
            return  # if we do not place any dimension, skip
        obsTypes = ("Distance", "Orientation")
        recheck = True
        while recheck:
            # settings might change during checking,
            # so recheck both observation types whenever the settings dialog is shown
            recheck = False
            for obsType in obsTypes:
                while True:
                    if not self.settings.value("dimension" + obsType +
                                               "Write"):
                        break
                    # check layer
                    layerId = self.settings.value("dimension" + obsType +
                                                  "Layer")
                    message = QCoreApplication.translate(
                        "IntersectIt", "To place dimensions, "
                        "you must define a layer in the settings.")
                    status, dimLayer = self.checkLayerExists(layerId, message)
                    if status == 2:
                        recheck = True
                        continue
                    if status == 3:
                        return
                    # check fields
                    if self.settings.value("dimension" + obsType +
                                           "ObservationWrite"):
                        obsField = self.settings.value("dimension" + obsType +
                                                       "ObservationField")
                        message = QCoreApplication.translate(
                            "IntersectIt",
                            "To save the observation in the layer,"
                            " please select a field for it.")
                        status = self.checkFieldExists(dimLayer, obsField,
                                                       message)
                        if status == 2:
                            recheck = True
                            continue
                        if status == 3:
                            return
                    if self.settings.value("dimension" + obsType +
                                           "PrecisionWrite"):
                        precisionField = self.settings.value("dimension" +
                                                             obsType +
                                                             "PrecisionField")
                        message = QCoreApplication.translate(
                            "IntersectIt",
                            "To save the precision of observation,"
                            " please select a field for it.")
                        status = self.checkFieldExists(dimLayer,
                                                       precisionField, message)
                        if status == 2:
                            recheck = True
                            continue
                        if status == 3:
                            return
                    break
        # save the intersection results
        for obsType in obsTypes:
            if self.settings.value("dimension" + obsType + "Write"):
                layerid = self.settings.value("dimension" + obsType + "Layer")
                layer = QgsMapLayerRegistry.instance().mapLayer(layerid)
                if layer is None:
                    continue
                initFields = layer.dataProvider().fields()
                features = []
                for obs in observations:
                    if obs["type"] != obsType.lower():
                        continue
                    f = QgsFeature()
                    f.setFields(initFields)
                    f.initAttributes(initFields.size())
                    if self.settings.value("dimension" + obsType +
                                           "ObservationWrite"):
                        f[self.settings.value(
                            "dimension" + obsType +
                            "ObservationField")] = obs["observation"]
                    if self.settings.value("dimension" + obsType +
                                           "PrecisionWrite"):
                        f[self.settings.value(
                            "dimension" + obsType +
                            "PrecisionField")] = obs["precision"]
                    p0 = QgsPoint(obs["x"], obs["y"])
                    p1 = intersectedPoint
                    if obs["type"] == "distance":
                        geom = Arc(p0, p1).geometry()
                    elif obs["type"] == "orientation":
                        geom = QgsGeometry().fromPolyline([p0, p1])
                    else:
                        raise NameError("Invalid observation %s" % obs["type"])
                    f.setGeometry(geom)
                    features.append(QgsFeature(f))
                if not layer.dataProvider().addFeatures(features):
                    self.iface.messageBar().pushMessage(
                        "Could not commit %s observations" % obsType,
                        QgsMessageBar.CRITICAL)
                layer.updateExtents()
        self.mapCanvas.refresh()

    def checkLayerExists(self, layerid, message):
        # returns:
        # 1: layer exists
        # 2: does not exist, settings has been open, so loop once more (i.e. continue)
        # 3: does not exist, settings not edited, so cancel
        layer = QgsMapLayerRegistry.instance().mapLayer(layerid)
        if layer is not None:
            return 1, layer

        reply = QMessageBox.question(
            self.iface.mainWindow(), "Intersect It",
            message + " Would you like to open settings?", QMessageBox.Yes,
            QMessageBox.No)
        if reply == QMessageBox.Yes:
            if MySettingsDialog().exec_():
                return 2
        return 3

    def checkFieldExists(self, layer, field, message):
        # returns:
        # 1: field exists
        # 2: does not exist, settings has been open, so loop once more (i.e. continue)
        # 3: does not exist, settings not edited, so cancel
        if layer.dataProvider().fieldNameIndex(field) != -1:
            return 1

        reply = QMessageBox.question(
            self.iface.mainWindow(), "Intersect It",
            message + " Would you like to open settings?", QMessageBox.Yes,
            QMessageBox.No)
        if reply == QMessageBox.Yes:
            if MySettingsDialog().exec_():
                return 2
        return 3
Example #30
0
class DailyImagesSearchResultsWidget(RESULTS_BASE, RESULTS_WIDGET):

    setAOIRequested = pyqtSignal(dict)
    checkedCountChanged = pyqtSignal(int)
    searchSaved = pyqtSignal(dict)

    def __init__(self):
        super().__init__()

        self.setupUi(self)

        self._p_client = PlanetClient.getInstance()

        self._has_more = True

        self._metadata_to_show = [
            PlanetNodeMetadata.CLOUD_PERCENTAGE,
            PlanetNodeMetadata.GROUND_SAMPLE_DISTANCE
        ]

        self._image_count = 0
        self._total_count = 0

        self._request = None
        self._local_filters = None
        self._response_iterator = None

        self.btnSaveSearch.setIcon(SAVE_ICON)
        self.btnSort.setIcon(SORT_ICON)
        self.btnAddPreview.setIcon(ADD_PREVIEW_ICON)
        self.btnAddPreview.setEnabled(False)

        self.btnSaveSearch.clicked.connect(self._save_search)
        self.btnAddPreview.clicked.connect(self._add_preview_clicked)
        self.btnSort.clicked.connect(self._sort_order_changed)
        self.btnSettings.clicked.connect(self._open_settings)
        self.lblImageCount.setOpenExternalLinks(False)
        self.lblImageCount.linkActivated.connect(self.load_more_link_clicked)

        self._aoi_box = None
        self._setup_request_aoi_box()

        self._set_widgets_visibility(False)

    def _set_widgets_visibility(self, search_ok):
        self.tree.setVisible(search_ok)
        self.widgetActions.setVisible(search_ok)
        self.widgetNoResults.setVisible(not search_ok)

    def search_has_been_performed(self):
        return self._request is not None

    def _open_settings(self):
        dlg = ResultsConfigurationDialog(self._metadata_to_show)
        if dlg.exec_():
            self._metadata_to_show = dlg.selection
            self.update_image_items()

    def _add_preview_clicked(self):
        self.add_preview()

    @waitcursor
    def add_preview(self):
        imgs = self.selected_images()
        if is_segments_write_key_valid():
            item_ids = [
                f"{img['properties'][ITEM_TYPE]}:{img[ID]}" for img in imgs
            ]
            analytics.track(PlanetClient.getInstance().user()["email"],
                            "Scene preview added to map", {"images": item_ids})
        create_preview_group("Selected images", imgs)

    def update_image_items(self):
        it = QTreeWidgetItemIterator(self.tree)
        while it.value():
            item = it.value()
            if isinstance(item, SceneItem):
                w = self.tree.itemWidget(item, 0)
                w.set_metadata_to_show(self._metadata_to_show)
            it += 1

    def _save_search(self):
        dlg = SaveSearchDialog(self._request)
        if dlg.exec_():
            self._p_client.create_search(dlg.request_to_save)
            self.searchSaved.emit(dlg.request_to_save)

    def sort_order(self):
        order = ["acquired"]
        if self.btnSort.isChecked():
            order.append("asc")
        else:
            order.append("desc")
        return order

    def _sort_order_changed(self):
        self.update_request(self._request, {})

    def load_more_link_clicked(self):
        self.load_more()

    @waitcursor
    def update_request(self, request, local_filters):
        self._image_count = 0
        self._request = request
        self._local_filters = local_filters
        self.tree.clear()
        stats_request = {"interval": "year"}
        stats_request.update(self._request)
        resp = self._p_client.stats(stats_request).get()
        self._total_count = sum([b["count"] for b in resp["buckets"]])
        if self._total_count:
            response = self._p_client.quick_search(self._request,
                                                   page_size=TOP_ITEMS_BATCH,
                                                   sort=' '.join(
                                                       self.sort_order()))
            self._response_iterator = response.iter()
            self.load_more()
            self._set_widgets_visibility(True)
        else:
            self._set_widgets_visibility(False)

    @waitcursor
    def load_more(self):
        page = next(self._response_iterator, None)
        if page is not None:
            for i in range(self.tree.topLevelItemCount()):
                date_item = self.tree.topLevelItem(i)
                date_widget = self.tree.itemWidget(date_item, 0)
                date_widget.has_new = False
                for j in range(date_item.childCount()):
                    satellite_item = date_item.child(j)
                    satellite_widget = self.tree.itemWidget(satellite_item, 0)
                    satellite_widget.has_new = False

            links = page.get()[page.LINKS_KEY]
            next_ = links.get(page.NEXT_KEY, None)
            self._has_more = next_ is not None
            images = page.get().get(page.ITEM_KEY)
            for i, image in enumerate(images):
                if self._passes_area_coverage_filter(image):
                    sort_criteria = "acquired"
                    date_item, satellite_item = self._find_items_for_satellite(
                        image)
                    date_widget = self.tree.itemWidget(date_item, 0)
                    satellite_widget = self.tree.itemWidget(satellite_item, 0)
                    item = SceneItem(image, sort_criteria)
                    widget = SceneItemWidget(image, sort_criteria,
                                             self._metadata_to_show, item)
                    widget.checkedStateChanged.connect(
                        self.checked_count_changed)
                    widget.checkedStateChanged.connect(
                        satellite_widget.update_checkbox)
                    widget.thumbnailChanged.connect(
                        satellite_widget.update_thumbnail)
                    item.setSizeHint(0, widget.sizeHint())
                    satellite_item.addChild(item)
                    self.tree.setItemWidget(item, 0, widget)
                    date_widget.update_for_children()
                    self._image_count += 1

            for i in range(self.tree.topLevelItemCount()):
                date_item = self.tree.topLevelItem(i)
                date_widget = self.tree.itemWidget(date_item, 0)
                for j in range(date_item.childCount()):
                    satellite_item = date_item.child(j)
                    satellite_widget = self.tree.itemWidget(satellite_item, 0)
                    satellite_widget.update_for_children()
                    satellite_widget.update_thumbnail()
                    satellite_item.sortChildren(0, Qt.AscendingOrder)
                date_widget.update_for_children()
                date_widget.update_thumbnail()
            self.item_count_changed()
        else:
            self._has_more = False
            self.item_count_changed()

    def _local_filter(self, name):
        for f in self._local_filters:
            if f.get("field_name") == name:
                return f

    def _passes_area_coverage_filter(self, image):
        aoi_geom = geometry_from_request(self._request)
        if aoi_geom is None:
            return True  # an ID filter is begin used, so it makes no sense to
            # check for are acoverage
        aoi_qgsgeom = qgsgeometry_from_geojson(aoi_geom)
        image_qgsgeom = qgsgeometry_from_geojson(image[GEOMETRY])
        filt = self._local_filter('area_coverage')
        if filt:
            minvalue = filt['config'].get('gte', 0)
            maxvalue = filt['config'].get('lte', 100)
            intersection = aoi_qgsgeom.intersection(image_qgsgeom)
            area_coverage = intersection.area() / aoi_qgsgeom.area() * 100
            return area_coverage > minvalue and area_coverage < maxvalue
        return True

    def _find_item_for_date(self, image):
        sort_criteria = "acquired"
        date = iso8601.parse_date(image[PROPERTIES][sort_criteria]).date()
        itemtype = image[PROPERTIES][ITEM_TYPE]
        count = self.tree.topLevelItemCount()
        for i in range(count):
            child = self.tree.topLevelItem(i)
            if child.date == date and child.itemtype == itemtype:
                return child
        date_item = DateItem(image, sort_criteria)
        widget = DateItemWidget(image, sort_criteria, date_item)
        date_item.setSizeHint(0, widget.sizeHint())
        self.tree.addTopLevelItem(date_item)
        self.tree.setItemWidget(date_item, 0, widget)
        return date_item

    def _find_items_for_satellite(self, image):
        date_item = self._find_item_for_date(image)
        date_widget = self.tree.itemWidget(date_item, 0)
        satellite = image[PROPERTIES][SATELLITE_ID]
        count = date_item.childCount()
        for i in range(count):
            child = date_item.child(i)
            if child.satellite == satellite:
                return date_item, child
        satellite_item = SatelliteItem(satellite)
        widget = SatelliteItemWidget(satellite, satellite_item)
        widget.checkedStateChanged.connect(date_widget.update_checkbox)
        widget.thumbnailChanged.connect(date_widget.update_thumbnail)
        satellite_item.setSizeHint(0, widget.sizeHint())
        date_item.addChild(satellite_item)
        self.tree.setItemWidget(satellite_item, 0, widget)
        return date_item, satellite_item

    def selected_images(self):
        selected = []
        it = QTreeWidgetItemIterator(self.tree)
        while it.value():
            item = it.value()
            if isinstance(item, SceneItem):
                w = self.tree.itemWidget(item, 0)
                w.set_metadata_to_show(self._metadata_to_show)
                if w.is_selected():
                    selected.append(w.image)
            it += 1
        return selected

    def checked_count_changed(self):
        hasSelection = bool(len(self.selected_images()))
        self.btnAddPreview.setEnabled(hasSelection)
        self.checkedCountChanged.emit(hasSelection)

    def item_count_changed(self):
        if self._image_count < self._total_count:
            self.lblImageCount.setText(
                f"{self._image_count} images. <a href='#'>Load more</a>")
        else:
            self.lblImageCount.setText(f"{self._image_count} images")

    def _setup_request_aoi_box(self):
        self._aoi_box = QgsRubberBand(iface.mapCanvas(),
                                      QgsWkbTypes.PolygonGeometry)
        self._aoi_box.setFillColor(QColor(0, 0, 0, 0))
        self._aoi_box.setStrokeColor(SEARCH_AOI_COLOR)
        self._aoi_box.setWidth(2)
        self._aoi_box.setLineStyle(Qt.DashLine)

    @pyqtSlot()
    def clear_aoi_box(self):
        if self._aoi_box:
            self._aoi_box.reset(QgsWkbTypes.PolygonGeometry)

    def clean_up(self):
        self.clear_aoi_box()
        self.tree.clear()
        self.lblImageCount.setText("")
        self._set_widgets_visibility(False)

    def closeEvent(self, event):
        self.clean_up()
        super().closeEvent(self, event)

    def request_query(self):
        return self._request
Example #31
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()
Example #32
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)
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 #34
0
class AdjustRasterMapTool(QgsMapToolEmitPoint):
    def __init__(self, iface):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rasterShadow = RasterShadowMapCanvasItem(self.canvas)

        self.rubberBandExtent = QgsRubberBand(self.canvas,
                                              QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.setColor(Qt.red)
        self.rubberBandExtent.setWidth(1)

        self.rubberBandAdjustSide = QgsRubberBand(self.canvas,
                                                  QgsWkbTypes.LineGeometry)
        self.rubberBandAdjustSide.setColor(Qt.red)
        self.rubberBandAdjustSide.setWidth(3)

        self.reset()

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

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandAdjustSide.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()
        self.layer = None

    def canvasPressEvent(self, e):
        # find the side of the rectangle closest to the click and some data
        # necessary to compute the new cneter and scale
        topLeft, topRight, bottomRight, bottomLeft = \
            self.layer.cornerCoordinates()
        top = [topLeft, topRight]
        right = [bottomRight, topRight]
        bottom = [bottomRight, bottomLeft]
        left = [bottomLeft, topLeft]

        click = QgsGeometry.fromPointXY(self.toMapCoordinates(e.pos()))

        # order is important (for referenceSide)
        sides = [top, right, bottom, left]
        distances = [
            click.distance(QgsGeometry.fromPolylineXY(side)) for side in sides
        ]
        self.indexSide = self.minDistance(distances)
        self.side = sides[self.indexSide]
        self.sidePoint = self.center(self.side)
        self.vector = self.directionVector(self.side)
        # side that does not move (opposite of indexSide)
        self.referenceSide = sides[(self.indexSide + 2) % 4]
        self.referencePoint = self.center(self.referenceSide)
        self.referenceDistance = self.distance(self.sidePoint,
                                               self.referencePoint)
        self.isXScale = self.indexSide % 2 == 1

        self.startPoint = click.asPoint()
        self.endPoint = self.startPoint
        self.isEmittingPoint = True

        self.isLayerVisible = isLayerVisible(self.iface, self.layer)
        setLayerVisible(self.iface, self.layer, False)

        adjustment = self.computeAdjustment()
        self.showAdjustment(*adjustment)
        self.layer.history.append({
            "action": "adjust",
            "center": self.layer.center,
            "xScale": self.layer.xScale,
            "yScale": self.layer.yScale
        })

    def minDistance(self, distances):
        sortedDistances = [
            i[0] for i in sorted(enumerate(distances), key=itemgetter(1))
        ]
        # first is min
        return sortedDistances[0]

    def directionVector(self, side):
        sideCenter = self.center(side)
        layerCenter = self.layer.center
        vector = [
            sideCenter.x() - layerCenter.x(),
            sideCenter.y() - layerCenter.y()
        ]
        norm = math.sqrt(vector[0]**2 + vector[1]**2)
        normedVector = [vector[0] / norm, vector[1] / norm]
        return normedVector

    def center(self, side):
        return QgsPointXY((side[0].x() + side[1].x()) / 2,
                          (side[0].y() + side[1].y()) / 2)

    def distance(self, pt1, pt2):
        return math.sqrt((pt1.x() - pt2.x())**2 + (pt1.y() - pt2.y())**2)

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandAdjustSide.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()

        center, xScale, yScale = self.computeAdjustment()
        self.layer.setCenter(center)
        self.layer.setScale(xScale * self.layer.xScale,
                            yScale * self.layer.yScale)

        setLayerVisible(self.iface, self.layer, self.isLayerVisible)
        self.layer.repaint()

        self.layer.commitTransformParameters()

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

        self.endPoint = self.toMapCoordinates(e.pos())

        adjustment = self.computeAdjustment()
        self.showAdjustment(*adjustment)

    def computeAdjustment(self):
        dX = self.endPoint.x() - self.startPoint.x()
        dY = self.endPoint.y() - self.startPoint.y()
        # project on vector
        dp = dX * self.vector[0] + dY * self.vector[1]

        # do not go beyond 5% of the current size of side
        if dp < -0.95 * self.referenceDistance:
            dp = -0.95 * self.referenceDistance

        updatedSidePoint = QgsPointXY(self.sidePoint.x() + dp * self.vector[0],
                                      self.sidePoint.y() + dp * self.vector[1])

        center = self.center([self.referencePoint, updatedSidePoint])
        scaleFactor = self.distance(self.referencePoint, updatedSidePoint)
        if self.isXScale:
            xScale = scaleFactor / self.referenceDistance
            yScale = 1.0
        else:
            xScale = 1.0
            yScale = scaleFactor / self.referenceDistance

        return (center, xScale, yScale)

    def showAdjustment(self, center, xScale, yScale):
        _, rotation, originalXScale, originalYScale = \
            self.layer.transformParameters()
        newXScale = xScale * originalXScale
        newYScale = yScale * originalYScale
        cornerPoints = self.layer.transformedCornerCoordinates(
            center, rotation, newXScale, newYScale)

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        for point in cornerPoints:
            self.rubberBandExtent.addPoint(point, False)
        # for closing
        self.rubberBandExtent.addPoint(cornerPoints[0], True)
        self.rubberBandExtent.show()

        # show rubberband for side
        # see def of indexSide in init:
        # cornerpoints are (topLeft, topRight, bottomRight, bottomLeft)
        self.rubberBandAdjustSide.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandAdjustSide.addPoint(cornerPoints[self.indexSide % 4],
                                           False)
        self.rubberBandAdjustSide.addPoint(
            cornerPoints[(self.indexSide + 1) % 4], True)
        self.rubberBandAdjustSide.show()

        self.rasterShadow.reset(self.layer)
        dx = center.x() - self.layer.center.x()
        dy = center.y() - self.layer.center.y()
        self.rasterShadow.setDeltaDisplacement(dx, dy, False)
        self.rasterShadow.setDeltaScale(xScale, yScale, True)
        self.rasterShadow.show()
Example #35
0
class MoveRasterMapTool(QgsMapToolEmitPoint):
    def __init__(self, iface):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rasterShadow = RasterShadowMapCanvasItem(self.canvas)

        self.rubberBandDisplacement = QgsRubberBand(self.canvas,
                                                    QgsWkbTypes.LineGeometry)
        self.rubberBandDisplacement.setColor(Qt.red)
        self.rubberBandDisplacement.setWidth(1)

        self.rubberBandExtent = QgsRubberBand(self.canvas,
                                              QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.setColor(Qt.red)
        self.rubberBandExtent.setWidth(1)

        self.isLayerVisible = True

        self.reset()

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

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()
        self.layer = None

    def canvasPressEvent(self, e):
        self.startPoint = self.toMapCoordinates(e.pos())
        self.endPoint = self.startPoint
        self.isEmittingPoint = True
        self.originalCenter = self.layer.center
        # this tool do the displacement itself TODO update so it is done by
        # transformed coordinates + new center)
        self.originalCornerPoints = self.layer.transformedCornerCoordinates(
            *self.layer.transformParameters())

        self.isLayerVisible = isLayerVisible(self.iface, self.layer)
        setLayerVisible(self.iface, self.layer, False)

        self.showDisplacement(self.startPoint, self.endPoint)
        self.layer.history.append({
            "action": "move",
            "center": self.layer.center
        })

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False

        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()

        x = self.originalCenter.x() + self.endPoint.x() - self.startPoint.x()
        y = self.originalCenter.y() + self.endPoint.y() - self.startPoint.y()
        self.layer.setCenter(QgsPointXY(x, y))

        setLayerVisible(self.iface, self.layer, self.isLayerVisible)
        self.layer.repaint()

        self.layer.commitTransformParameters()

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

        self.endPoint = self.toMapCoordinates(e.pos())
        self.showDisplacement(self.startPoint, self.endPoint)

    def showDisplacement(self, startPoint, endPoint):
        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        point1 = QgsPointXY(startPoint.x(), startPoint.y())
        point2 = QgsPointXY(endPoint.x(), endPoint.y())
        self.rubberBandDisplacement.addPoint(point1, False)
        self.rubberBandDisplacement.addPoint(point2,
                                             True)  # true to update canvas
        self.rubberBandDisplacement.show()

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        for point in self.originalCornerPoints:
            self._addDisplacementToPoint(self.rubberBandExtent, point, False)
        # for closing
        self._addDisplacementToPoint(self.rubberBandExtent,
                                     self.originalCornerPoints[0], True)
        self.rubberBandExtent.show()

        self.rasterShadow.reset(self.layer)
        self.rasterShadow.setDeltaDisplacement(
            self.endPoint.x() - self.startPoint.x(),
            self.endPoint.y() - self.startPoint.y(), True)
        self.rasterShadow.show()

    def _addDisplacementToPoint(self, rubberBand, point, doUpdate):
        x = point.x() + self.endPoint.x() - self.startPoint.x()
        y = point.y() + self.endPoint.y() - self.startPoint.y()
        self.rubberBandExtent.addPoint(QgsPointXY(x, y), doUpdate)
Example #36
0
class ScaleRasterMapTool(QgsMapToolEmitPoint):
    def __init__(self, iface):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rasterShadow = RasterShadowMapCanvasItem(self.canvas)

        self.rubberBandExtent = QgsRubberBand(self.canvas,
                                              QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.setColor(Qt.red)
        self.rubberBandExtent.setWidth(1)

        self.reset()

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

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()
        self.layer = None

    def canvasPressEvent(self, e):
        pressed_button = e.button()
        if pressed_button == 1:
            self.startPoint = e.pos()
            self.endPoint = self.startPoint
            self.isEmittingPoint = True
            self.height = float(self.canvas.height())
            self.width = float(self.canvas.width())

            modifiers = QApplication.keyboardModifiers()
            self.isKeepRelativeScale = bool(modifiers & Qt.ControlModifier)

            self.isLayerVisible = isLayerVisible(self.iface, self.layer)
            setLayerVisible(self.iface, self.layer, False)

            scaling = self.computeScaling()
            self.showScaling(*scaling)
        self.layer.history.append({
            "action": "scale",
            "xScale": self.layer.xScale,
            "yScale": self.layer.yScale
        })

    def canvasReleaseEvent(self, e):
        pressed_button = e.button()
        if pressed_button == 1:
            self.isEmittingPoint = False

            self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
            self.rasterShadow.reset()

            xScale, yScale = self.computeScaling()
            self.layer.setScale(xScale * self.layer.xScale,
                                yScale * self.layer.yScale)

            setLayerVisible(self.iface, self.layer, self.isLayerVisible)
        elif pressed_button == 2:
            number, ok = QInputDialog.getText(
                None, "Scale & DPI", "Enter scale,dpi (e.g. 3000,96)")
            if not ok:
                self.layer.history.pop()
                return
            scales = number.split(',')
            if len(scales) != 2:
                self.layer.history.pop()
                QMessageBox.information(self.iface.mainWindow(), "Error",
                                        "Must be 2 numbers")
                return
            scale = tryfloat(scales[0])
            dpi = tryfloat(scales[1])
            if scale and dpi:
                xScale = scale / (dpi / 0.0254)
                yScale = xScale
            else:
                self.layer.history.pop()
                QMessageBox.information(
                    self.iface.mainWindow(), "Error",
                    "Bad format: Must be scale,dpi (e.g. 3000,96)")
                return

            self.layer.setScale(xScale, yScale)

        self.layer.repaint()
        self.layer.commitTransformParameters()

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

        self.endPoint = e.pos()
        scaling = self.computeScaling()
        self.showScaling(*scaling)

    def computeScaling(self):
        dX = -(self.endPoint.x() - self.startPoint.x())
        dY = self.endPoint.y() - self.startPoint.y()
        xScale = 1.0 - (dX / (self.width * 1.1))
        yScale = 1.0 - (dY / (self.height * 1.1))

        if self.isKeepRelativeScale:
            # keep same scale in both dimensions
            return (xScale, xScale)
        else:
            return (xScale, yScale)

    def showScaling(self, xScale, yScale):
        if xScale == 0 and yScale == 0:
            return

        center, rotation, originalXScale, originalYScale = \
            self.layer.transformParameters()
        newXScale = xScale * originalXScale
        newYScale = yScale * originalYScale
        cornerPoints = self.layer.transformedCornerCoordinates(
            center, rotation, newXScale, newYScale)

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        for point in cornerPoints:
            self.rubberBandExtent.addPoint(point, False)
        # for closing
        self.rubberBandExtent.addPoint(cornerPoints[0], True)
        self.rubberBandExtent.show()

        self.rasterShadow.reset(self.layer)
        self.rasterShadow.setDeltaScale(xScale, yScale, True)
        self.rasterShadow.show()
class MultipleSelection(QgsMapTool):
    def __init__(self,
                 iface,
                 controller,
                 layers,
                 mincut=None,
                 parent_manage=None,
                 manage_new_psector=None,
                 table_object=None,
                 dialog=None):
        """ Class constructor """

        self.layers = layers
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.mincut = mincut
        self.parent_manage = parent_manage
        self.manage_new_psector = manage_new_psector
        self.table_object = table_object
        self.dialog = dialog

        # Call superclass constructor and set current action
        QgsMapTool.__init__(self, self.canvas)

        self.controller = controller
        self.rubber_band = QgsRubberBand(self.canvas, 2)
        self.rubber_band.setColor(QColor(255, 100, 255))
        self.rubber_band.setFillColor(QColor(254, 178, 76, 63))
        self.rubber_band.setWidth(1)
        self.reset()
        self.selected_features = []

        # Snapper
        self.snapper_manager = SnappingConfigManager(self.iface)
        self.snapper = self.snapper_manager.get_snapper()

    def reset(self):

        self.start_point = self.end_point = None
        self.is_emitting_point = False
        self.reset_rubber_band()

    def canvasPressEvent(self, event):

        if event.button() == Qt.LeftButton:
            self.start_point = self.toMapCoordinates(event.pos())
            self.end_point = self.start_point
            self.is_emitting_point = True
            self.show_rect(self.start_point, self.end_point)

    def canvasReleaseEvent(self, event):

        self.is_emitting_point = False
        rectangle = self.get_rectangle()
        selected_rectangle = None
        key = QApplication.keyboardModifiers()

        if event.button() != Qt.LeftButton:
            self.rubber_band.hide()
            return

        # Disconnect signal to enhance process
        # We will reconnect it when processing last layer of the group
        if self.mincut:
            self.mincut.disconnect_signal_selection_changed()
        if self.parent_manage:
            self.parent_manage.disconnect_signal_selection_changed()
        if self.manage_new_psector:
            self.manage_new_psector.disconnect_signal_selection_changed()

        for i in range(len(self.layers)):
            layer = self.layers[i]
            if i == len(self.layers) - 1:
                if self.mincut:
                    self.mincut.connect_signal_selection_changed(
                        "mincut_connec")
                if self.parent_manage:
                    self.parent_manage.connect_signal_selection_changed(
                        self.dialog, self.table_object)
                if self.manage_new_psector:
                    self.manage_new_psector.connect_signal_selection_changed(
                        self.manage_new_psector.dlg_plan_psector,
                        self.table_object)

            # Selection by rectangle
            if rectangle:
                if selected_rectangle is None:
                    selected_rectangle = self.canvas.mapSettings(
                    ).mapToLayerCoordinates(layer, rectangle)
                # If Ctrl+Shift clicked: remove features from selection
                if key == (Qt.ControlModifier | Qt.ShiftModifier):
                    layer.selectByRect(selected_rectangle,
                                       layer.RemoveFromSelection)
                # If Ctrl clicked: add features to selection
                elif key == Qt.ControlModifier:
                    layer.selectByRect(selected_rectangle,
                                       layer.AddToSelection)
                # If Ctrl not clicked: add features to selection
                else:
                    layer.selectByRect(selected_rectangle,
                                       layer.AddToSelection)

            # Selection one by one
            else:
                event_point = self.snapper_manager.get_event_point(event)
                result = self.snapper_manager.snap_to_background_layers(
                    event_point)
                if self.snapper_manager.result_is_valid():
                    # Get the point. Leave selection
                    self.snapper_manager.get_snapped_feature(result, True)

        self.rubber_band.hide()

    def canvasMoveEvent(self, event):

        if not self.is_emitting_point:
            return

        self.end_point = self.toMapCoordinates(event.pos())
        self.show_rect(self.start_point, self.end_point)

    def show_rect(self, start_point, end_point):

        self.reset_rubber_band()
        if start_point.x() == end_point.x() or start_point.y() == end_point.y(
        ):
            return

        point1 = QgsPointXY(start_point.x(), start_point.y())
        point2 = QgsPointXY(start_point.x(), end_point.y())
        point3 = QgsPointXY(end_point.x(), end_point.y())
        point4 = QgsPointXY(end_point.x(), start_point.y())

        self.rubber_band.addPoint(point1, False)
        self.rubber_band.addPoint(point2, False)
        self.rubber_band.addPoint(point3, False)
        self.rubber_band.addPoint(point4, True)
        self.rubber_band.show()

    def get_rectangle(self):

        if self.start_point is None or self.end_point is None:
            return None
        elif self.start_point.x() == self.end_point.x() or self.start_point.y(
        ) == self.end_point.y():
            return None

        return QgsRectangle(self.start_point, self.end_point)

    def deactivate(self):

        self.rubber_band.hide()
        QgsMapTool.deactivate(self)

    def activate(self):
        pass

    def reset_rubber_band(self):

        try:
            self.rubber_band.reset(2)
        except:
            pass
Example #38
0
class ParentMapTool(QgsMapTool):


    def __init__(self, iface, settings, action, index_action):  
        """ Class constructor """

        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.settings = settings
        self.show_help = bool(int(self.settings.value('status/show_help', 1)))
        self.index_action = index_action
        self.layer_arc = None        
        self.layer_connec = None        
        self.layer_node = None   
        
        self.layer_arc_man = None        
        self.layer_connec_man = None        
        self.layer_node_man = None
        self.layer_gully_man = None 
            
        self.schema_name = None        
        self.controller = None        
        self.dao = None 
        
        # Call superclass constructor and set current action        
        QgsMapTool.__init__(self, self.canvas)
        self.setAction(action)

        # Snapper
        self.snapper_manager = SnappingConfigManager(self.iface)
        self.snapper = QgsMapCanvasSnapper(self.canvas)
        
        # Change map tool cursor
        self.cursor = QCursor()
        self.cursor.setShape(Qt.CrossCursor)

        # Get default cursor
        self.std_cursor = self.parent().cursor()    
        
        # Set default vertex marker
        color = QColor(255, 100, 255)
        self.vertex_marker = QgsVertexMarker(self.canvas)
        self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
        self.vertex_marker.setColor(color)
        self.vertex_marker.setIconSize(15)
        self.vertex_marker.setPenWidth(3)  
                 
        # Set default rubber band
        color_selection = QColor(254, 178, 76, 63)
        self.rubber_band = QgsRubberBand(self.canvas, QGis.Polygon)   
        self.rubber_band.setColor(color)
        self.rubber_band.setFillColor(color_selection)           
        self.rubber_band.setWidth(1)           
        self.reset()
        
        self.force_active_layer = True
        
        # Set default encoding 
        reload(sys)
        sys.setdefaultencoding('utf-8')   #@UndefinedVariable    
        
        
    def get_cursor_multiple_selection(self):
        """ Set cursor for multiple selection """
        
        path_folder = os.path.join(os.path.dirname(__file__), os.pardir) 
        path_cursor = os.path.join(path_folder, 'icons', '201.png')                
        if os.path.exists(path_cursor):      
            cursor = QCursor(QPixmap(path_cursor))    
        else:        
            cursor = QCursor(Qt.ArrowCursor)  
                
        return cursor
     

    def set_layers(self, layer_arc_man, layer_connec_man, layer_node_man, layer_gully_man=None):
        """ Sets layers involved in Map Tools functions
            Sets Snapper Manager """
        self.layer_arc_man = layer_arc_man
        self.layer_connec_man = layer_connec_man
        self.layer_node_man = layer_node_man
        self.layer_gully_man = layer_gully_man
        self.snapper_manager.set_layers(layer_arc_man, layer_connec_man, layer_node_man, layer_gully_man)


    def set_controller(self, controller):
        self.controller = controller
        self.schema_name = controller.schema_name
        self.plugin_dir = self.controller.plugin_dir 
        self.snapper_manager.controller = controller
        
        
    def deactivate(self):
        
        # Uncheck button
        self.action().setChecked(False)

        # Restore previous snapping
        self.snapper_manager.recover_snapping_options()

        # Recover cursor
        self.canvas.setCursor(self.std_cursor)

        # Remove highlight
        self.vertex_marker.hide()        


    def set_icon(self, widget, icon):
        """ Set @icon to selected @widget """

        # Get icons folder
        icons_folder = os.path.join(self.plugin_dir, 'icons')           
        icon_path = os.path.join(icons_folder, str(icon) + ".png")           
        if os.path.exists(icon_path):
            widget.setIcon(QIcon(icon_path))
        else:
            self.controller.log_info("File not found", parameter=icon_path)
            
    
    def set_action_pan(self):
        """ Set action 'Pan' """  
        try:
            self.iface.actionPan().trigger()     
        except Exception:          
            pass  


    def reset(self):
                
        # Graphic elements
        self.rubber_band.reset(QGis.Polygon)

        # Selection
        self.snapped_feat = None      
        
    
    def cancel_map_tool(self):
        """ Executed if user press right button or escape key """
        
        # Reset rubber band
        self.reset()

        # Deactivate map tool
        self.deactivate()
        self.set_action_pan()
                        

    def remove_markers(self):
        """ Remove previous markers """
             
        vertex_items = [i for i in self.canvas.scene().items() if issubclass(type(i), QgsVertexMarker)]
        for ver in vertex_items:
            if ver in self.canvas.scene().items():
                self.canvas.scene().removeItem(ver)
        

    def refresh_map_canvas(self):
        """ Refresh all layers present in map canvas """
        
        self.canvas.refreshAllLayers()
        for layer_refresh in self.canvas.layers():
            layer_refresh.triggerRepaint()     
           
           
    def open_dialog(self, dlg=None, dlg_name=None, maximize_button=True, stay_on_top=True): 
        """ Open dialog """

        if dlg is None or type(dlg) is bool:
            dlg = self.dlg
            
        # Manage i18n of the dialog                  
        if dlg_name:      
            self.controller.manage_translation(dlg_name, dlg)      
            
        # Manage stay on top and maximize button
        if maximize_button and stay_on_top:           
            dlg.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowStaysOnTopHint)       
        elif not maximize_button and stay_on_top:
            dlg.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowStaysOnTopHint) 
        elif maximize_button and not stay_on_top:
            dlg.setWindowFlags(Qt.WindowMaximizeButtonHint)              

        # Open dialog
        dlg.open()    
                    

    def close_dialog(self, dlg=None, set_action_pan=True): 
        """ Close dialog """
        
        if dlg is None or type(dlg) is bool:
            dlg = self.dlg
        try:
            self.save_settings(dlg)
            dlg.close()
            if set_action_pan:
                map_tool = self.canvas.mapTool()
                # If selected map tool is from the plugin, set 'Pan' as current one 
                if map_tool.toolName() == '':
                    self.set_action_pan()
        except AttributeError:
            pass


    def load_settings(self, dialog=None):
        """ Load QGIS settings related with dialog position and size """

        if dialog is None:
            dialog = self.dlg

        try:
            x = self.controller.plugin_settings_value(dialog.objectName() + "_x")
            y = self.controller.plugin_settings_value(dialog.objectName() + "_y")
            width = self.controller.plugin_settings_value(dialog.objectName() + "_width", dialog.property('width'))
            height = self.controller.plugin_settings_value(dialog.objectName() + "_height", dialog.property('height'))

            if int(x) < 0 or int(y) < 0:
                dialog.resize(int(width), int(height))
            else:
                screens = ctypes.windll.user32
                screen_x = screens.GetSystemMetrics(78)
                screen_y = screens.GetSystemMetrics(79)
                if int(x) > screen_x:
                    x = int(screen_x) - int(width)
                if int(y) > screen_y:
                    y = int(screen_y)
                dialog.setGeometry(int(x), int(y), int(width), int(height))
        except:
            pass
            
            
    def save_settings(self, dialog=None):
        """ Save QGIS settings related with dialog position and size """   
                   
        if dialog is None:
            dialog = self.dlg
            
        try:             
            self.controller.plugin_settings_set_value(dialog.objectName() + "_width", dialog.property('width'))
            self.controller.plugin_settings_set_value(dialog.objectName() + "_height", dialog.property('height'))
            self.controller.plugin_settings_set_value(dialog.objectName() + "_x", dialog.pos().x())
            self.controller.plugin_settings_set_value(dialog.objectName() + "_y", dialog.pos().y())  
        except:
            pass                      
            
        
    def check_expression(self, expr_filter, log_info=False):
        """ Check if expression filter @expr is valid """
        
        if log_info:
            self.controller.log_info(expr_filter)
        expr = QgsExpression(expr_filter)
        if expr.hasParserError():
            message = "Expression Error"
            self.controller.log_warning(message, parameter=expr_filter)      
            return (False, expr)
        return (True, expr)
    
        
    def canvasMoveEvent(self, event):
        
        # Make sure active layer is always 'v_edit_node'
        cur_layer = self.iface.activeLayer()
        if cur_layer != self.layer_node and self.force_active_layer:
            self.iface.setActiveLayer(self.layer_node) 
          
        # Hide highlight
        self.vertex_marker.hide()
  
        try:
            # Get current mouse coordinates
            x = event.pos().x()
            y = event.pos().y()
            event_point = QPoint(x, y)
        except(TypeError, KeyError):
            self.iface.actionPan().trigger()
            return

        # Snapping
        (retval, result) = self.snapper.snapToCurrentLayer(event_point, 2)  # @UnusedVariable
  
        # That's the snapped features
        if result:          
            # Get the point and add marker on it
            point = QgsPoint(result[0].snappedVertex)
            self.vertex_marker.setCenter(point)
            self.vertex_marker.show()           
                             
Example #39
0
class OrientationMapTool(QgsMapTool):
    def __init__(self, iface):
        self.iface = iface
        self.settings = MySettings()
        self.canvas = iface.mapCanvas()
        self.rubber = QgsRubberBand(self.canvas)
        QgsMapTool.__init__(self, self.canvas)

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

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

    def canvasMoveEvent(self, mouseEvent):
        ori = self.get_orientation(mouseEvent.pos())
        if ori is None:
            self.rubber.reset()
        else:
            self.rubber.setToGeometry(ori.geometry(), None)

    def canvasPressEvent(self, mouseEvent):
        if mouseEvent.button() != Qt.LeftButton:
            self.rubber.reset()
            return
        ori = self.get_orientation(mouseEvent.pos())
        if ori is None:
            self.rubber.reset()
            return
        dlg = OrientationDialog(ori, self.rubber)
        if dlg.exec_():
            if ori.length != 0:
                ori.save()
        self.rubber.reset()

    def get_orientation(self, pos):
        match = self.snap_to_segment(pos)
        if not match.hasEdge():
            return None
        vertices = match.edgePoints()
        po = match.point()
        dist = (po.sqrDist(vertices[0]), po.sqrDist(vertices[1]))
        mindist = min(dist)
        if mindist == 0:
            return None
        i = dist.index(mindist)
        ve = vertices[i]
        az = po.azimuth(ve)
        return Orientation(self.iface, ve, az)

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

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

        snap_util = self.canvas.snappingUtils()
        old_layers = snap_util.layers()
        old_mode = snap_util.snapToMapMode()
        old_inter = snap_util.snapOnIntersections()
        snap_util.setLayers(snap_layers)
        snap_util.setSnapToMapMode(QgsSnappingUtils.SnapAdvanced)
        snap_util.setSnapOnIntersections(False)
        m = snap_util.snapToMap(map_point)
        snap_util.setLayers(old_layers)
        snap_util.setSnapToMapMode(old_mode)
        snap_util.setSnapOnIntersections(old_inter)
        return m
Example #40
0
class MapTool(QgsMapTool):
    geometry_changed = pyqtSignal(QgsGeometry, bool)
    tool_deactivated = pyqtSignal()

    def __init__(self, canvas, cursorstyle=Qt.CrossCursor):
        self.canvas = canvas
        QgsMapTool.__init__(self, canvas)
        self.caller = self.sender()
        self.cursorStyle = cursorstyle
        self.active = False
        # get selection color
        selcolor = self.canvas.selectionColor()
        mycolor = QColor(selcolor.red(), selcolor.green(), selcolor.blue(), 40)
        self.rb = QgsRubberBand(self.canvas)
        self.rb.setStrokeColor(QColor(255, 0, 0, 40))
        self.rb.setFillColor(mycolor)
        self.rb.setLineStyle(Qt.PenStyle(Qt.SolidLine))
        self.rb.setWidth(2)
        self.center = None
        self.segments = 120  #circle of 30 segments

    def setCursorStyle(self):
        cursor = QCursor()
        cursor.setShape(self.cursorStyle)
        self.setCursor(cursor)

    def activate(self):
        self.caller.setChecked(True)
        self.setCursorStyle()
        self.geometry_changed.emit(QgsGeometry(), False)

    def deactivate(self):
        self.canvas.scene().removeItem(self.rb)
        self.tool_deactivated.emit()
        self.caller.setChecked(False)
        QgsMapTool.deactivate(self)

    def setGeometry(self, geo):
        self.rb.setToGeometry(geo)

    def canvasPressEvent(self, e):
        if e.button() == Qt.LeftButton:
            self.active = True
            self.center = self.toMapCoordinates(e.pos())
            self.geometry_changed.emit(QgsGeometry(), False)
            self.rb.reset()
        pass

    def canvasMoveEvent(self, QgsMapMouseEvent):
        if self.active:
            cp = self.toMapCoordinates(QgsMapMouseEvent.pos())
            self.rbcircle(self.rb, self.center, cp, self.segments)
            self.geometry_changed.emit(self.rb.asGeometry(), True)
        pass

    def canvasReleaseEvent(self, mouseevent):
        if mouseevent.button() == Qt.LeftButton:
            self.active = False
            self.geometry_changed.emit(self.rb.asGeometry(), True)
        pass

    def rbcircle(self, rb, center, edgePoint, N):
        r = math.sqrt(center.sqrDist(edgePoint))
        rb.reset(QgsWkbTypes.PolygonGeometry)
        for itheta in range(N + 1):
            theta = itheta * (2.0 * math.pi / N)
            rb.addPoint(
                QgsPointXY(center.x() + r * math.cos(theta),
                           center.y() + r * math.sin(theta)))
        return
Example #41
0
class LineMapTool(MapTool, QgsMapToolEmitPoint):
    '''
    draw a line on the map (connected, multiple sections)

    Attributes
    ----------
    drawn : pyqtSignal
        emitted after double click or right click on the map canvas, emits the
        drawn line
    '''
    drawn = pyqtSignal(QgsGeometry)
    wkbtype = QgsWkbTypes.LineGeometry

    def __init__(self,
                 ui_element: QWidget,
                 canvas: QgsMapCanvas = None,
                 color: Union[str, int] = None,
                 draw_markers=False,
                 line_width: int = 2,
                 line_style: int = Qt.SolidLine,
                 snap_geometry: QgsGeometry = None,
                 target_epsg: int = 25832):
        '''
        Parameters
        ----------
        ui_element : QWidget
            clickable UI element, clicking it will activate/deactivate this
            tool
        canvas : QgsMapCanvas, optional
            the map canvas the tool will work on, defaults to the map canvas of
            the QGIS UI
        color : int or str, optional
            color description, sets color of line and markers while
            drawing, defaults to blue
        draw_markers : bool, optional
            draw markers between segments of the line, defaults to no markers
        line_width : int, optional
            width of drawn lines in pixels, defaults to 2 pixels
        line_style : int, optional
            style of drawn lines (e.g. Qt.DashDotLine), defaults to solid line
        snap_geometry : QgsGeometry, optional
            snap drawn lines to outline of given geometry, defaults to no
            snapping
        target_epsg : int, optional
            projection of emitted geometry after drawing as epsg code,
            defaults to 25832
        '''
        self.canvas = canvas
        MapTool.__init__(self, ui_element, self.canvas)
        QgsMapToolEmitPoint.__init__(self, canvas=self.canvas)
        self.rubberband = QgsRubberBand(self.canvas, self.wkbtype)
        self.color = QColor(color) if color else QColor(0, 0, 255)
        self.rubberband.setColor(self.color)
        self.color.setAlpha(100)
        self.rubberband.setFillColor(self.color)
        self.rubberband.setLineStyle(line_style)
        self.rubberband.setWidth(line_width)

        self.snap_geometry = self.set_snap_geometry(snap_geometry)
        self.draw_markers = draw_markers
        if self.draw_markers:
            # auto points on outline should but doesn't work:
            #self.drawing_lines.setIcon(QgsRubberBand.ICON_CIRCLE)
            #self.drawing_lines.setIconSize(8)

            # drawing markers manually instead
            self.markers = []

        self._drawing = False
        self._moving = False

        # marker for showing snapped point on move
        self._move_marker = QgsVertexMarker(self.canvas)
        self._move_marker.setColor(self.color)
        self._move_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
        self._move_marker.setIconSize(10)
        self._move_marker.setPenWidth(3)

        self.reset()

    def set_snap_geometry(self, geom: QgsGeometry):
        '''
        snap lines to outline of given geometry

        Parameters
        ----------
        snap_geometry : QgsGeometry
            geometry to snap lines to
        '''
        if not geom:
            return
        if SHAPELY_LOADED:
            self.snap_geometry = wkt.loads(geom.asWkt()).boundary
        # alternative for MacOS
        else:
            self.snap_geometry = QgsCurvePolygon()
            self.snap_geometry.fromWkt(geom.asWkt())

    def reset(self):
        '''
        reset drawing
        '''
        scene = self.canvas.scene()
        if self.draw_markers:
            for m in self.markers:
                scene.removeItem(m)
            self.markers = []
        self._moving = False
        self._drawing = False
        self.rubberband.reset(self.wkbtype)

    def canvasDoubleClickEvent(self, e):
        '''
        override, emit line on double click
        '''
        if self._moving:
            self.rubberband.removeLastPoint()
        geom = self.rubberband.asGeometry()
        self.drawn.emit(self.transform_from_map(geom))
        self.reset()

    def _snap(self, point: QgsPoint) -> QgsPointXY:
        '''
        snap point to snap-geometry
        '''
        point = self.transform_from_map(point)
        if SHAPELY_LOADED:
            p = geometry.Point(point.x(), point.y())
            np = nearest_points(self.snap_geometry, p)[0]
            p = QgsPointXY(np.x, np.y)
        # alternative for MacOS
        else:
            closest = QgsGeometryUtils.closestPoint(
                self.snap_geometry, QgsPoint(point.x(), point.y()))
            p = QgsPointXY(closest.x(), closest.y())
        p = self.transform_to_map(p)
        return p

    def canvasPressEvent(self, e):
        '''
        override, finish line segment when map is clicked
        '''
        if (e.button() == Qt.RightButton):
            if self._moving:
                self.rubberband.removeLastPoint()
            geom = self.rubberband.asGeometry()
            self.drawn.emit(self.transform_from_map(geom))
            self.reset()
            return
        self._moving = False
        self._drawing = True
        point = self.toMapCoordinates(e.pos())
        if self.snap_geometry:
            point = self._snap(point)
        self.rubberband.addPoint(point, True)
        if self.draw_markers:
            marker = QgsVertexMarker(self.canvas)
            marker.setCenter(point)
            marker.setColor(self.color)
            marker.setIconSize(8)
            marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
            marker.setPenWidth(4)
            self.markers.append(marker)

    def canvasMoveEvent(self, e):
        '''
        override, draw connecting line to last segment when moving mouse
        '''
        if not self.snap_geometry and not self._drawing:
            return
        point = self.toMapCoordinates(e.pos())
        if self.snap_geometry:
            point = self._snap(point)
        if self.snap_geometry:
            self._move_marker.setCenter(point)
        if self._drawing:
            #self.rubberBand.removeLastPoint()
            if self._moving:
                self.rubberband.removeLastPoint()
            self.rubberband.addPoint(point, True)
            self._moving = True

    def disconnect(self, **kwargs):
        '''
        override, 'remove' marker
        '''
        if self._move_marker:
            #scene = self.canvas.scene()
            #scene.removeItem(self._move_marker)
            # workaround: if removed from scene marker won't appear any more
            # set it somewhere it can't be seen
            self._move_marker.setCenter(QgsPointXY(0, 0))
        super().disconnect(**kwargs)
Example #42
0
class InfoTool(TouchMapTool):
    infoResults = pyqtSignal(dict)

    def __init__(self, canvas, snapradius = 2):
        super(InfoTool, self).__init__(canvas)
        self.radius = snapradius

        self.band = QgsRubberBand(self.canvas)
        self.band.setColor(QColor.fromRgb(224,162,16))
        self.band.setWidth(3)

        self.selectband = None
        self.selectrect = QRect()
        self.dragging = False
        self.selectionlayers = []

    def getFeatures(self, rect, firstonly=False):
        self.band.reset()
        for layer in self.selectionlayers.itervalues():
            if (not layer.type() == QgsMapLayer.VectorLayer
                or layer.geometryType() == QGis.NoGeometry):
                continue

            rect = self.toLayerCoordinates(layer, rect)
            rq = QgsFeatureRequest().setFilterRect(rect)\
                                    .setFlags(QgsFeatureRequest.ExactIntersect)\
                                    .setSubsetOfAttributes([])
            features = []
            if firstonly:
                try:
                    feature = layer.getFeatures(rq).next()
                    if feature.isValid():
                        features.append(feature)
                except StopIteration:
                    continue
            else:
                for feature in layer.getFeatures(rq):
                    if feature.isValid():
                        features.append(feature)

            yield layer, features

    def toSearchRect(self, point):
        point = self.toMapCoordinates(point)
        rect = QgsRectangle(point.x(), point.y(), point.x() + 10, point.y() + 10)
        return rect

    def canvasPressEvent(self, event):
        if self.pinching:
            return

        self.dragging = False
        self.selectrect.setRect(0, 0, 0, 0)

        self.selectband = QgsRubberBand(self.canvas, QGis.Polygon )
        self.selectband.setColor(QColor.fromRgb(0,0,255, 65))
        self.selectband.setWidth(5)

    def canvasMoveEvent(self, event):
        if self.pinching:
            return

        if not event.buttons() == Qt.LeftButton:
            return

        if not self.dragging:
            self.selectrect.setTopLeft(event.pos())
            self.dragging = True
        self.selectrect.setBottomRight(event.pos())

        maptoolutils.setRubberBand(self.canvas, self.selectrect, self.selectband)

    def canvasReleaseEvent(self, event):
        if self.pinching:
            return

        if self.dragging:
            geometry = self.selectband.asGeometry()
            if not geometry:
                return

            rect = geometry.boundingBox()
            firstonly = False
        else:
            firstonly = True
            rect = self.toSearchRect(event.pos())

        self.dragging = False
        self.selectband.reset()

        results = OrderedDict((l,f) for l, f in self.getFeatures(rect))
        self.infoResults.emit(results)
class QgepMapToolAddFeature(QgsMapToolAdvancedDigitizing):
    """
    Base class for adding features
    """
    def __init__(self, iface: QgisInterface, layer):
        QgsMapToolAdvancedDigitizing.__init__(self, iface.mapCanvas(),
                                              iface.cadDockWidget())
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.layer = layer
        self.rubberband = QgepRubberBand3D(iface.mapCanvas(),
                                           layer.geometryType())
        self.rubberband.setColor(QColor("#ee5555"))
        self.rubberband.setWidth(1)
        self.temp_rubberband = QgsRubberBand(iface.mapCanvas(),
                                             layer.geometryType())
        self.temp_rubberband.setColor(QColor("#ee5555"))
        self.temp_rubberband.setWidth(1)
        self.temp_rubberband.setLineStyle(Qt.DotLine)

    def activate(self):
        """
        When activating the map tool
        """
        QgsMapToolAdvancedDigitizing.activate(self)
        self.canvas.setCursor(QCursor(Qt.CrossCursor))

    def deactivate(self):
        """
        On deactivating the map tool
        """
        QgsMapToolAdvancedDigitizing.deactivate(self)
        self.canvas.unsetCursor()

    # pylint: disable=no-self-use
    def isZoomTool(self):
        """
        This is no zoom tool
        """
        return False

    # ===========================================================================
    # Events
    # ===========================================================================

    def cadCanvasReleaseEvent(self, event):
        """
        Called when a mouse button is
        :param event:
        :return:
        """
        if event.button() == Qt.RightButton:
            self.right_clicked(event)
        else:
            self.left_clicked(event)

    def left_clicked(self, event):
        """
        When the canvas is left clicked we add a new point to the rubberband.
        :type event: QMouseEvent
        """
        mousepos = self.canvas.getCoordinateTransform()\
            .toMapCoordinates(event.pos().x(), event.pos().y())
        self.rubberband.addPoint(mousepos)
        self.temp_rubberband.reset()

    def right_clicked(self, _):
        """
        On a right click we create a new feature from the existing rubberband and show the add
        dialog
        """
        f = QgsFeature(self.layer.fields())
        f.setGeometry(self.rubberband.asGeometry())
        dlg = self.iface.getFeatureForm(self.layer, f)
        dlg.setMode(QgsAttributeForm.AddFeatureMode)
        dlg.exec_()
        self.rubberband.reset3D()
        self.temp_rubberband.reset()

    def cadCanvasMoveEvent(self, event):
        """
        When the mouse is moved the rubberband needs to be updated
        :param event: The coordinates etc.
        """

        # When a generated event arrives it's a QMoveEvent... No idea why, but this prevents from an exception
        try:
            QgsMapToolAdvancedDigitizing.cadCanvasMoveEvent(self, event)
            mousepos = event.mapPoint()
            self.temp_rubberband.movePoint(mousepos)
            self.mouse_move(event)

        except TypeError:
            pass

    def mouse_move(self, event):
        pass
Example #44
0
class EditTool(MapTool):
    """
        Inspection tool which copies the feature to a new layer
        and copies selected data from the underlying feature.
    """
    
    finished = pyqtSignal(object, QgsFeature)
    featuresfound = pyqtSignal(dict)

    def __init__(self, canvas, forms, snapradius = 2):
        MapTool.__init__(self, canvas, [])
        self.canvas = canvas
        self.radius = snapradius
        self.forms = forms
        
        self.band = QgsRubberBand(self.canvas)
        self.band.setColor(QColor.fromRgb(224,162,16))
        self.band.setWidth(3)
        
        self.selectband = None
        
        self.selectrect = QRect()
        self.dragging = False

        self.cursor = QCursor(QPixmap(["16 16 3 1",
            "      c None",
            ".     c #FF0000",
            "+     c #FFFFFF",
            "                ",
            "       +.+      ",
            "      ++.++     ",
            "     +.....+    ",
            "    +.     .+   ",
            "   +.   .   .+  ",
            "  +.    .    .+ ",
            " ++.    .    .++",
            " ... ...+... ...",
            " ++.    .    .++",
            "  +.    .    .+ ",
            "   +.   .   .+  ",
            "   ++.     .+   ",
            "    ++.....+    ",
            "      ++.++     ",
            "       +.+      "]))

    def addForm(self, form):
        self.forms.append(form)
        self.layersupdated.emit(True)

    def layers(self):
        """
        Return a set of layers that this edit tool can work on
        """
        return set([form.QGISLayer for form in self.forms])

    def formsforlayer(self, layer):
        for form in self.forms:
            if form.QGISLayer == layer:
                yield form

    def reset(self):
        self.forms = []
        self.layersupdated.emit(False)

    def getFeatures(self, rect):
        rq = QgsFeatureRequest().setFilterRect(rect)

        self.band.reset()
        for layer in self.layers():
            forms = list(self.formsforlayer(layer))
            rq = QgsFeatureRequest().setFilterRect(rect)
            for feature in layer.getFeatures(rq):
                if feature.isValid():
                    yield feature, forms
                    
    def toSearchRect(self, point):
        searchRadius =  self.canvas.extent().width() * ( self.radius / 100.0 )

        point = self.toMapCoordinates(point)

        rect = QgsRectangle()                                                 
        rect.setXMinimum(point.x() - searchRadius)
        rect.setXMaximum(point.x() + searchRadius)
        rect.setYMinimum(point.y() - searchRadius)
        rect.setYMaximum(point.y() + searchRadius)
        return rect

    def canvasPressEvent(self, event):
        self.selectrect.setRect( 0, 0, 0, 0 )
        
        self.selectband = QgsRubberBand(self.canvas, QGis.Polygon )
        self.selectband.setColor(QColor.fromRgb(0,0,255, 65))
        self.selectband.setWidth(5)
        
    def canvasMoveEvent(self, event):
        if not event.buttons() == Qt.LeftButton:
            return
        
        if not self.dragging:
            self.dragging = True
            self.selectrect.setTopLeft(event.pos())
        self.selectrect.setBottomRight(event.pos())
        
        maptoolutils.setRubberBand(self.canvas, self.selectrect, self.selectband)  
                     
    def canvasReleaseEvent(self, event):
        if self.dragging:
            geometry = self.selectband.asGeometry()
            if not geometry:
                return

            rect = geometry.boundingBox()            
        else:
            rect = self.toSearchRect(event.pos())
            
        self.dragging = False
        self.selectband.reset()
            
        features = dict(self.getFeatures(rect))
        print features
            
        if len(features) == 1:
            feature = features.keys()[0]
            forms = features.values()[0]
            if len(forms) == 1:
                self.finished.emit(forms[0], feature)
            else:
                self.featuresfound.emit(features)
        elif len(features) > 0:
            self.featuresfound.emit(features)

    def isEditTool(self):
        return True
Example #45
0
class ParentMapTool(QgsMapTool):
    def __init__(self, iface, settings, action, index_action):
        """ Class constructor """

        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.settings = settings
        self.show_help = bool(int(self.settings.value('status/show_help', 1)))
        self.index_action = index_action
        self.layer_arc = None
        self.layer_connec = None
        self.layer_gully = None
        self.layer_node = None
        self.schema_name = None
        self.controller = None
        self.dao = None
        self.snapper_manager = None

        # Call superclass constructor and set current action
        QgsMapTool.__init__(self, self.canvas)
        self.setAction(action)

        # Change map tool cursor
        self.cursor = QCursor()
        self.cursor.setShape(Qt.CrossCursor)

        # Get default cursor
        self.std_cursor = self.parent().cursor()

        # Set default vertex marker
        color = QColor(255, 100, 255)
        self.vertex_marker = QgsVertexMarker(self.canvas)
        self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
        self.vertex_marker.setColor(color)
        self.vertex_marker.setIconSize(15)
        self.vertex_marker.setPenWidth(3)

        # Set default rubber band
        color_selection = QColor(254, 178, 76, 63)
        self.rubber_band = QgsRubberBand(self.canvas, 2)
        self.rubber_band.setColor(color)
        self.rubber_band.setFillColor(color_selection)
        self.rubber_band.setWidth(1)
        self.reset()

        self.force_active_layer = True

    def get_cursor_multiple_selection(self):
        """ Set cursor for multiple selection """

        path_folder = os.path.join(os.path.dirname(__file__), os.pardir)
        path_cursor = os.path.join(path_folder, 'icons', '201.png')
        if os.path.exists(path_cursor):
            cursor = QCursor(QPixmap(path_cursor))
        else:
            cursor = QCursor(Qt.ArrowCursor)

        return cursor

    def set_controller(self, controller):

        self.controller = controller
        self.schema_name = controller.schema_name
        self.plugin_dir = self.controller.plugin_dir
        if self.snapper_manager is None:
            self.snapper_manager = SnappingConfigManager(self.iface)
        self.snapper_manager.controller = controller

    def deactivate(self):

        # Uncheck button
        self.action().setChecked(False)

        # Restore previous snapping
        self.snapper_manager.recover_snapping_options()

        # Enable snapping
        self.snapper_manager.enable_snapping(True)

        # Recover cursor
        self.canvas.setCursor(self.std_cursor)

        # Remove highlight
        self.vertex_marker.hide()

    def recover_previus_maptool(self):
        if self.controller.prev_maptool:
            self.iface.mapCanvas().setMapTool(self.controller.prev_maptool)
            self.controller.prev_maptool = None

    def remove_vertex(self):
        """ Remove vertex_marker from canvas"""
        vertex_items = [
            i for i in self.iface.mapCanvas().scene().items()
            if issubclass(type(i), QgsVertexMarker)
        ]

        for ver in vertex_items:
            if ver in self.iface.mapCanvas().scene().items():
                if self.vertex_marker == ver:
                    self.iface.mapCanvas().scene().removeItem(ver)

    def set_icon(self, widget, icon):
        """ Set @icon to selected @widget """

        # Get icons folder
        icons_folder = os.path.join(self.plugin_dir, 'icons')
        icon_path = os.path.join(icons_folder, str(icon) + ".png")
        if os.path.exists(icon_path):
            widget.setIcon(QIcon(icon_path))
        else:
            self.controller.log_info("File not found", parameter=icon_path)

    def set_action_pan(self):
        """ Set action 'Pan' """
        try:
            self.iface.actionPan().trigger()
        except Exception:
            pass

    def reset_rubber_band(self, geom_type="polygon"):

        try:
            if geom_type == "polygon":
                geom_type = QgsWkbTypes.PolygonGeometry
            elif geom_type == "line":
                geom_type = QgsWkbTypes.LineString
            self.rubber_band.reset(geom_type)
        except:
            pass

    def reset(self):

        self.reset_rubber_band()
        self.snapped_feat = None

    def cancel_map_tool(self):
        """ Executed if user press right button or escape key """

        # Reset rubber band
        self.reset()

        # Deactivate map tool
        self.deactivate()
        self.set_action_pan()

    def remove_markers(self):
        """ Remove previous markers """

        vertex_items = [
            i for i in list(self.canvas.scene().items())
            if issubclass(type(i), QgsVertexMarker)
        ]
        for ver in vertex_items:
            if ver in list(self.canvas.scene().items()):
                self.canvas.scene().removeItem(ver)

    def refresh_map_canvas(self):
        """ Refresh all layers present in map canvas """

        self.canvas.refreshAllLayers()
        for layer_refresh in self.canvas.layers():
            layer_refresh.triggerRepaint()

    def open_dialog(self,
                    dlg=None,
                    dlg_name=None,
                    info=True,
                    maximize_button=True,
                    stay_on_top=True):
        """ Open dialog """

        # Check database connection before opening dialog
        if not self.controller.check_db_connection():
            return

        if dlg is None or type(dlg) is bool:
            dlg = self.dlg

        # Manage i18n of the dialog
        if dlg_name:
            self.controller.manage_translation(dlg_name, dlg)

        # Manage stay on top, maximize/minimize button and information button
        # if info is True maximize flag will be ignored
        # To enable maximize button you must set info to False
        flags = Qt.WindowCloseButtonHint
        if info:
            flags |= Qt.WindowSystemMenuHint | Qt.WindowContextHelpButtonHint
        else:
            if maximize_button:
                flags |= Qt.WindowMinMaxButtonsHint

        if stay_on_top:
            flags |= Qt.WindowStaysOnTopHint

        dlg.setWindowFlags(flags)

        # Open dialog
        if issubclass(type(dlg), GwDialog):
            dlg.open()
        elif issubclass(type(dlg), GwMainWindow):
            dlg.show()
        else:
            dlg.show()

    def close_dialog(self, dlg=None, set_action_pan=True):
        """ Close dialog """

        if dlg is None or type(dlg) is bool:
            dlg = self.dlg
        try:
            self.save_settings(dlg)
            dlg.close()
            if set_action_pan:
                map_tool = self.canvas.mapTool()
                # If selected map tool is from the plugin, set 'Pan' as current one
                if map_tool.toolName() == '':
                    self.set_action_pan()
        except AttributeError:
            pass

    def load_settings(self, dialog=None):
        """ Load QGIS settings related with dialog position and size """

        if dialog is None:
            dialog = self.dlg

        try:
            x = self.controller.plugin_settings_value(dialog.objectName() +
                                                      "_x")
            y = self.controller.plugin_settings_value(dialog.objectName() +
                                                      "_y")
            width = self.controller.plugin_settings_value(
                dialog.objectName() + "_width", dialog.property('width'))
            height = self.controller.plugin_settings_value(
                dialog.objectName() + "_height", dialog.property('height'))

            if int(x) < 0 or int(y) < 0:
                dialog.resize(int(width), int(height))
            else:
                screens = ctypes.windll.user32
                screen_x = screens.GetSystemMetrics(78)
                screen_y = screens.GetSystemMetrics(79)
                if int(x) > screen_x:
                    x = int(screen_x) - int(width)
                if int(y) > screen_y:
                    y = int(screen_y)
                dialog.setGeometry(int(x), int(y), int(width), int(height))
        except:
            pass

    def save_settings(self, dialog=None):
        """ Save QGIS settings related with dialog position and size """

        if dialog is None:
            dialog = self.dlg

        try:
            self.controller.plugin_settings_set_value(
                dialog.objectName() + "_width", dialog.property('width'))
            self.controller.plugin_settings_set_value(
                dialog.objectName() + "_height", dialog.property('height'))
            self.controller.plugin_settings_set_value(
                dialog.objectName() + "_x",
                dialog.pos().x())
            self.controller.plugin_settings_set_value(
                dialog.objectName() + "_y",
                dialog.pos().y())
        except:
            pass

    def check_expression(self, expr_filter, log_info=False):
        """ Check if expression filter @expr is valid """

        if log_info:
            self.controller.log_info(expr_filter)
        expr = QgsExpression(expr_filter)
        if expr.hasParserError():
            message = "Expression Error"
            self.controller.log_warning(message, parameter=expr_filter)
            return False, expr

        return True, expr

    def get_composers_list(self):

        layour_manager = QgsProject.instance().layoutManager().layouts()
        active_composers = [layout for layout in layour_manager]

        return active_composers

    def get_composer_index(self, name):

        index = 0
        composers = self.get_composers_list()
        for comp_view in composers:
            composer_name = comp_view.name()
            if composer_name == name:
                break
            index += 1

        return index

    def canvasMoveEvent(self, event):

        # Make sure active layer is always 'v_edit_node'
        cur_layer = self.iface.activeLayer()
        if cur_layer != self.layer_node and self.force_active_layer:
            self.iface.setActiveLayer(self.layer_node)

        # Hide highlight and get coordinates
        self.vertex_marker.hide()
        event_point = self.snapper_manager.get_event_point(event)

        # Snapping
        result = self.snapper_manager.snap_to_current_layer(event_point)
        if self.snapper_manager.result_is_valid():
            self.snapper_manager.add_marker(result, self.vertex_marker)

    def create_body(self, form='', feature='', filter_fields='', extras=None):
        """ Create and return parameters as body to functions"""

        client = f'$${{"client":{{"device":4, "infoType":1, "lang":"ES"}}, '
        form = f'"form":{{{form}}}, '
        feature = '"feature":{' + feature + '}, '
        filter_fields = '"filterFields":{' + filter_fields + '}'
        page_info = '"pageInfo":{}'
        data = '"data":{' + filter_fields + ', ' + page_info
        if extras:
            data += ', ' + extras
        data += f'}}}}$$'
        body = "" + client + form + feature + data

        return body

    def refresh_legend(self):
        """ This function solves the bug generated by changing the type of feature.
        Mysteriously this bug is solved by checking and unchecking the categorization of the tables.
        # TODO solve this bug
        """
        layers = [
            self.controller.get_layer_by_tablename('v_edit_node'),
            self.controller.get_layer_by_tablename('v_edit_connec'),
            self.controller.get_layer_by_tablename('v_edit_gully')
        ]

        for layer in layers:
            if layer:
                ltl = QgsProject.instance().layerTreeRoot().findLayer(
                    layer.id())
                ltm = self.iface.layerTreeView().model()
                legendNodes = ltm.layerLegendNodes(ltl)
                for ln in legendNodes:
                    current_state = ln.data(Qt.CheckStateRole)
                    ln.setData(Qt.Unchecked, Qt.CheckStateRole)
                    ln.setData(Qt.Checked, Qt.CheckStateRole)
                    ln.setData(current_state, Qt.CheckStateRole)

    def put_layer_into_toc(self,
                           tablename=None,
                           the_geom="the_geom",
                           field_id="id",
                           group='GW Layers'):
        """ Put layer from postgres DB into TOC"""
        schema_name = self.controller.credentials['schema'].replace('"', '')
        uri = QgsDataSourceUri()
        uri.setConnection(self.controller.credentials['host'],
                          self.controller.credentials['port'],
                          self.controller.credentials['db'],
                          self.controller.credentials['user'],
                          self.controller.credentials['password'])
        if not field_id:
            field_id = self.controller.get_pk(tablename)
            if not field_id:
                field_id = "id"
        uri.setDataSource(schema_name, f'{tablename}', the_geom, None,
                          field_id)
        layer = QgsVectorLayer(uri.uri(), f'{tablename}', "postgres")

        root = QgsProject.instance().layerTreeRoot()
        my_group = root.findGroup(group)
        if my_group is None:
            my_group = root.insertGroup(0, group)

        my_group.insertLayer(0, layer)
        self.iface.mapCanvas().refresh()
        return layer

    def populate_info_text(self,
                           dialog,
                           data,
                           force_tab=True,
                           reset_text=True,
                           tab_idx=1):

        change_tab = False
        text = utils_giswater.getWidgetText(dialog,
                                            'txt_infolog',
                                            return_string_null=False)
        if reset_text:
            text = ""
        for item in data['info']['values']:
            if 'message' in item:
                if item['message'] is not None:
                    text += str(item['message']) + "\n"
                    if force_tab:
                        change_tab = True
                else:
                    text += "\n"

        utils_giswater.setWidgetText(dialog, 'txt_infolog', text + "\n")
        qtabwidget = dialog.findChild(QTabWidget, 'mainTab')
        if change_tab and qtabwidget is not None:
            qtabwidget.setCurrentIndex(tab_idx)

        return change_tab
Example #46
0
class BucketFill:
    """A little plugin to allow you to set the color of a vector
    class by clicking on it."""
    def __init__(self, IFACE):
        # Save reference to the QGIS interface
        self.iface = IFACE
        self.canvas = self.iface.mapCanvas()
        self.bucketTool = QgsMapToolEmitPoint(self.canvas)
        self.polygonFlag = True
        self.rubberband = QgsRubberBand(self.canvas, self.polygonFlag)

    def initGui(self):
        """Called by QGIS to add gui elements to its Mainwindow
         etc. BucketFill class.

        Args:
            None
        Returns:
            None
        Raises:
            None

        """
        self.initActions()
        # Add toolbar button and menu item - colour chooser
        self.iface.addToolBarIcon(self.colorChooserAction)
        self.iface.addPluginToMenu("&Bucket fill", self.colorChooserAction)
        # Add toolbar button and menu item - map tool
        self.iface.addToolBarIcon(self.bucketFillAction)
        self.iface.addPluginToMenu("&Bucket fill", self.bucketFillAction)

    def initActions(self):
        """Setup actions. Implemented in a separate function so it can
        be used in the context of our testing framework.

        Args:
            None
        Returns:
            None
        Raises:
            None

        """
        # Create action that will start plugin configuration
        self.colorChooserAction = (QAction(
            QIcon(":/plugins/bucketfill/icon.png"), "Bucket fill",
            self.iface.mainWindow()))
        self.bucketFillAction = (QAction(
            QIcon(":/plugins/bucketfill/bucket.png"), "Bucket fill",
            self.iface.mainWindow()))
        # connect the action to the chooseColor method
        QObject.connect(self.colorChooserAction, SIGNAL("triggered()"),
                        self.chooseColor)
        QObject.connect(self.bucketFillAction, SIGNAL("triggered()"),
                        self.enableBucketTool)
        QObject.connect(
            self.bucketTool,
            SIGNAL("canvasClicked(const QgsPoint &, Qt::MouseButton)"),
            self.setColorForClass)

    def unload(self):
        """Constructor for the BucketFill class.

        Args:
            None
        Returns:
            None
        Raises:
            None

        """
        self.iface.removePluginMenu("&Bucket fill", self.colorChooserAction)
        self.iface.removeToolBarIcon(self.colorChooserAction)
        self.iface.removeToolBarIcon(self.bucketFillAction)

    def chooseColor(self):
        """Show a color picker to let the user choose a color.

        Args:
            None
        Returns:
            None
        Raises:
            None

        """
        mySettings = QSettings()
        try:
            myInitialColor = QColor(
                mySettings.value("vectorbucketfill/current_color"))
        except:
            myInitialColor = QColor(255, 255, 255)
        #myColor = QColor()
        myColor = QColorDialog.getColor(initial=myInitialColor)
        #myColorSelect = BucketFillDialog()
        if QColor.isValid(myColor):
            # do something useful
            mySettings.setValue("vectorbucketfill/current_color", myColor)

    def enableBucketTool(self):
        """Make the bucket tool active on the canvas.

        Args:
            None
        Returns:
            None
        Raises:
            None

        """
        self.canvas.setMapTool(self.bucketTool)

    def setColorForClass(self, thePoint, theButton):
        """Set the color of the active layer's feature
        class that falls under the cursor

        Args:

            * thePoint - a QgsPoint indicating where the click on
                the canvas took place in map coordinates of the canvas.
            * theButton - a Qt::MouseButton enumerator indicating
                which button was clicked with

        Returns:
            None
        Raises:
            None

        """
        # get the active layer
        myLayer = self.getActiveVectorLayer()

        # get style class list
        myStyles = self.getStyleClassList(myLayer)

        # identify click xy on canvas (map coords)
        myClickBox = self.getClickBbox(thePoint)
        # convert myClickBox to map coords
        #myExtent = self.pixelToCrsBox(myClickBox, self.canvas, myLayer)
        #settrace()
        # make a rubber band for visual confirmation of the click location
        myRubberBand = self.makeRubberBand(myClickBox)

        # use provider to select based on attr and bbox, and get first feature
        # from resulting list
        myFeature = self.getFirstFeature(myLayer, myClickBox)

        # find the symbol for said feature
        #mySymbol = self.getSymbolForFeature(myFeature)
        # clone class
        # set fill color for class
        # replace original with altered clone
        # refresh the canvas

    def getActiveVectorLayer(self):
        """Get the active vector layer.

        Args:
            None
        Returns:
            A valid QGIS vector layer
        Raises:
            IncorrectLayerTypeException if current layer is not a vector layer
            NoCurrentLayerException if no layer is selected.
        """
        # get active layer for canvas
        myLayer = self.iface.activeLayer()
        if myLayer is None:
            myMessage = ('There is no current layer. Load a vector layer and '
                         'select it before using it.')
            raise ex.NoCurrentLayerException(myMessage)
        # check that it's a vector
        if myLayer.type() == QgsMapLayer.VectorLayer:
            return myLayer
        else:
            myMessage = 'Current layer is not a vector layer.'
            raise ex.IncorrectLayerTypeException(myMessage)

    def getStyleClassList(self, theLayer):
        """
        Get the list of style classes in the given layer.

        Args:
            Object: the active layer.
        Returns:
            A list of styles from the given layer.
        Raises:
            UnknownSymbolTypeException if symbol type is unknown.
            OldSymbologyException if layer uses old symbology.
        """
        if not theLayer.isUsingRendererV2():
            myMessage = ('This plugin does not currently'
                         ' support old symbology.')
            raise ex.OldSymbologyException(myMessage)

        myRenderer = theLayer.rendererV2()
        myType = myRenderer.type()
        myStylesList = []
        if myType == 'singleSymbol':
            mySymbol = myRenderer.symbol()
            myStylesList.append(mySymbol)
        elif myType == 'categorizedSymbol':
            for myCategory in myRenderer.categories():
                mySymbol = myCategory.symbol().clone()
                myStylesList.append(mySymbol)
        elif myType == 'graduatedSymbol':
            for myRange in myRenderer.ranges():
                mySymbol = myRange.symbol().clone()
                myStylesList.append(mySymbol)
        else:
            myMessage = 'Unknown symbol type.'
            raise ex.UnknownSymbolTypeException(myMessage)
        return myStylesList

    def getClickBbox(self, thePoint):
        """
        Get a tiny bbox around a mouse click.

        Args:
            Point object.
        Returns:
            Tiny QgsRectangle bbox around point.
        Raises:
            CoordinateProcessingException if bbox creation encounters error.
        """

        # get the xy coords
        #QMessageBox.information(None, 'VF', str(thePoint))
        myX = thePoint.x()
        myY = thePoint.y()
        myUnitsPerPixel = self.canvas.mapUnitsPerPixel()

        # create a little bbox from clicked coords
        try:
            myBbox = QgsRectangle()
            myBbox.setXMinimum(myX - myUnitsPerPixel)
            myBbox.setYMinimum(myY - myUnitsPerPixel)
            myBbox.setXMaximum(myX + myUnitsPerPixel)
            myBbox.setYMaximum(myY + myUnitsPerPixel)
            #QMessageBox.information(None, 'VF', myBbox.toString())
            return myBbox
        except:
            msg = 'Click coordinates could not be processed.'
            raise ex.CoordinateProcessingException(msg)

    def pixelToCrsBox(self, theClickBox, theCanvas, theLayer):
        """
        Takes a bbox in pixel coords, converts it to a bbox in layer coords.

        Args:
            The bbox that needs to be converted.
            The current canvas.
            The current layer.
        Returns:
            The converted bbox.
        Raises:
            None
        """

        # converts from screen to map canvas crs
        myMapToPixel = theCanvas.getCoordinateTransform()
        myX1 = theClickBox.xMinimum()
        myY1 = theClickBox.yMinimum()
        myPoint1 = myMapToPixel.toMapCoordinates(myX1, myY1)

        myX2 = theClickBox.xMaximum()
        myY2 = theClickBox.yMaximum()
        myPoint2 = myMapToPixel.toMapCoordinates(myX2, myY2)

        myRectangle = QgsRectangle(myPoint1, myPoint2)

        myExtent = theCanvas.mapRenderer()\
            .mapToLayerCoordinates(theLayer, myRectangle)

        print "COMPUTED EXTENT: %s, %s, %s, %s" % (
            myExtent.xMinimum(), myExtent.yMinimum(), myExtent.xMaximum(),
            myExtent.yMaximum())
        return myExtent

    def makeRubberBand(self, theRectangle):
        """Makes a rubber band select on the canvas where the user clicked."""
        self.rubberband.reset(True)
        self.rubberband = QgsRubberBand(self.canvas, True)
        self.rubberband.setColor(QColor(255, 0, 0))
        self.rubberband.setWidth(10)
        self.rubberband.addPoint(QgsPoint(\
                                          theRectangle.xMinimum(),
                                          theRectangle.yMinimum()))
        self.rubberband.addPoint(QgsPoint(\
                                          theRectangle.xMaximum(),
                                          theRectangle.yMinimum()))
        self.rubberband.addPoint(QgsPoint(\
                                          theRectangle.xMaximum(),
                                          theRectangle.yMaximum()))
        self.rubberband.addPoint(QgsPoint(\
                                          theRectangle.xMinimum(),
                                          theRectangle.yMaximum()))

    def getFirstFeature(self, theLayer, theClickBox):
        """
        Gets the first feature within the bbox in the active layer.

        Args:
            The current layer.
            The converted bbox.
        Returns:
            A feature.
        Raises:
            LayerLoadException if data could not be loaded.
            NoSelectedFeatureException if no feature is selected.
        """

        myProvider = theLayer.dataProvider()
        if myProvider is None:
            msg = ('Could not obtain data provider from '
                   'layer "%s"' % theLayer.source())
            raise ex.LayerLoadException(msg)

        #myLayerExtent = theLayer.extent()
        myProvider.rewind()
        myAttributes = myProvider.attributeIndexes()
        myFetchGeometryFlag = False
        myUseIntersectFlag = False

        QMessageBox.information(None, 'Provider', str(myProvider))
        QMessageBox.information(None, 'Box', str(theClickBox))
        self.rubberband.reset(True)
        mySelection = myProvider.select(myAttributes, theClickBox,
                                        myFetchGeometryFlag,
                                        myUseIntersectFlag)
        mySelection = myProvider.select(myAttributes, theClickBox, False)

        #theLayer.select([])  # we don't actually need the attributes
        #theLayer.setSelectedFeatures([myF.id() for myF in theLayer])
        # select all the feature ids

        if mySelection == None:
            myFeatureCount = theLayer.featureCount()
            raise ex.NoSelectedFeatureException(
                "No feature selected. Using "
                "provider {%s}, "
                "attributes {%s}, and "
                "rectangle {%s} with "
                "extents {%s, %s, %s, %s}. "
                "Layer has %s features in total." % (
                    str(myProvider),
                    #str(myAttributes),
                    "attrs",
                    str(theClickBox),
                    theClickBox.xMinimum(),
                    theClickBox.yMinimum(),
                    theClickBox.xMaximum(),
                    theClickBox.yMaximum(),
                    str(myFeatureCount)))
        else:
            myFeature = myProvider.nextFeature(mySelection)
            return myFeature

    def getStyleForFeature(self, theFeature):
        """
        Gets the class of the feature passed to it.

        Args:
            A feature.
        Returns:
            A class.
        Raises:
            None.
        """
        pass
class QgepMapToolDigitizeDrainageChannel(QgsMapTool):
    '''
    This is used to digitize a drainage channel.

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

    Input:

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

    Output:

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

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

    geometryDigitized = pyqtSignal()

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

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

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

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

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

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

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

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

                self.geometryDigitized.emit()

            self.firstPoint = mousepos
Example #48
0
class SplineTool(QgsMapToolEdit):
    def __init__(self, iface):
        super(SplineTool, self).__init__(iface.mapCanvas())
        self.iface = iface
        self.canvas = self.iface.mapCanvas()

        self.rb = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry)
        self.snap_marker = QgsVertexMarker(self.canvas)
        self.snapping_utils = self.canvas.snappingUtils()

        self.points = []  # digitized, not yet interpolated points
        self.type = QgsWkbTypes.LineGeometry  # layer geometry type
        self.tolerance = None
        self.tightness = None
        self.is_polygon = None

        self.cursor = QCursor(
            QPixmap([
                "16 16 3 1",
                "      c None",
                ".     c #FF0000",
                "+     c #FFFFFF",
                "                ",
                "       +.+      ",
                "      ++.++     ",
                "     +.....+    ",
                "    +.     .+   ",
                "   +.   .   .+  ",
                "  +.    .    .+ ",
                " ++.    .    .++",
                " ... ...+... ...",
                " ++.    .    .++",
                "  +.    .    .+ ",
                "   +.   .   .+  ",
                "   ++.     .+   ",
                "    ++.....+    ",
                "      ++.++     ",
                "       +.+      ",
            ]))

        s = QgsSettings()
        self.snap_col = s.value("/qgis/digitizing/snap_color",
                                QColor("#ff00ff"))

    def canvasMoveEvent(self, event):
        color = QColor(255, 0, 0, 100)
        self.rb.setColor(color)
        self.rb.setWidth(1)
        point = self.toMapCoordinates(event.pos())

        # try to snap to a feature
        result = self.snapping_utils.snapToMap(point)
        if result.isValid():
            point = result.point()
            self.update_snap_marker(snapped_pt=point)
        else:
            self.update_snap_marker()

        points = list(self.points)
        points.append(QgsPoint(point))
        points = interpolate(points)
        self.set_rubber_band_points(points)

    def canvasReleaseEvent(self, event):
        color = QColor(255, 0, 0, 100)
        self.rb.setColor(color)
        self.rb.setWidth(1)
        point = self.toMapCoordinates(event.pos())

        if event.button() == Qt.LeftButton:
            # try to snap to a feature
            result = self.snapping_utils.snapToMap(point)
            if result.isValid():
                point = result.point()
            self.points.append(QgsPoint(point))
            points = interpolate(self.points)
            self.set_rubber_band_points(points)
        else:
            if len(self.points) >= 2:
                # refresh without last point
                self.refresh()
                self.create_feature()
            self.reset_points()
            self.reset_rubber_band()
            self.canvas.refresh()

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Escape:
            self.deactivate()
            self.activate()
        elif e.key() == Qt.Key_Backspace:
            if self.points:
                self.points.pop()
            points = interpolate(self.points)
            self.set_rubber_band_points(points)
            self.canvas.refresh()

    def reset_points(self):
        self.points = []

    # Create feature from digitized points, i.e. without the last moving point
    # where right click happened. This the same way how core QGIS Add Feature works.
    def create_feature(self):
        layer = self.iface.activeLayer()
        provider = layer.dataProvider()
        fields = provider.fields()
        f = QgsFeature(fields)
        coords = [QgsPointXY(pt) for pt in interpolate(self.points)]

        proj = QgsProject.instance()
        if layer.crs() != proj.crs():
            trans_context = proj.transformContext()
            transf = QgsCoordinateTransform(proj.crs(), layer.crs(),
                                            trans_context)
            coords_tmp = coords[:]
            coords = []
            for point in coords_tmp:
                transformed_pt = transf.transform(point)
                coords.append(transformed_pt)

        # Add geometry to feature
        if self.is_polygon:
            g = QgsGeometry.fromPolygonXY([coords])
        else:
            g = QgsGeometry.fromPolylineXY(coords)
        f.setGeometry(g)

        # Add attribute fields to feature
        for field in fields.toList():
            ix = fields.indexFromName(field.name())
            f[field.name()] = provider.defaultValue(ix)

        layer.beginEditCommand("Feature added")

        settings = QSettings()
        disable_attributes = settings.value(
            "/qgis/digitizing/disable_enter_attribute_values_dialog",
            False,
            type=bool)
        layer.addFeature(f)
        if disable_attributes:
            layer.endEditCommand()
        else:
            dlg = self.iface.getFeatureForm(layer, f)
            if dlg.exec_():
                layer.endEditCommand()
            else:
                layer.destroyEditCommand()

    def refresh(self):
        if self.points:
            points = interpolate(self.points)
            self.set_rubber_band_points(points)

    def canvasPressEvent(self, event):
        pass

    def showSettingsWarning(self):
        pass

    def activate(self):
        self.canvas.setCursor(self.cursor)
        layer = self.iface.activeLayer()
        self.type = layer.geometryType()
        self.is_polygon = False
        if self.type == QgsWkbTypes.PolygonGeometry:
            self.is_polygon = True

    def reset_rubber_band(self):
        self.rb.reset(self.type)

    def set_rubber_band_points(self, points):
        self.reset_rubber_band()
        for point in points:
            update = point is points[-1]
            if isinstance(point, QgsPoint):
                point = QgsPointXY(point)
            self.rb.addPoint(point, update)

    def update_snap_marker(self, snapped_pt=None):
        self.canvas.scene().removeItem(self.snap_marker)
        if snapped_pt is None:
            return
        self.snap_marker = QgsVertexMarker(self.canvas)
        self.snap_marker.setCenter(snapped_pt)
        self.snap_marker.setIconSize(16)
        self.snap_marker.setIconType(QgsVertexMarker.ICON_BOX)
        self.snap_marker.setPenWidth(3)
        self.snap_marker.setColor(self.snap_col)

    def deactivate(self):
        self.reset_points()
        self.update_snap_marker()
        self.reset_rubber_band()
        QgsMapToolEdit.deactivate(self)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True
class CaptureCoordinateTool(QgsMapTool):
    def __init__(self, canvas, txtXCoord, txtYCoord, annotation=None):
        self.canvas = canvas
        self.txtXCoord = txtXCoord
        self.txtYCoord = txtYCoord
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.annotation = annotation
        self.mSnapper = QgsMapCanvasSnapper(canvas)
        self.rubberBand = QgsRubberBand(canvas, QGis.Point)
        self.rubberBand.setColor(Qt.red)
        self.rubberBand.setWidth(10)
        self.rubberBandClick = QgsRubberBand(canvas, QGis.Point)
        self.rubberBandClick.setColor(Qt.green)
        self.rubberBandClick.setWidth(3)
        #         lblDoc = QTextDocument(label)
        #         self.annotation.setDocument(lblDoc)
        #         self.annotation.setFrameBackgroundColor(QColor(0,0,0,0))
        #         self.annotation.setFrameSize( QSizeF( 30, 20 ) )

        self.reset()

    def reset(self):
        self.Point = None
#     def canvasPressEvent(self, e):

    def canvasReleaseEvent(self, e):
        #         self.Point = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas)
        self.Point = self.snapPoint(e.pos())
        if self.annotation is not None:
            self.annotation.setMapPosition(self.Point)
            self.annotation.show()
        else:
            self.rubberBandClick.reset(QGis.Point)
            #         snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas, True)

            self.rubberBandClick.addPoint(self.Point)
            self.rubberBandClick.show()


#         self.setOffsetFromReferencePoint (QPointF(self.Point.x(),self.Point.y()))
        self.txtXCoord.setText(str(self.Point.x()))
        #         print str(self.Point.x())
        self.txtYCoord.setText(str(self.Point.y()))

    def canvasMoveEvent(self, e):
        if define._snapping == False:
            return
        self.rubberBand.reset(QGis.Point)
        #         snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas, True)
        snapPoint = self.snapPoint(e.pos(), True)
        if snapPoint == None:
            return
        self.rubberBand.addPoint(snapPoint)
        self.rubberBand.show()

    def snapPoint(self, p, bNone=False):
        if define._snapping == False:
            return define._canvas.getCoordinateTransform().toMapCoordinates(p)
        snappingResults = self.mSnapper.snapToBackgroundLayers(p)
        if (snappingResults[0] != 0 or len(snappingResults[1]) < 1):
            if bNone:
                return None
            else:
                return define._canvas.getCoordinateTransform(
                ).toMapCoordinates(p)
        else:
            return snappingResults[1][0].snappedVertex

    def deactivate(self):
        self.rubberBand.reset(QGis.Point)
        QgsMapTool.deactivate(self)
        self.emit(SIGNAL("deactivated()"))
Example #50
0
class ItemWidgetBase(QFrame):

    checkedStateChanged = pyqtSignal()
    thumbnailChanged = pyqtSignal()

    def __init__(self, item):
        QFrame.__init__(self)
        self.item = item
        self.is_updating_checkbox = False
        self.setMouseTracking(True)
        self.setStyleSheet("ItemWidgetBase{border: 2px solid transparent;}")

    def _setup_ui(self, text, thumbnailurl):

        self.lockLabel = QLabel()
        iconSize = QSize(16, 16)
        self.lockLabel.setPixmap(LOCK_ICON.pixmap(iconSize))
        self.checkBox = QCheckBox("")
        self.checkBox.stateChanged.connect(self.check_box_state_changed)
        self.nameLabel = QLabel(text)
        self.iconLabel = QLabel()
        self.labelZoomTo = QLabel()
        self.labelZoomTo.setPixmap(ZOOMTO_ICON.pixmap(QSize(18, 18)))
        self.labelZoomTo.setToolTip("Zoom to extent")
        self.labelZoomTo.mousePressEvent = self.zoom_to_extent
        self.labelAddPreview = QLabel()
        self.labelAddPreview.setPixmap(ADD_PREVIEW_ICON.pixmap(QSize(18, 18)))
        self.labelAddPreview.setToolTip("Add preview layer to map")
        self.labelAddPreview.mousePressEvent = self._add_preview_clicked

        layout = QHBoxLayout()
        layout.setMargin(0)
        layout.addWidget(self.checkBox)
        layout.addWidget(self.lockLabel)
        pixmap = QPixmap(PLACEHOLDER_THUMB, 'SVG')
        self.thumbnail = None
        thumb = pixmap.scaled(48, 48, Qt.KeepAspectRatio,
                              Qt.SmoothTransformation)
        self.iconLabel.setPixmap(thumb)
        self.iconLabel.setFixedSize(48, 48)
        layout.addWidget(self.iconLabel)
        if thumbnailurl is not None:
            download_thumbnail(thumbnailurl, self)
        layout.addWidget(self.nameLabel)
        layout.addStretch()
        layout.addWidget(self.labelZoomTo)
        layout.addWidget(self.labelAddPreview)
        layout.addSpacing(10)
        self.setLayout(layout)

        self.footprint = QgsRubberBand(iface.mapCanvas(),
                                       QgsWkbTypes.PolygonGeometry)
        self.footprint.setStrokeColor(PLANET_COLOR)
        self.footprint.setWidth(2)

    def set_thumbnail(self, img):
        self.thumbnail = QPixmap(img)
        thumb = self.thumbnail.scaled(48, 48, Qt.KeepAspectRatio,
                                      Qt.SmoothTransformation)
        self.iconLabel.setPixmap(thumb)
        self.thumbnailChanged.emit()

    def is_selected(self):
        return self.checkBox.isChecked()

    def _geom_bbox_in_project_crs(self):
        transform = QgsCoordinateTransform(
            QgsCoordinateReferenceSystem("EPSG:4326"),
            QgsProject.instance().crs(), QgsProject.instance())
        return transform.transformBoundingBox(self.geom.boundingBox())

    def _geom_in_project_crs(self):
        transform = QgsCoordinateTransform(
            QgsCoordinateReferenceSystem("EPSG:4326"),
            QgsProject.instance().crs(), QgsProject.instance())
        geom = QgsGeometry(self.geom)
        geom.transform(transform)
        return geom

    def show_footprint(self):
        self.footprint.setToGeometry(self._geom_in_project_crs())

    def hide_footprint(self):
        self.footprint.reset(QgsWkbTypes.PolygonGeometry)

    def enterEvent(self, event):
        self.setStyleSheet(
            "ItemWidgetBase{border: 2px solid rgb(0, 157, 165);}")
        self.show_footprint()

    def leaveEvent(self, event):
        self.setStyleSheet("ItemWidgetBase{border: 2px solid transparent;}")
        self.hide_footprint()

    def zoom_to_extent(self, evt):
        rect = QgsRectangle(self._geom_bbox_in_project_crs())
        rect.scale(1.05)
        iface.mapCanvas().setExtent(rect)
        iface.mapCanvas().refresh()

    def _add_preview_clicked(self, evt):
        self.add_preview()

    @waitcursor
    def add_preview(self):
        if is_segments_write_key_valid():
            item_ids = [
                f"{img['properties'][ITEM_TYPE]}:{img[ID]}"
                for img in self.item.images()
            ]
            analytics.track(PlanetClient.getInstance().user()["email"],
                            "Scene preview added to map", {"images": item_ids})
        create_preview_group(self.name(), self.item.images())

    def check_box_state_changed(self):
        self.checkedStateChanged.emit()
        self.is_updating_checkbox = True
        total = self.item.childCount()
        if self.checkBox.isTristate():
            self.checkBox.setTristate(False)
            self.checkBox.setChecked(False)
        else:
            for i in range(total):
                w = self.item.treeWidget().itemWidget(self.item.child(i), 0)
                w.set_checked(self.checkBox.isChecked())
        self.is_updating_checkbox = False

    def update_checkbox(self):
        if self.is_updating_checkbox:
            return
        selected = 0
        total = self.item.childCount()
        for i in range(total):
            w = self.item.treeWidget().itemWidget(self.item.child(i), 0)
            if w.is_selected():
                selected += 1
        self.checkBox.blockSignals(True)
        if selected == total:
            self.checkBox.setTristate(False)
            self.checkBox.setCheckState(Qt.Checked)
        elif selected == 0:
            self.checkBox.setTristate(False)
            self.checkBox.setCheckState(Qt.Unchecked)
        else:
            self.checkBox.setTristate(True)
            self.checkBox.setCheckState(Qt.PartiallyChecked)
        self.checkBox.blockSignals(False)
        self.checkedStateChanged.emit()

    def set_checked(self, checked):
        self.checkBox.setChecked(checked)

    def update_thumbnail(self):
        thumbnails = self.scene_thumbnails()
        if thumbnails and None not in thumbnails:
            bboxes = [img[GEOMETRY] for img in self.item.images()]
            pixmap = createCompoundThumbnail(bboxes, thumbnails)
            thumb = pixmap.scaled(48, 48, Qt.KeepAspectRatio,
                                  Qt.SmoothTransformation)
            self.iconLabel.setPixmap(thumb)
            self.thumbnailChanged.emit()

    def scene_thumbnails(self):
        thumbnails = []
        for i in range(self.item.childCount()):
            w = self.item.treeWidget().itemWidget(self.item.child(i), 0)
            thumbnails.extend(w.scene_thumbnails())
        return thumbnails
class CaptureCoordinateToolUpdate(QgsMapTool):
    def __init__(self, canvas, annotation=None):
        self.canvas = canvas
        #         self.tableView = tableView
        #         self.standardItemModel = standardItemModel
        #         self.txtXCoord = txtXCoord
        #         self.txtYCoord = txtYCoord
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.annotation = annotation
        self.mSnapper = QgsMapCanvasSnapper(canvas)
        self.rubberBand = QgsRubberBand(canvas, QGis.Point)
        self.rubberBand.setColor(Qt.red)
        self.rubberBand.setWidth(10)
        self.rubberBandClick = QgsRubberBand(canvas, QGis.Point)
        self.rubberBandClick.setColor(Qt.green)
        self.rubberBandClick.setWidth(3)
        self.obstaclesLayerList = QgisHelper.getSurfaceLayers(
            SurfaceTypes.Obstacles)
        self.demLayerList = QgisHelper.getSurfaceLayers(SurfaceTypes.DEM)
        #         lblDoc = QTextDocument(label)
        #         self.annotation.setDocument(lblDoc)
        #         self.annotation.setFrameBackgroundColor(QColor(0,0,0,0))
        #         self.annotation.setFrameSize( QSizeF( 30, 20 ) )

        self.reset()

    def reset(self):
        self.Point = None
#     def canvasPressEvent(self, e):

    def canvasReleaseEvent(self, e):
        pointBackground = e.pos()
        #         self.Point = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas)
        self.Point, self.pointID, self.layer = self.snapPoint(e.pos())
        self.selectedLayerFromSnapPoint = None
        resultValueList = []
        if self.annotation is not None:
            self.annotation.setMapPosition(self.Point)
            self.annotation.show()
        else:
            self.rubberBandClick.reset(QGis.Point)
            #         snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas, True)

            self.rubberBandClick.addPoint(self.Point)
            self.rubberBandClick.show()
        self.selectedLayerFromSnapPoint = define._canvas.currentLayer()
        # if self.obstaclesLayerList != None:
        #     for obstacleLayer in self.obstaclesLayerList:
        #         if self.layer == None:
        #             break
        #         if obstacleLayer.name() == self.layer.name():
        #             self.selectedLayerFromSnapPoint = self.layer
        #             break
        if self.selectedLayerFromSnapPoint != None and isinstance(
                self.selectedLayerFromSnapPoint,
                QgsVectorLayer) and self.pointID != None:
            # if self.pointID == None:
            #     resultValueList.append("Background")
            #
            #     resultValueList.append(str(self.Point.x()))
            #     resultValueList.append(str(self.Point.y()))
            #     resultValueList.append("0.0")
            # else:
            dataProvider = self.selectedLayerFromSnapPoint.dataProvider()
            featureIter = dataProvider.getFeatures(
                QgsFeatureRequest(self.pointID))
            feature = None
            for feature0 in featureIter:
                feature = feature0

            idx = self.selectedLayerFromSnapPoint.fieldNameIndex('Name')
            if not idx == -1:
                idValue = feature.attributes()[idx]
                resultValueList.append(idValue.toString())
            else:
                resultValueList.append("")
#             itemList.append(QStandardItem(idValue.toString()))

            resultValueList.append(str(self.Point.x()))
            resultValueList.append(str(self.Point.y()))

            idx = self.selectedLayerFromSnapPoint.fieldNameIndex('Altitude')
            if not idx == -1:
                altitudeValue = feature.attributes()[idx]
                resultValueList.append(altitudeValue.toString())
            else:
                resultValueList.append("0.0")

        else:

            if self.Point != None:
                identifyResult = None
                idValue = "Background"
                if self.demLayerList != None:

                    for demLayer in self.demLayerList:
                        identifyResults = demLayer.dataProvider().identify(
                            self.Point, QgsRaster.IdentifyFormatValue)
                        identifyResult = identifyResults.results()
                if identifyResult != None and identifyResult[1].toString(
                ) != "":
                    idValue = "DEM"

                resultValueList.append(idValue)
                resultValueList.append(str(self.Point.x()))
                resultValueList.append(str(self.Point.y()))
                if identifyResult != None and identifyResult[1].toString(
                ) != "":
                    resultValueList.append(identifyResult[1].toString())
                else:
                    resultValueList.append("0")
        self.emit(SIGNAL("resultPointValueList"), resultValueList)

    def canvasMoveEvent(self, e):
        if define._snapping == False:
            return
        self.rubberBand.reset(QGis.Point)
        #         snapPoint = QgisHelper.snapPoint(e.pos(), self.mSnapper, define._canvas, True)
        snapPoint, snapPointID, layer = self.snapPoint(e.pos(), True)
        if snapPoint == None:
            return
        self.rubberBand.addPoint(snapPoint)
        self.rubberBand.show()
#         print snapPointID

    def snapPoint(self, p, bNone=False):
        if define._snapping == False:
            return (
                define._canvas.getCoordinateTransform().toMapCoordinates(p),
                None, None)
        snappingResults = self.mSnapper.snapToCurrentLayer(
            p, QgsSnapper.SnapToVertex)
        if (snappingResults[0] != 0 or len(snappingResults[1]) < 1):

            if bNone:
                return (None, None, None)
            else:
                return (define._canvas.getCoordinateTransform().
                        toMapCoordinates(p), None, None)
        else:
            return (snappingResults[1][0].snappedVertex,
                    snappingResults[1][0].snappedAtGeometry,
                    snappingResults[1][0].layer)

    def deactivate(self):
        self.rubberBand.reset(QGis.Point)
        QgsMapTool.deactivate(self)
        self.emit(SIGNAL("deactivated()"))
Example #52
0
class AddPipeTool(QgsMapTool):
    def __init__(self, data_dock, params):
        QgsMapTool.__init__(self, data_dock.iface.mapCanvas())

        self.iface = data_dock.iface
        """:type : QgisInterface"""
        self.data_dock = data_dock
        """:type : DataDock"""
        self.params = params

        self.mouse_pt = None
        self.mouse_clicked = False
        self.first_click = False
        self.rubber_band = QgsRubberBand(self.canvas(), False)
        self.rubber_band.setColor(QColor(255, 128, 128))
        self.rubber_band.setWidth(1)
        self.rubber_band.setBrushStyle(Qt.Dense4Pattern)
        self.rubber_band.reset()

        self.snapper = None
        self.snapped_feat_id = None
        self.snapped_vertex = None
        self.snapped_vertex_nr = None
        self.vertex_marker = QgsVertexMarker(self.canvas())
        self.elev = None

        self.diameter_dialog = None

    def canvasPressEvent(self, event):
        if event.button() == Qt.RightButton:
            self.mouse_clicked = False

        if event.button() == Qt.LeftButton:
            self.mouse_clicked = True

    def canvasMoveEvent(self, event):

        self.mouse_pt = self.toMapCoordinates(event.pos())

        last_ix = self.rubber_band.numberOfVertices()

        self.rubber_band.movePoint(last_ix - 1,
                                   (self.snapped_vertex if self.snapped_vertex
                                    is not None else self.mouse_pt))

        elev = raster_utils.read_layer_val_from_coord(self.params.dem_rlay,
                                                      self.mouse_pt, 1)
        self.elev = elev
        if elev is not None:
            self.data_dock.lbl_elev_val.setText("{0:.2f}".format(self.elev))
        else:
            self.data_dock.lbl_elev_val.setText('-')

        # Mouse not clicked: snapping to closest vertex
        match = self.snapper.snapToMap(self.mouse_pt)

        if match.isValid():
            # Pipe starts from an existing vertex
            self.snapped_feat_id = match.featureId()
            self.snapped_vertex = match.point()
            self.snapped_vertex_nr = match.vertexIndex()

            self.vertex_marker.setCenter(self.snapped_vertex)
            self.vertex_marker.setColor(QColor(255, 0, 0))
            self.vertex_marker.setIconSize(10)
            self.vertex_marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
            self.vertex_marker.setPenWidth(3)
            self.vertex_marker.show()
        #
        else:

            # It's a new, isolated pipe
            self.snapped_vertex = None
            self.snapped_feat_id = None
            self.vertex_marker.hide()

    def canvasReleaseEvent(self, event):

        # if not self.mouse_clicked:
        #     return
        if event.button() == Qt.LeftButton:

            # Update rubber bands
            self.rubber_band.addPoint(
                (self.snapped_vertex
                 if self.snapped_vertex is not None else self.mouse_pt), True)
            if self.first_click:
                self.rubber_band.addPoint(
                    (self.snapped_vertex if self.snapped_vertex is not None
                     else self.mouse_pt), True)

            self.first_click = not self.first_click

        elif event.button() == Qt.RightButton:

            # try:

            pipe_band_geom = self.rubber_band.asGeometry()

            # No rubber band geometry and feature snapped: pop the context menu
            if pipe_band_geom is None and self.snapped_feat_id is not None:
                menu = QMenu()
                section_action = menu.addAction('Section...')  # TODO: softcode
                diameter_action = menu.addAction(
                    'Change diameter...')  # TODO: softcode
                action = menu.exec_(self.iface.mapCanvas().mapToGlobal(
                    QPoint(event.pos().x(),
                           event.pos().y())))

                pipe_ft = vector_utils.get_feats_by_id(self.params.pipes_vlay,
                                                       self.snapped_feat_id)[0]
                if action == section_action:
                    if self.params.dem_rlay is None:
                        self.iface.messageBar().pushMessage(
                            Parameters.plug_in_name,
                            'No DEM selected. Cannot edit section.',
                            QgsMessageBar.WARNING, 5)  # TODO: softcode
                    else:
                        # Check whether the pipe is all inside the DEM
                        pipe_pts = pipe_ft.geometry().asPolyline()

                        for pt in pipe_pts:
                            if not self.params.dem_rlay.extent().contains(pt):
                                self.iface.messageBar().pushMessage(
                                    Parameters.plug_in_name,
                                    'Some pipe vertices fall outside of the DEM. Cannot edit section.',
                                    QgsMessageBar.WARNING, 5)  # TODO: softcode
                                return

                        # Check whether the start/end nodes have an elevation value
                        (start_node_ft,
                         end_node_ft) = NetworkUtils.find_start_end_nodes(
                             self.params, pipe_ft.geometry())
                        start_node_elev = start_node_ft.attribute(
                            Junction.field_name_elev)
                        end_node_elev = end_node_ft.attribute(
                            Junction.field_name_elev)
                        if start_node_elev == NULL or end_node_elev == NULL:
                            self.iface.messageBar().pushMessage(
                                Parameters.plug_in_name,
                                'Missing elevation value in start or end node attributes. Cannot edit section.',
                                QgsMessageBar.WARNING, 5)  # TODO: softcode
                            return

                        pipe_dialog = PipeSectionDialog(
                            self.iface.mainWindow(), self.iface, self.params,
                            pipe_ft)
                        pipe_dialog.exec_()

                elif action == diameter_action:

                    old_diam = pipe_ft.attribute(Pipe.field_name_diameter)
                    self.diameter_dialog = DiameterDialog(
                        self.iface.mainWindow(), self.params, old_diam)
                    self.diameter_dialog.exec_()  # Exec creates modal dialog
                    new_diameter = self.diameter_dialog.get_diameter()
                    if new_diameter is None:
                        return

                    # Update pipe diameter
                    vector_utils.update_attribute(self.params.pipes_vlay,
                                                  pipe_ft,
                                                  Pipe.field_name_diameter,
                                                  new_diameter)

                    # Check if a valve is present
                    adj_valves = NetworkUtils.find_links_adjacent_to_link(
                        self.params, self.params.pipes_vlay, pipe_ft, True,
                        True, False)

                    if adj_valves['valves']:
                        self.iface.messageBar().pushMessage(
                            Parameters.plug_in_name,
                            'Valves detected on the pipe: need to update their diameters too.',
                            QgsMessageBar.WARNING, 5)  # TODO: softcode

                return

            # There's a rubber band: create new pipe
            if pipe_band_geom is not None:
                # Finalize line
                rubberband_pts = pipe_band_geom.asPolyline()[:-1]
                rubberband_pts = self.remove_duplicated_point(rubberband_pts)

                if len(rubberband_pts) < 2:
                    return

                # Check whether the pipe points are located on existing nodes
                junct_nrs = [0]
                for p in range(1, len(rubberband_pts) - 1):
                    overlapping_nodes = NetworkUtils.find_overlapping_nodes(
                        self.params, rubberband_pts[p])
                    if overlapping_nodes['junctions'] or overlapping_nodes[
                            'reservoirs'] or overlapping_nodes['tanks']:
                        junct_nrs.append(p)

                junct_nrs.append(len(rubberband_pts) - 1)

                new_pipes_nr = len(junct_nrs) - 1

                new_pipes_fts = []
                new_pipes_eids = []

                for np in range(new_pipes_nr):

                    pipe_eid = NetworkUtils.find_next_id(
                        self.params.pipes_vlay, Pipe.prefix)  # TODO: softcode
                    demand = float(self.data_dock.txt_pipe_demand.text())
                    diameter = float(self.data_dock.txt_pipe_diameter.text())
                    loss = float(self.data_dock.txt_pipe_loss.text())
                    roughness = float(
                        self.data_dock.lbl_pipe_roughness_val_val.text())
                    status = self.data_dock.cbo_pipe_status.currentText()
                    material = self.data_dock.cbo_pipe_roughness.currentText()
                    pipe_desc = self.data_dock.txt_pipe_desc.text()
                    pipe_tag = self.data_dock.cbo_pipe_tag.currentText()

                    pipe_ft = LinkHandler.create_new_pipe(
                        self.params, pipe_eid, diameter, loss, roughness,
                        status, material,
                        rubberband_pts[junct_nrs[np]:junct_nrs[np + 1] + 1],
                        True, pipe_desc, pipe_tag)
                    self.rubber_band.reset()

                    new_pipes_fts.append(pipe_ft)
                    new_pipes_eids.append(pipe_eid)

                emitter_coeff_s = self.data_dock.txt_junction_emit_coeff.text()
                if emitter_coeff_s is None or emitter_coeff_s == '':
                    emitter_coeff = float(0)
                else:
                    emitter_coeff = float(
                        self.data_dock.txt_junction_emit_coeff.text())

                # Description
                junction_desc = self.data_dock.txt_junction_desc.text()

                # Tag
                junction_tag = self.data_dock.cbo_junction_tag.currentText()

                # Create start and end node, if they don't exist
                (start_junction,
                 end_junction) = NetworkUtils.find_start_end_nodes(
                     self.params, new_pipes_fts[0].geometry())
                new_start_junction = None
                if not start_junction:
                    new_start_junction = rubberband_pts[0]
                    junction_eid = NetworkUtils.find_next_id(
                        self.params.junctions_vlay, Junction.prefix)
                    elev = raster_utils.read_layer_val_from_coord(
                        self.params.dem_rlay, new_start_junction, 1)
                    if elev is None:
                        elev = 0
                        # If elev is none, and the DEM is selected, it's better to inform the user
                        if self.params.dem_rlay is not None:
                            self.iface.messageBar().pushMessage(
                                Parameters.plug_in_name,
                                'Elevation value not available: element elevation set to 0.',
                                QgsMessageBar.WARNING, 5)  # TODO: softcode
                    deltaz = float(self.data_dock.txt_junction_deltaz.text())
                    j_demand = float(self.data_dock.txt_junction_demand.text())

                    pattern = self.data_dock.cbo_junction_pattern.itemData(
                        self.data_dock.cbo_junction_pattern.currentIndex())
                    if pattern is not None:
                        pattern_id = pattern.id
                    else:
                        pattern_id = None
                    NodeHandler.create_new_junction(
                        self.params, new_start_junction, junction_eid, elev,
                        j_demand, deltaz, pattern_id, emitter_coeff,
                        junction_desc, junction_tag)

                (start_junction,
                 end_junction) = NetworkUtils.find_start_end_nodes(
                     self.params,
                     new_pipes_fts[len(new_pipes_fts) - 1].geometry())
                new_end_junction = None
                if not end_junction:
                    new_end_junction = rubberband_pts[len(rubberband_pts) - 1]
                    junction_eid = NetworkUtils.find_next_id(
                        self.params.junctions_vlay, Junction.prefix)
                    elev = raster_utils.read_layer_val_from_coord(
                        self.params.dem_rlay, new_end_junction, 1)
                    if elev is None:
                        elev = 0
                        # If elev is none, and the DEM is selected, it's better to inform the user
                        if self.params.dem_rlay is not None:
                            self.iface.messageBar().pushMessage(
                                Parameters.plug_in_name,
                                'Elevation value not available: element elevation set to 0.',
                                QgsMessageBar.WARNING, 5)  # TODO: softcode
                    deltaz = float(self.data_dock.txt_junction_deltaz.text())

                    pattern = self.data_dock.cbo_junction_pattern.itemData(
                        self.data_dock.cbo_junction_pattern.currentIndex())
                    if pattern is not None:
                        pattern_id = pattern.id
                    else:
                        pattern_id = None
                    NodeHandler.create_new_junction(
                        self.params, new_end_junction, junction_eid, elev,
                        demand, deltaz, pattern_id, emitter_coeff,
                        junction_desc, junction_tag)

                # If end or start node intersects a pipe, split it
                if new_start_junction:
                    for pipe_ft in self.params.pipes_vlay.getFeatures():
                        if pipe_ft.attribute(Pipe.field_name_eid) != new_pipes_eids[0] and\
                                        pipe_ft.geometry().distance(QgsGeometry.fromPoint(new_start_junction)) < self.params.tolerance:
                            LinkHandler.split_pipe(self.params, pipe_ft,
                                                   new_start_junction)

                if new_end_junction:
                    for pipe_ft in self.params.pipes_vlay.getFeatures():
                        if pipe_ft.attribute(Pipe.field_name_eid) != new_pipes_eids[-1] and\
                                        pipe_ft.geometry().distance(QgsGeometry.fromPoint(new_end_junction)) < self.params.tolerance:
                            LinkHandler.split_pipe(self.params, pipe_ft,
                                                   new_end_junction)

        # except Exception as e:
        #     self.rubber_band.reset()
        #     self.iface.messageBar().pushWarning('Cannot add new pipe to ' + self.params.pipes_vlay.name() + ' layer', repr(e))
        #     traceback.print_exc(file=sys.stdout)

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.rubber_band.reset()

    def activate(self):

        self.update_snapper()

        # Editing
        if not self.params.junctions_vlay.isEditable():
            self.params.junctions_vlay.startEditing()
        if not self.params.pipes_vlay.isEditable():
            self.params.pipes_vlay.startEditing()

    def deactivate(self):

        QgsProject.instance().setSnapSettingsForLayer(
            self.params.junctions_vlay.id(), True, QgsSnapper.SnapToVertex,
            QgsTolerance.MapUnits, 0, True)

        QgsProject.instance().setSnapSettingsForLayer(
            self.params.reservoirs_vlay.id(), True, QgsSnapper.SnapToVertex,
            QgsTolerance.MapUnits, 0, True)
        QgsProject.instance().setSnapSettingsForLayer(
            self.params.tanks_vlay.id(), True, QgsSnapper.SnapToVertex,
            QgsTolerance.MapUnits, 0, True)
        QgsProject.instance().setSnapSettingsForLayer(
            self.params.pipes_vlay.id(), True, QgsSnapper.SnapToSegment,
            QgsTolerance.MapUnits, 0, True)

        # self.rubber_band.reset()
        self.data_dock.btn_add_pipe.setChecked(False)

        self.canvas().scene().removeItem(self.vertex_marker)

    def isZoomTool(self):
        return False

    def isTransient(self):
        return False

    def isEditTool(self):
        return True

    def reset_marker(self):
        self.outlet_marker.hide()
        self.canvas().scene().removeItem(self.outlet_marker)

    def remove_duplicated_point(self, pts):

        # This is needed because the rubber band sometimes returns duplicated points

        purged_pts = [pts[0]]
        for p in enumerate(range(len(pts) - 1), 1):
            if pts[p[0]] == pts[p[0] - 1]:
                continue
            else:
                purged_pts.append(pts[p[0]])

        return purged_pts

    def update_snapper(self):
        layers = {
            self.params.junctions_vlay: QgsPointLocator.Vertex,
            self.params.reservoirs_vlay: QgsPointLocator.Vertex,
            self.params.tanks_vlay: QgsPointLocator.Vertex,
            self.params.pipes_vlay: QgsPointLocator.All
        }

        self.snapper = NetworkUtils.set_up_snapper(layers,
                                                   self.iface.mapCanvas(),
                                                   self.params.snap_tolerance)

    # Needed by Observable
    def update(self, observable):
        self.update_snapper()
Example #53
0
class ProfiletoolMapTool(QgsMapTool):
    
    # Signals
    sig_clearMap = pyqtSignal()
    sig_createProfile = pyqtSignal()
    sig_changeCoord = pyqtSignal(QgsPointXY, str)


    def __init__(self, canvas, drawLineButton, showProfileButton): #buttonShowProf
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        
        self.cursor = QCursor(Qt.CrossCursor)

        # Red line
        self.rubberband = QgsRubberBand(self.canvas)
        self.rubberband.setWidth(3)
        self.rubberband.setColor(QColor(231, 28, 35))
    
        # Buttons from main dialog
        self.drawLineButton = drawLineButton
        self.buttonShowProf = showProfileButton

        # Coordinates of drawn line points
        self.pointsToDraw = []
        # Temporary save double clicks
        self.dblclktemp = None
        # Drawn line geometry
        self.drawnLine = None
        # Point markers on each end of the line
        self.markers = []
        
        # Backup the last active Tool before the pofile tool became active
        self.savedTool = self.canvas.mapTool()


    def drawLine(self):
        # Emit signal that clears map and deletes profile
        self.sig_clearMap.emit()
        self.reset()
        self.canvas.setMapTool(self)        # runs function self.activate()


    def activate(self):
        self.canvas.setCursor(self.cursor)


    def deactivate(self):
        self.canvas.setCursor(QCursor(Qt.OpenHandCursor))
        self.pointsToDraw = []
        # Stop pressing down button
        self.drawLineButton.setChecked(False)


    def reset(self):
        self.removeStueMarker()
        self.canvas.setMapTool(self.savedTool)
        self.rubberband.reset()
        self.pointsToDraw = []
        self.dblclktemp = None
        self.drawnLine = None
        
        
    def canvasMoveEvent(self, event):
        if len(self.pointsToDraw) > 0:
            self.rubberband.reset()
            line = [self.pointsToDraw[0], event.mapPoint()]
            self.rubberband.setToGeometry(QgsGeometry.fromPolylineXY(line), None)
 

    def canvasReleaseEvent(self, event):
        mapPos = event.mapPoint()
        if mapPos == self.dblclktemp:
            self.dblclktemp = None
            return
        else:
            # Mark point with marker symbol
            self.drawStueMarker(mapPos)
            
            # Klick ist first point of line
            if len(self.pointsToDraw) == 0:
                self.rubberband.reset()
                self.pointsToDraw.append(mapPos)
                return
            
            # Klick is second point of line
            elif len(self.pointsToDraw) == 1:
                self.pointsToDraw.append(mapPos)
                self.removeStueMarker()
                self.dblclktemp = mapPos
                self.drawnLine = self.createDigiFeature(self.pointsToDraw)
                self.sig_changeCoord.emit(self.pointsToDraw[0], 'A')
                self.sig_changeCoord.emit(self.pointsToDraw[1], 'E')
                self.canvas.setMapTool(self.savedTool)      # self.deactivate()


    def setCursor(self, cursor):
        self.cursor = cursor


    def updateLine(self, points):
        self.rubberband.setToGeometry(QgsGeometry.fromPolylineXY(points), None)
        self.drawnLine = self.createDigiFeature(points)
        self.drawStueMarker(points[0])
        self.drawStueMarker(points[1])


    def drawStueMarker(self, point):
        marker = QgsStueMarker(self.canvas)
        marker.setCenter(point)
        self.markers.append(marker)
        self.canvas.refresh()


    def removeStueMarker(self, position=-1):
        if position >= 0:
            marker = self.markers[position]
            self.canvas.scene().removeItem(marker)
            self.markers.pop(position)
        else:
            for marker in self.markers:
                self.canvas.scene().removeItem(marker)
            self.markers = []
        self.canvas.refresh()


    @staticmethod
    def createDigiFeature(pnts):
        line = QgsGeometry.fromPolylineXY(pnts)
        qgFeat = QgsFeature()
        qgFeat.setGeometry(line)
        return qgFeat
class TaskingDockWidget(BASE, WIDGET):
    def __init__(
        self,
        parent=None,
    ):
        super().__init__(parent=parent)

        self.setupUi(self)

        self.rect = None
        self.prev_map_tool = None

        self.btnMapTool.setIcon(TASKING_ICON)
        self.btnMapTool.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)

        self.footprint = QgsRubberBand(iface.mapCanvas(),
                                       QgsWkbTypes.PolygonGeometry)
        self.footprint.setStrokeColor(PLANET_COLOR)
        self.footprint.setFillColor(QColor(204, 235, 239, 100))
        self.footprint.setWidth(2)
        self.marker = QgsRubberBand(iface.mapCanvas(),
                                    QgsWkbTypes.PointGeometry)
        self.marker.setIcon(QgsRubberBand.ICON_SVG)
        self.marker.setSvgIcon(SVG_ICON, QPoint(-15, -30))

        self.map_tool = AOICaptureMapTool(iface.mapCanvas())
        self.map_tool.aoi_captured.connect(self.aoi_captured)
        self.btnMapTool.toggled.connect(self._set_map_tool)
        iface.mapCanvas().mapToolSet.connect(self._map_tool_set)

        self.textBrowserPoint.setHtml("No point selected")
        self.btnOpenDashboard.setEnabled(False)

        self.btnOpenDashboard.clicked.connect(self._open_tasking_dashboard)
        self.btnCancel.clicked.connect(self.cancel_clicked)

        self.visibilityChanged.connect(self.visibility_changed)

        self.textBrowserPoint.viewport().setAutoFillBackground(False)

    def aoi_captured(self, rect, pt):
        self.pt = pt
        self.rect = rect
        self.footprint.setToGeometry(QgsGeometry.fromRect(rect))
        transform = QgsCoordinateTransform(
            QgsCoordinateReferenceSystem("EPSG:4326"),
            QgsProject.instance().crs(),
            QgsProject.instance(),
        )
        transformed = transform.transform(pt)
        self.marker.setToGeometry(QgsGeometry.fromPointXY(transformed))
        self._set_map_tool(False)
        text = f"""
                <p><b>Selected Point Coordinates</b></p>
                <p align="center">Latitude : {pt.x():.4f}</p>
                <p align="center">Longitude : {pt.y():.4f}</p>
                """
        self.textBrowserPoint.setHtml(text)
        self.btnCancel.setEnabled(True)
        self.btnOpenDashboard.setEnabled(True)

    def cancel_clicked(self):
        self.footprint.reset(QgsWkbTypes.PolygonGeometry)
        self.marker.reset(QgsWkbTypes.PointGeometry)
        self.btnOpenDashboard.setEnabled(False)
        self.textBrowserPoint.setHtml("")
        self.btnCancel.setEnabled(False)
        self._set_map_tool(False)

    def _set_map_tool(self, checked):
        if checked:
            self.prev_map_tool = iface.mapCanvas().mapTool()
            iface.mapCanvas().setMapTool(self.map_tool)
        else:
            if self.prev_map_tool is not None:
                iface.mapCanvas().setMapTool(self.prev_map_tool)

    def _map_tool_set(self, new, old):
        if new != self.map_tool:
            self.btnMapTool.blockSignals(True)
            self.btnMapTool.setChecked(False)
            self.btnMapTool.blockSignals(False)

    def visibility_changed(self, visible):
        if not visible:
            self.cancel_clicked()

    def _open_tasking_dashboard(self):
        dialog = WarningDialog(self.pt)
        dialog.exec()
Example #55
0
class GeorefRasterBy2PointsMapTool(QgsMapToolEmitPoint):
    def __init__(self, iface):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rasterShadow = RasterShadowMapCanvasItem(self.canvas)

        self.firstPoint = None

        self.rubberBandOrigin = QgsRubberBand(self.canvas,
                                              QgsWkbTypes.PointGeometry)
        self.rubberBandOrigin.setColor(Qt.red)
        self.rubberBandOrigin.setIcon(QgsRubberBand.ICON_CIRCLE)
        self.rubberBandOrigin.setIconSize(7)
        self.rubberBandOrigin.setWidth(2)

        self.rubberBandDisplacement = QgsRubberBand(self.canvas,
                                                    QgsWkbTypes.LineGeometry)
        self.rubberBandDisplacement.setColor(Qt.red)
        self.rubberBandDisplacement.setWidth(1)

        self.rubberBandExtent = QgsRubberBand(self.canvas,
                                              QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.setColor(Qt.red)
        self.rubberBandExtent.setWidth(2)

        self.isLayerVisible = True

        self.reset()

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

    def reset(self):
        self.startPoint = self.endPoint = self.firstPoint = None
        self.isEmittingPoint = False
        self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry)
        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()
        self.layer = None

    def deactivate(self):
        QgsMapToolEmitPoint.deactivate(self)
        self.reset()

    def canvasPressEvent(self, e):
        if self.firstPoint is None:
            self.startPoint = self.toMapCoordinates(e.pos())
            self.endPoint = self.startPoint
            self.isEmittingPoint = True
            self.originalCenter = self.layer.center
            # this tool do the displacement itself TODO update so it is done by
            # transformed coordinates + new center)
            self.originalCornerPoints = \
                self.layer.transformedCornerCoordinates(
                    *self.layer.transformParameters())

            self.isLayerVisible = isLayerVisible(self.iface, self.layer)
            setLayerVisible(self.iface, self.layer, False)

            self.showDisplacement(self.startPoint, self.endPoint)
            self.layer.history.append({
                "action": "2pointsA",
                "center": self.layer.center
            })
        else:
            self.startPoint = self.toMapCoordinates(e.pos())
            self.endPoint = self.startPoint

            self.startY = e.pos().y()
            self.endY = self.startY
            self.isEmittingPoint = True
            self.height = self.canvas.height()

            self.isLayerVisible = isLayerVisible(self.iface, self.layer)
            setLayerVisible(self.iface, self.layer, False)

            rotation = self.computeRotation()
            xScale = yScale = self.computeScale()
            self.showRotationScale(rotation, xScale, yScale)
            self.layer.history.append({
                "action": "2pointsB",
                "center": self.layer.center,
                "xScale": self.layer.xScale,
                "yScale": self.layer.yScale,
                "rotation": self.layer.rotation
            })

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False

        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        self.rasterShadow.reset()

        if self.firstPoint is None:
            x = (self.originalCenter.x() + self.endPoint.x() -
                 self.startPoint.x())
            y = (self.originalCenter.y() + self.endPoint.y() -
                 self.startPoint.y())
            self.layer.setCenter(QgsPointXY(x, y))
            self.firstPoint = self.endPoint

            setLayerVisible(self.iface, self.layer, self.isLayerVisible)
            self.layer.repaint()

            self.layer.commitTransformParameters()
        else:
            rotation = self.computeRotation()
            xScale = yScale = self.computeScale()
            self.layer.moveCenterFromPointRotate(self.firstPoint, rotation,
                                                 xScale, yScale)
            self.layer.setRotation(self.layer.rotation + rotation)
            self.layer.setScale(self.layer.xScale * xScale,
                                self.layer.yScale * yScale)

            setLayerVisible(self.iface, self.layer, self.isLayerVisible)
            self.layer.repaint()

            self.layer.commitTransformParameters()

            self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
            self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
            self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry)
            self.rasterShadow.reset()

            self.firstPoint = None
            self.startPoint = self.endPoint = None

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

        self.endPoint = self.toMapCoordinates(e.pos())

        if self.firstPoint is None:
            self.showDisplacement(self.startPoint, self.endPoint)
        else:
            self.endY = e.pos().y()
            rotation = self.computeRotation()
            xScale = yScale = self.computeScale()
            self.showRotationScale(rotation, xScale, yScale)

    def computeRotation(self):
        # The angle is the difference between angle
        # horizontal/endPoint-firstPoint and horizontal/startPoint-firstPoint.
        dX0 = self.startPoint.x() - self.firstPoint.x()
        dY0 = self.startPoint.y() - self.firstPoint.y()
        dX = self.endPoint.x() - self.firstPoint.x()
        dY = self.endPoint.y() - self.firstPoint.y()
        return math.degrees(math.atan2(-dY, dX) - math.atan2(-dY0, dX0))

    def computeScale(self):
        # The scale is the ratio between endPoint-firstPoint and
        # startPoint-firstPoint.
        dX0 = self.startPoint.x() - self.firstPoint.x()
        dY0 = self.startPoint.y() - self.firstPoint.y()
        dX = self.endPoint.x() - self.firstPoint.x()
        dY = self.endPoint.y() - self.firstPoint.y()
        return math.sqrt((dX * dX + dY * dY) / (dX0 * dX0 + dY0 * dY0))

    def showRotationScale(self, rotation, xScale, yScale):
        center, _, _, _ = self.layer.transformParameters()
        # newRotation = rotation + originalRotation
        cornerPoints = self.layer.transformedCornerCoordinatesFromPoint(
            self.firstPoint, rotation, xScale, yScale)

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        for point in cornerPoints:
            self.rubberBandExtent.addPoint(point, False)
        self.rubberBandExtent.addPoint(cornerPoints[0], True)
        self.rubberBandExtent.show()

        # Calculate the displacement of the center due to the rotation from
        # another point.
        newCenterDX = (cornerPoints[0].x() +
                       cornerPoints[2].x()) / 2 - center.x()
        newCenterDY = (cornerPoints[0].y() +
                       cornerPoints[2].y()) / 2 - center.y()
        self.rasterShadow.reset(self.layer)
        self.rasterShadow.setDeltaDisplacement(newCenterDX, newCenterDY, False)
        self.rasterShadow.setDeltaScale(xScale, yScale, False)
        self.rasterShadow.setDeltaRotation(rotation, True)
        self.rasterShadow.show()

        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        point0 = QgsPointXY(self.startPoint.x(), self.startPoint.y())
        point1 = QgsPointXY(self.firstPoint.x(), self.firstPoint.y())
        point2 = QgsPointXY(self.endPoint.x(), self.endPoint.y())
        self.rubberBandDisplacement.addPoint(point0, False)
        self.rubberBandDisplacement.addPoint(point1, False)
        self.rubberBandDisplacement.addPoint(point2,
                                             True)  # true to update canvas
        self.rubberBandDisplacement.show()

    def showDisplacement(self, startPoint, endPoint):
        self.rubberBandOrigin.reset(QgsWkbTypes.PointGeometry)
        self.rubberBandOrigin.addPoint(endPoint, True)
        self.rubberBandOrigin.show()

        self.rubberBandDisplacement.reset(QgsWkbTypes.LineGeometry)
        point1 = QgsPointXY(startPoint.x(), startPoint.y())
        point2 = QgsPointXY(endPoint.x(), endPoint.y())
        self.rubberBandDisplacement.addPoint(point1, False)
        self.rubberBandDisplacement.addPoint(point2,
                                             True)  # true to update canvas
        self.rubberBandDisplacement.show()

        self.rubberBandExtent.reset(QgsWkbTypes.LineGeometry)
        for point in self.originalCornerPoints:
            self._addDisplacementToPoint(self.rubberBandExtent, point, False)
        # for closing
        self._addDisplacementToPoint(self.rubberBandExtent,
                                     self.originalCornerPoints[0], True)
        self.rubberBandExtent.show()

        self.rasterShadow.reset(self.layer)
        self.rasterShadow.setDeltaDisplacement(
            self.endPoint.x() - self.startPoint.x(),
            self.endPoint.y() - self.startPoint.y(), True)
        self.rasterShadow.show()

    def _addDisplacementToPoint(self, rubberBand, point, doUpdate):
        x = point.x() + self.endPoint.x() - self.startPoint.x()
        y = point.y() + self.endPoint.y() - self.startPoint.y()
        self.rubberBandExtent.addPoint(QgsPointXY(x, y), doUpdate)
Example #56
0
class RectangleMapTool(QgsMapToolEmitPoint):

    boxCreated = pyqtSignal(QgsRectangle)

    def __init__(self, canvas):
        self.canvas = canvas
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.rubberBand = QgsRubberBand(self.canvas,
                                        QgsWkbTypes().GeometryType(2))
        self.rubberBand.setColor(Qt.red)
        self.rubberBand.setBrushStyle(Qt.Dense6Pattern)
        self.rubberBand.setWidth(1)
        self.reset()

    def reset(self):
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBand.reset(QgsWkbTypes().GeometryType(2))

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

    def canvasReleaseEvent(self, e):
        self.isEmittingPoint = False
        r = self.rectangle()
        if r is not None:
            self.boxCreated.emit(r)

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

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

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

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

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

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

        srsCrs = self.canvas.mapSettings().destinationCrs()
        dstCrs = QgsCoordinateReferenceSystem(
            4326, QgsCoordinateReferenceSystem.EpsgCrsId)
        coordinateTransformer = QgsCoordinateTransform(srsCrs, dstCrs,
                                                       QgsProject.instance())
        rect = coordinateTransformer.transform(
            QgsRectangle(self.startPoint, self.endPoint))

        return rect
class RectangleMapTool(QgsMapToolEmitPoint):
    """
    Map tool that lets the user define the analysis extents.
    """
    rectangle_created = pyqtSignal()
    deactivated = pyqtSignal()

    def __init__(self, canvas):
        """Constructor for the map tool.

        :param canvas: Canvas that tool will interact with.
        :type canvas: QgsMapCanvas
        """
        self.canvas = canvas
        self.start_point = None
        self.end_point = None
        self.is_emitting_point = False

        QgsMapToolEmitPoint.__init__(self, self.canvas)

        self.rubber_band = QgsRubberBand(self.canvas, geometryType=QGis.Line)
        self.rubber_band.setColor(QColor(0, 0, 240, 100))
        # Needs QGIS 2.6
        # self.rubber_band.setFillColor(QColor(0, 0, 240, 0))
        self.rubber_band.setWidth(1)

        self.reset()

    def reset(self):
        """
        Clear the rubber band for the analysis extents.
        """
        self.start_point = self.end_point = None
        self.is_emitting_point = False
        self.rubber_band.reset(QGis.Polygon)

    def canvasPressEvent(self, e):
        """
        Handle canvas press events so we know when user is capturing the rect.

        :param e: A Qt event object.
        :type: QEvent
        """
        self.start_point = self.toMapCoordinates(e.pos())
        self.end_point = self.start_point
        self.is_emitting_point = True

        self.show_rectangle(self.start_point, self.end_point)

    def canvasReleaseEvent(self, e):
        """
        Handle canvas release events  has finished capturing e

        :param e: A Qt event object.
        :type: QEvent
        """
        _ = e
        self.is_emitting_point = False
        self.rectangle_created.emit()

    def canvasMoveEvent(self, e):
        """

        :param e:
        :return:
        """
        if not self.is_emitting_point:
            return

        self.end_point = self.toMapCoordinates(e.pos())
        self.show_rectangle(self.start_point, self.end_point)

    def show_rectangle(self, start_point, end_point):
        """
        Show the rectangle on the canvas.

        :param start_point: QGIS Point object representing the origin (
            top left).
        :type start_point: QgsPoint

        :param end_point: QGIS Point object representing the contra-origin (
            bottom right).
        :type end_point: QgsPoint

        :return:
        """
        self.rubber_band.reset(QGis.Polygon)
        if (start_point.x() == end_point.x() or
                start_point.y() == end_point.y()):
            return

        point1 = start_point
        point2 = QgsPoint(end_point.x(), start_point.y())
        point3 = end_point
        point4 = QgsPoint(start_point.x(), end_point.y())

        update_canvas = False
        self.rubber_band.addPoint(point1, update_canvas)
        self.rubber_band.addPoint(point2, update_canvas)
        self.rubber_band.addPoint(point3, update_canvas)
        self.rubber_band.addPoint(point4, update_canvas)
        # noinspection PyArgumentEqualDefault
        # no False so canvas will update
        # close the polygon otherwise it shows as a filled rect
        self.rubber_band.addPoint(point1)
        self.rubber_band.show()

    def rectangle(self):
        """
        Accessor for the rectangle.

        :return: A rectangle showing the designed extent.
        :rtype: QgsRectangle
        """
        if self.start_point is None or self.end_point is None:
            return None
        elif self.start_point.x() == self.end_point.x() or \
                self.start_point.y() == self.end_point.y():
            return None

        return QgsRectangle(self.start_point, self.end_point)

    def set_rectangle(self, rectangle):
        """
        Set the rectangle for the selection.
        :param rectangle:
        :return:
        """
        if rectangle == self.rectangle():
            return False

        if rectangle is None:
            self.reset()
        else:
            self.start_point = QgsPoint(
                rectangle.xMinimum(), rectangle.yMinimum())
            self.end_point = QgsPoint(
                rectangle.xMaximum(), rectangle.yMaximum())
            self.show_rectangle(self.start_point, self.end_point)
        return True

    def deactivate(self):
        """
        Disable the tool.
        """
        QgsMapTool.deactivate(self)
        self.deactivated.emit()
Example #58
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 SetHandDraw(self, value):
        ''' Set Hand Draw '''
        self._interaction.HandDraw = value

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.painter.end()
        return

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

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

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

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

        # Cursor Coordinates
        if self.gt is not None:

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

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

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

            self.parent.lb_cursor_coord.setText(txt)

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

        if not event.buttons():
            return

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                AddDrawLineOnMap(self.drawLines)

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

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

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

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

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

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

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

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

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

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

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

    def leaveEvent(self, _):
        self.parent.lb_cursor_coord.setText("")
        self.setCursor(QCursor(Qt.ArrowCursor))
class 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 BaseTool(QgsMapToolEmitPoint):

    __metaclass__ = ABCMeta

    apply = pyqtSignal(dict)

    def _apply(self):
        self.collect_data() if not self._data else None
        self._data[k.geometry] = {
            k.line: self.line_band.asGeometry(),
            k.polygon: self.poly_band.asGeometry()
        }
        self.apply.emit(self._data)
        self.reset()

    def __init__(self, canvas):
        self.canvas = canvas
        QgsMapToolEmitPoint.__init__(self, self.canvas)
        self.replaced_tool = canvas.mapTool()
        self.points = []
        self.done = True
        self._line_band = None
        self._poly_band = None
        self._markers = []
        self._info = None
        self._line_color = Qt.black
        self._poly_color = Qt.lightGray
        self._data = {}

    @property
    def n_points(self):
        return len(self.points)

    @property
    def has_points(self):
        return self.n_points > 1

    @property
    def info(self):
        if not self._info:
            self._info = QLabel(parent=self.canvas)
            font = self._info.font()
            font.setPointSize(10)
            font.setFamily('Courier New')
            self._info.setFont(font)
            self._info.setStyleSheet('color: black')
        return self._info

    @property
    def line_band(self):
        if self._line_band is None:
            self._line_band = QgsRubberBand(self.canvas)
            self._line_band.setColor(self._line_color)
            self._line_band.setOpacity(1)
            self._line_band.setWidth(1)
            self._line_band.reset(QgsWkbTypes.LineGeometry)
        return self._line_band

    @property
    def poly_band(self):
        if self._poly_band is None:
            self._poly_band = QgsRubberBand(self.canvas)
            self._poly_band.setColor(self._poly_color)
            self._poly_band.setOpacity(0.1)
            self._poly_band.setWidth(0.1)
            self._poly_band.reset(QgsWkbTypes.PolygonGeometry)
        return self._poly_band

    @property
    def markers(self):
        if not self._markers:
            line_points = self.line_points
            line_points = line_points if line_points else self.points
            for point in line_points:
                index = line_points.index(point)
                is_extreme_point = index == 0 or index == len(line_points) - 1
                marker = QgsVertexMarker(self.canvas)
                marker.setColor(self._line_color)
                marker.setFillColor(
                    self._poly_color if not is_extreme_point else Qt.red)
                marker.setOpacity(1)
                marker.setPenWidth(1)
                marker.setIconSize(5)
                marker.setIconType(QgsVertexMarker.ICON_CIRCLE)
                marker.setCenter(point)
                self._markers.append(marker)
        return self._markers

    @property
    @abstractmethod
    def line_points(self):
        """точки для отрисовки линии"""

    @property
    @abstractmethod
    def poly_points(self):
        """точки для отрисовки фона"""

    def draw(self):
        if not self.has_points:
            return

        self.reset()

        line_points = self.line_points
        for point in line_points:
            is_last_point = line_points.index(point) == len(line_points) - 1
            self.line_band.addPoint(point, doUpdate=is_last_point)

        poly_points = self.poly_points
        for point in poly_points:
            is_last_point = poly_points.index(point) == len(poly_points) - 1
            self.poly_band.addPoint(point, doUpdate=is_last_point)

        self.show()

    @abstractmethod
    def collect_data(self):
        """сбор данных для отправки клиенту"""

    @abstractmethod
    def collect_info(self):
        """ подготовка данных к отображению рядом с курсором мыши"""

    def show_info(self):
        self.info.hide()
        self.info.setText(self.collect_info())
        tl = self.canvas.mapToGlobal(self.canvas.rect().topLeft())
        self.info.move(QCursor.pos().x() + 15 - tl.x(),
                       QCursor.pos().y() - tl.y())
        self.info.show()

    def reset(self):
        for marker in self.markers:
            marker.hide()
        self.markers.clear()
        self.line_band.reset(QgsWkbTypes.LineGeometry)
        self.poly_band.reset(QgsWkbTypes.PolygonGeometry)

    def show(self):
        for marker in self.markers:
            marker.show()
        self.line_band.show()
        self.poly_band.show()
        self.show_info()

    def set_done(self, clear):
        if clear:
            self.reset()
        else:
            self._apply()
        self.done = True
        self.points = []
        self.canvas.setMapTool(self.replaced_tool)
        self.canvas.refresh()
        self.info.hide()
        self._info = None

    def canvasPressEvent(self, e):
        if e.button() == Qt.RightButton:
            self.set_done(clear=True)
        if e.button() == Qt.LeftButton:
            self.done = False

    def canvasReleaseEvent(self, e):
        if self.done or e.button() != Qt.LeftButton:
            return
        p = self.toMapCoordinates(e.pos())
        self.points.append(p)
        self.done = False
        self.draw()

    def canvasMoveEvent(self, e):
        if self.done:
            return
        p = self.toMapCoordinates(e.pos())
        self.points.pop() if self.has_points else None
        self.points.append(p)
        self.done = False
        self.draw()

    def canvasDoubleClickEvent(self, e):
        if not self.done:
            self.set_done(clear=False)

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Escape:
            self.set_done(clear=True)
        if e.key() in (Qt.Key_Return, Qt.Key_Enter):
            self.set_done(clear=False)

    def deactivate(self):
        if not self.done:
            self.set_done(clear=True)
        super(BaseTool, self).deactivate()