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()
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 )
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 )