Exemple #1
0
class AssignBandValueTool(QgsMapTool):
    def __init__(self, iface, rasterLayer):
        """
        Tool Behaviours: (all behaviours start edition, except for rectangle one)
        1- Left Click: Creates a new point feature with the value from raster, according to selected attribute. 
        5- Shift + drag and drop: draws a rectangle, then features that intersect this rectangle are selected 
        and their value is set according to raster value and selected attribute.
        """
        self.iface = iface        
        self.canvas = self.iface.mapCanvas()
        QgsMapTool.__init__(self, self.canvas)
        self.toolAction = None
        self.qgsMapToolEmitPoint = QgsMapToolEmitPoint(self.canvas)
        self.dsgGeometryHandler = DsgGeometryHandler(iface)
        self.rasterLayer = rasterLayer
        self.setRubberbandParameters()
        self.reset()
        self.auxList = []
        self.decimals = self.getDecimals()

    def getDecimals(self):
        settings = QSettings()
        settings.beginGroup('PythonPlugins/DsgTools/Options')
        decimals = settings.value('decimals')
        if decimals:
            return int(decimals)
        else:
            return 0
    
    def getSuppressOptions(self):
        qgisSettings = QSettings()
        qgisSettings.beginGroup('Qgis/digitizing')
        setting = qgisSettings.value('disable_enter_attribute_values_dialog')
        qgisSettings.endGroup()
        if not setting:
            return False
        if setting.lower() == u'false':
            return False
        else:
            return True

    def setRubberbandParameters(self):
        self.rubberBand = QgsRubberBand(self.canvas, QGis.Polygon)
        self.hoverRubberBand = QgsRubberBand(self.canvas, QGis.Polygon)
        mFillColor = QColor( 254, 178, 76, 63 )
        self.rubberBand.setColor(mFillColor)
        self.hoverRubberBand.setColor(QColor( 255, 0, 0, 90 ))
        self.rubberBand.setWidth(1)
    
    def reset(self):
        """
        Resets rubber band.
        """
        self.startPoint = self.endPoint = None
        self.isEmittingPoint = False
        self.rubberBand.reset(QGis.Polygon)

    def canvasPressEvent(self, e):
        """
        Method used to build rectangle if shift is held, otherwise, feature select/deselect and identify is done.
        :param e: (QgsMouseEvent) mouse event.
        """
        if e.button() == QtCore.Qt.LeftButton:
            self.auxList = []
            if QtGui.QApplication.keyboardModifiers() == QtCore.Qt.ShiftModifier:
                self.isEmittingPoint = True
                self.startPoint = self.toMapCoordinates(e.pos())
                self.endPoint = self.startPoint
                self.isEmittingPoint = True
                self.showRect(self.startPoint, self.endPoint)

    def canvasMoveEvent(self, e):
        """
        Used only on rectangle select.
        """
        if not self.isEmittingPoint:
            return
        self.endPoint = self.toMapCoordinates( e.pos() )
        self.showRect(self.startPoint, self.endPoint)        

    def showRect(self, startPoint, endPoint):
        """
        Builds rubberband rect.
        """
        self.rubberBand.reset(QGis.Polygon)
        if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
            return
        point1 = QgsPoint(startPoint.x(), startPoint.y())
        point2 = QgsPoint(startPoint.x(), endPoint.y())
        point3 = QgsPoint(endPoint.x(), endPoint.y())
        point4 = QgsPoint(endPoint.x(), startPoint.y())
    
        self.rubberBand.addPoint(point1, False)
        self.rubberBand.addPoint(point2, False)
        self.rubberBand.addPoint(point3, False)
        self.rubberBand.addPoint(point4, True)    # true to update canvas
        self.rubberBand.show()

    def rectangle(self):
        """
        Builds rectangle from self.startPoint and self.endPoint
        """
        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 setAction(self, action):
        self.toolAction = action
        self.toolAction.setCheckable(True)
    
    def canvasReleaseEvent(self, e):
        """
        After the rectangle is built, here features are selected.
        """
        # tool was planned to work on left click 
        if e.button() == QtCore.Qt.LeftButton:
            layer = self.iface.mapCanvas().currentLayer()
            if QtGui.QApplication.keyboardModifiers() == QtCore.Qt.ShiftModifier:
                self.isEmittingPoint = False
                r = self.rectangle()
                if r is None:
                    return
                bbRect = self.canvas.mapSettings().mapToLayerCoordinates(layer, r)
                self.rubberBand.hide()
                #select all stuff
                layer.setSelectedFeatures([]) #portar para o feature handler
                layer.select(bbRect, True)
                #mudar depois para o dsgmothafucka
                featDict = dict()
                pointDict = dict()
                for feat in layer.selectedFeatures():
                    featDict[feat.id()] = feat
                    pointDict[feat.id()] = feat.geometry()
                pixelValueDict = self.getPixelValueFromPointDict(pointDict, self.rasterLayer)
                for idx in pointDict:
                    value = pixelValueDict[idx]
                    if value:
                        self.auxList.append({'featId':idx, 'feat':featDict[idx], 'value':value})
            else:
                value, pointGeom = self.getPixelValue(self.rasterLayer)
                if value:
                    self.auxList.append({'geom':pointGeom, 'value':value})
            #create context menu to select attribute
            if self.auxList:
                self.createContextMenuOnPosition(e, layer)

    def createContextMenuOnPosition(self, e, layer):
        menu = QMenu()
        callbackDict = dict()
        fieldList = [field.name() for field in layer.fields() if field.isNumeric()]
        for field in fieldList:
            action = menu.addAction(field)
            callback = lambda t = [field, layer] : self.handleFeatures(t[0], t[1])
            action.triggered[()].connect(callback)
        menu.exec_(self.canvas.viewport().mapToGlobal(e.pos()))
    
    def handleFeatures(self, selectedField, layer):
        layer.startEditing()
        for item in self.auxList:
            if 'featId' in item:
                feat = item['feat']
                idx = feat.fieldNameIndex(selectedField)
                feat.setAttribute(idx, item['value'])
                layer.updateFeature(feat)
            else:
                feature = QgsFeature(layer.fields())
                self.dsgGeometryHandler.reprojectFeature(item['geom'], layer.crs())
                feature.setGeometry(item['geom'])
                self.addFeature(feature, layer, selectedField, item['value'])
        self.auxList = []
        self.canvas.refresh()
    
    def addFeature(self, feature, layer, field, pointValue):
        fields = layer.fields()
        feature.initAttributes(fields.count())            
        provider = layer.dataProvider()             
        for i in range(fields.count()):
            value = provider.defaultValue(i) if fields[i].name() != field else pointValue
            if value:
                feature.setAttribute(i, value)                
        form = QgsAttributeDialog(layer, feature, False)
        form.setMode(QgsAttributeForm.AddFeatureMode)
        formSuppress = layer.editFormConfig().suppress()
        if formSuppress == QgsEditFormConfig.SuppressDefault:
            if self.getSuppressOptions(): #this is calculated every time because user can switch options while using tool
                layer.addFeature(feature, True)
            else:
                if not form.exec_():
                    feature.setAttributes(form.feature().attributes())
        elif formSuppress == QgsEditFormConfig.SuppressOff:
            if not form.exec_():
                feature.setAttributes(form.feature().attributes())
        else:
            layer.addFeature(feature, True)

    def getCursorRect(self, e):
        """
        Calculates small cursor rectangle around mouse position. Used to facilitate operations
        """
        p = self.toMapCoordinates(e.pos())
        w = self.canvas.mapUnitsPerPixel() * 10
        return QgsRectangle(p.x()-w, p.y()-w, p.x()+w, p.y()+w)
    
    def deactivate(self):
        """
        Deactivate tool.
        """
        QtGui.QApplication.restoreOverrideCursor()
        self.hoverRubberBand.reset(QGis.Polygon)
        try:
            if self.toolAction:
                self.toolAction.setChecked(False)
            if self is not None:
                QgsMapTool.deactivate(self)
                self.canvas.unsetMapTool(self)
        except:
            pass

    def activate(self):
        """
        Activate tool.
        """
        if self.toolAction:
            self.toolAction.setChecked(True)
        QgsMapTool.activate(self)
        self.iface.mapCanvas().setMapTool(self)
        layer = self.iface.mapCanvas().currentLayer()
        if not layer or not isinstance(layer, QgsVectorLayer):
            self.iface.messageBar().pushMessage(self.tr("Warning"), self.tr("Select a point vector layer as the active layer"),
                                                level=QgsMessageBar.INFO, duration=10)
            self.deactivate()

    def reprojectSearchArea(self, layer, geom):
        """
        Reprojects search area if necessary, according to what is being searched.
        :param layer: (QgsVectorLayer) layer which target rectangle has to have same SRC.
        :param geom: (QgsRectangle) rectangle representing search area.
        """
        #geom always have canvas coordinates
        epsg = self.canvas.mapSettings().destinationCrs().authid()
        #getting srid from something like 'EPSG:31983'
        srid = layer.crs().authid()
        if epsg == srid:
            return geom
        crsSrc = QgsCoordinateReferenceSystem(epsg)
        crsDest = QgsCoordinateReferenceSystem(srid)
        # Creating a transformer
        coordinateTransformer = QgsCoordinateTransform(crsSrc, crsDest) # here we have to put authid, not srid
        auxGeom = QgsGeometry.fromRect(geom)
        auxGeom.transform(coordinateTransformer)
        return auxGeom.boundingBox()

    def getPixelValue(self, rasterLayer):
        mousePos = self.qgsMapToolEmitPoint.toMapCoordinates(self.canvas.mouseLastXY())
        mousePosGeom = QgsGeometry.fromPoint(mousePos)
        return self.getPixelValueFromPoint(mousePosGeom, rasterLayer), mousePosGeom

    def getPixelValueFromPoint(self, mousePosGeom, rasterLayer, fromCanvas = True):
        """
        
        """
        rasterCrs = rasterLayer.crs() if rasterLayer else False
        if rasterCrs:
            if fromCanvas:
                self.dsgGeometryHandler.reprojectFeature(mousePosGeom, rasterCrs, self.canvas.mapRenderer().destinationCrs())
            else:
                mousePosGeom = QgsGeometry(mousePosGeom)
                self.dsgGeometryHandler.reprojectFeature(mousePosGeom, rasterCrs, self.canvas.currentLayer().crs())
            # isMulti = QgsWKBTypes.isMultiType(int(layer.wkbType())) # tem que ver se serve pra QgsGeometry
            mousePos = mousePosGeom.asMultiPoint()[0] if mousePosGeom.isMultipart() else mousePosGeom.asPoint()
            # identify pixel(s) information
            i = rasterLayer.dataProvider().identify( mousePos, QgsRaster.IdentifyFormatValue )
            if i.isValid():
                value = i.results().values()[0]
                if value:
                    value = int(value) if self.decimals == 0 else round(value, self.decimals)
                return value
            else:
                return None
    
    def getPixelValueFromPointDict(self, pointDict, rasterLayer):
        """
        pointDict = {'pointId':QgsGeometry}

        returns {'pointId': value}
        """
        return {key : self.getPixelValueFromPoint(value, rasterLayer, fromCanvas=False) for key, value in pointDict.iteritems()} #no python3 eh items()
Exemple #2
0
class DsgRasterInfoTool(QWidget, Ui_DsgRasterInfoTool):
    """
    This class is supposed to help revision operators. It shows, on mouse hovering
    raster layer's band values. For a MDS product, altimetry is, then, given.
    Tool Behaviour:
    1- On hoverring a pixel: expose band value(s)
    2- On mouse click: create a new instance of desired layer (filled on config).
        * behaviour 2 is an extrapolation of first conception
    """
    def __init__(self, iface, parent = None):
        """
        Class constructor.
        """
        # super(QgsRasterLayer, self).__init__()
        self.canvas = iface.mapCanvas()
        super(DsgRasterInfoTool, self).__init__(parent)
        self.setupUi(self)
        self.bandTooltipButton.setToolTip(self.tr("Show raster tooltip"))
        self.dynamicHistogramButton.setToolTip(self.tr("Dynamic histogram view"))
        self.valueSetterButton.setToolTip(self.tr("Set raster value from mouse click\nShift + Left Click + Mouse Drag: Selects a set of points and assigns raster value for each point"))
        self.assignBandValueTool = None
        self.parent = parent
        self.splitter.hide()
        self.iface = iface
        self.timerMapTips = QTimer( self.canvas )
        self.DsgGeometryHandler = DsgGeometryHandler(iface)
        self.addShortcuts()
        self.valueSetterButton.setEnabled(False)
        self.iface.mapCanvas().currentLayerChanged.connect(self.enableAssignValue)
        self.iface.actionToggleEditing().triggered.connect(self.enableAssignValue)
        # start currentLayer selection
        self.currentLayer = None

    def resetEditingSignals(self, currentLayer):
        """
        Disconnects editing signal from previously selected layer and connects it to newly selected layer.
        Method is called whenever currentlLayerChanged signal is emitted.
        """
        # get previous selected layer
        prevLayer = self.currentLayer
        # update current selected layer
        self.currentLayer = currentLayer
        activateAlias = lambda : self.activateValueSetter(True)
        deactivateAlias = lambda : self.activateValueSetter(False)
        if prevLayer:
            try:
                # if there was a previous selection, signals must be disconnected from it before connecting to the new layer
                prevLayer.editingStarted.disconnect(activateAlias)
                prevLayer.editingStopped.disconnect(deactivateAlias)
            except:
                # in case signal is not yet connected, somehow
                pass
        # connecting signals to new layer
        if isinstance(self.currentLayer, QgsVectorLayer):
            self.currentLayer.editingStarted.connect(activateAlias)
            self.currentLayer.editingStopped.connect(deactivateAlias)

    def add_action(self, icon_path, text, callback, parent=None):
        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        if parent:
            parent.addAction(action)
        return action

    def addShortcuts(self):
        icon_path = ':/plugins/DsgTools/icons/rasterToolTip.png'
        text = self.tr('DSGTools: Raster information tool')
        self.activateToolAction = self.add_action(icon_path, text, self.rasterInfoPushButton.toggle, parent = self.parent)
        self.iface.registerMainWindowAction(self.activateToolAction, '')
        icon_path = ':/plugins/DsgTools/icons/band_tooltip.png'
        text = self.tr('DSGTools: Band tooltip')
        self.bandTooltipButtonAction = self.add_action(icon_path, text, self.bandTooltipButton.toggle, parent = self.parent)
        self.iface.registerMainWindowAction(self.bandTooltipButtonAction, '')
        icon_path = ':/plugins/DsgTools/icons/histogram.png'
        text = self.tr('DSGTools: Dynamic Histogram Viewer')
        self.dynamicHistogramButtonAction = self.add_action(icon_path, text, self.dynamicHistogramButton.toggle, parent = self.parent)
        self.iface.registerMainWindowAction(self.dynamicHistogramButtonAction, '')
        icon_path = ':/plugins/DsgTools/icons/valueSetter.png'
        text = self.tr('DSGTools: Set Value From Point')
        self.valueSetterButtonAction = self.add_action(icon_path, text, self.valueSetterButton.toggle, parent = self.parent)
        self.iface.registerMainWindowAction(self.valueSetterButtonAction, '')
        # self.timerMapTips.timeout.connect( self.showToolTip )

    def enableAssignValue(self):
        layer = self.iface.mapCanvas().currentLayer()
        if layer and isinstance(layer, QgsVectorLayer):
            if layer.geometryType() == QGis.Point and layer.isEditable():
                self.valueSetterButton.setEnabled(True)
                # reset editing signals
                self.resetEditingSignals(currentLayer=layer)
            else:
                self.valueSetterButton.setEnabled(False)
                self.valueSetterButton.setChecked(False)
                self.activateValueSetter(False)
        else:
            self.valueSetterButton.setEnabled(False)
            self.valueSetterButton.setChecked(False)
            self.activateValueSetter(False)

    def deactivate(self):
        self.activateBandValueTool(False)
        self.activateStretchTool(False)
        self.activateValueSetter(False)

    @pyqtSlot(bool, name = 'on_rasterInfoPushButton_toggled')
    def toggleBar(self, toggled=None):
        """
        Shows/Hides the tool bar
        """
        if toggled is None:
            toggled = self.rasterInfoPushButton.isChecked()
        if toggled:
            self.splitter.show()
        else:
            self.splitter.hide()      
    
    @pyqtSlot(bool, name = 'on_bandTooltipButton_toggled')
    def activateBandValueTool(self, state):
        if state:
            self.iface.mapCanvas().xyCoordinates.connect(self.showToolTip)
        else:
            self.iface.mapCanvas().xyCoordinates.disconnect(self.showToolTip)
    
    @pyqtSlot(bool, name = 'on_dynamicHistogramButton_toggled')
    def activateStretchTool(self, state):
        if state:
            self.iface.mapCanvas().extentsChanged.connect(self.stretch_raster)
        else:
            self.iface.mapCanvas().extentsChanged.disconnect(self.stretch_raster)
    
    @pyqtSlot(bool, name = 'on_valueSetterButton_toggled')
    def activateValueSetter(self, state):
        if state:
            raster = self.rasterComboBox.currentLayer()
            self.loadTool(self.iface, raster)
        else:
            self.unloadTool()
    
    def loadTool(self, iface, raster):
        self.assignBandValueTool = AssignBandValueTool(self.iface, raster)
        self.assignBandValueTool.activate()
    
    def unloadTool(self):
        if self.assignBandValueTool:
            self.assignBandValueTool.deactivate()
        self.assignBandValueTool = None

    def stretch_raster(self):
        try:
            formerLayer = self.iface.activeLayer()
            layer = self.rasterComboBox.currentLayer()
            self.iface.mapCanvas().currentLayerChanged.disconnect(self.enableAssignValue)
            self.iface.setActiveLayer(layer)
            self.iface.mainWindow().findChild( QAction, 'mActionLocalCumulativeCutStretch' ).trigger()
            self.iface.setActiveLayer(formerLayer)
            self.iface.mapCanvas().currentLayerChanged.connect(self.enableAssignValue)
        except AttributeError:
            pass
    
    def getPixelValue(self, mousePos, rasterLayer):
        """
        
        """
        rasterCrs = rasterLayer.crs()
        mousePosGeom = QgsGeometry.fromPoint(mousePos)
        canvasCrs = self.canvas.mapRenderer().destinationCrs()
        self.DsgGeometryHandler.reprojectFeature(mousePosGeom, rasterCrs, canvasCrs)
        mousePos = mousePosGeom.asPoint()
        # identify pixel(s) information
        i = rasterLayer.dataProvider().identify( mousePos, QgsRaster.IdentifyFormatValue )
        if i.isValid():
            text = ", ".join(['{0:g}'.format(r) for r in i.results().values() if r is not None] )
        else:
            text = ""
        return text

    def showToolTip(self, qgsPoint):
        """
        
        """
        self.timerMapTips.stop()
        self.timerMapTips.start( 6000 ) # time in milliseconds
        if self.canvas.underMouse():
            raster = self.rasterComboBox.currentLayer()
            if raster:
                text = self.getPixelValue(qgsPoint, raster)
                p = self.canvas.mapToGlobal( self.canvas.mouseLastXY() )
                QToolTip.showText( p, text, self.canvas )
Exemple #3
0
class BandValueTool(QgsMapTool):
    """
    This class is supposed to help revision operators. It shows, on mouse hovering
    raster layer's band values. For a MDS product, altimetry is, then, given.
    Tool Behaviour:
    1- On hoverring a pixel: expose band value(s)
    2- On mouse click: create a new instance of desired layer (filled on config).
        * behaviour 2 is an extrapolation of first conception
    """
    def __init__(self, iface, parent):
        """
        Class constructor.
        """
        # super(QgsRasterLayer, self).__init__()
        self.canvas = iface.mapCanvas()
        super(BandValueTool, self).__init__(self.canvas)
        self.parent = parent
        self.iface = iface
        self.toolAction = None
        self.QgsMapToolEmitPoint = QgsMapToolEmitPoint(self.canvas)
        self.DsgGeometryHandler = DsgGeometryHandler(iface)
        self.timerMapTips = QTimer( self.canvas )
        self.timerMapTips.timeout.connect( self.showToolTip )
        self.activated = False
    
    def setAction(self, action):
        """
        
        """
        self.toolAction = action

    def activate(self):
        """
        Activates tool.
        """
        if self.toolAction:
            self.activated = True
        QgsMapTool.activate(self)
        self.canvas.setMapTool(self)
    
    def deactivate(self):
        """
        Deactivates tool.
        """
        self.timerMapTips.stop()
        try:
            if self.toolAction:
                self.activated = False
                self.toolAction.setChecked(False)
            if self is not None:
                QgsMapTool.deactivate(self)
        except:
            pass        

    def canvasMoveEvent(self, e):
        QToolTip.hideText()
        self.timerMapTips.start( 500 ) # time in milliseconds
        self.showToolTip()               
    
    def getPixelValue(self, rasterLayer):
        """
        
        """
        rasterCrs = rasterLayer.crs()
        mousePos = self.QgsMapToolEmitPoint.toMapCoordinates(self.canvas.mouseLastXY())
        mousePosGeom = QgsGeometry.fromPoint(mousePos)
        self.DsgGeometryHandler.reprojectFeature(mousePosGeom, rasterCrs, self.canvas.mapRenderer().destinationCrs())
        mousePos = mousePosGeom.asPoint()
        # identify pixel(s) information
        i = rasterLayer.dataProvider().identify( mousePos, QgsRaster.IdentifyFormatValue )
        if i.isValid():
            text = ", ".join(['{0:g}'.format(r) for r in i.results().values() if r is not None] )
        else:
            text = ""
        return text

    def showToolTip(self):
        """
        
        """
        self.timerMapTips.stop()
        if self.canvas.underMouse():
            raster = self.parent.rasterComboBox.currentLayer()
            if raster:
                text = self.getPixelValue(raster)
                p = self.canvas.mapToGlobal( self.canvas.mouseLastXY() )
                QToolTip.showText( p, text, self.canvas )