def createWidget(self): self._layer = None if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): if self.param.multiple: return MultipleInputPanel(options=[]) else: widget = QgsFieldComboBox() widget.setAllowEmptyFieldName(self.param.optional) if self.param.datatype == ParameterTableField.DATA_TYPE_NUMBER: widget.setFilters(QgsFieldProxyModel.Numeric) elif self.param.datatype == ParameterTableField.DATA_TYPE_STRING: widget.setFilters(QgsFieldProxyModel.String) return widget else: widget = QComboBox() widget.setEditable(True) fields = self.dialog.getAvailableValuesOfType( ParameterTableField, None) if self.param.optional: widget.addItem(self.NOT_SET, None) for f in fields: widget.addItem(self.dialog.resolveValueDescription(f), f) return widget
def testFilter(self): """ test setting field with filter """ l = create_layer() w = QgsFieldComboBox() w.setLayer(l) w.setFilters(QgsFieldProxyModel.Int) self.assertEqual(w.layer(), l) w.setField('fldint') self.assertEqual(w.currentField(), 'fldint')
def createWidget(self): self._layer = None if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH): if self.param.multiple: return MultipleInputPanel(options=[]) else: widget = QgsFieldComboBox() widget.setAllowEmptyFieldName(self.param.optional) widget.fieldChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) if self.param.datatype == ParameterTableField.DATA_TYPE_NUMBER: widget.setFilters(QgsFieldProxyModel.Numeric) elif self.param.datatype == ParameterTableField.DATA_TYPE_STRING: widget.setFilters(QgsFieldProxyModel.String) elif self.param.datatype == ParameterTableField.DATA_TYPE_DATETIME: widget.setFilters(QgsFieldProxyModel.Date | QgsFieldProxyModel.Time) return widget else: widget = QComboBox() widget.setEditable(True) fields = self.dialog.getAvailableValuesOfType(ParameterTableField, None) if self.param.optional: widget.addItem(self.NOT_SET, None) for f in fields: widget.addItem(self.dialog.resolveValueDescription(f), f) return widget
class Dialog(QtGui.QDialog): def __init__(self, curPointLayerName, curPolygonLayerName, curFiledName, parent=None): QtGui.QDialog.__init__(self, parent) self.resize(300, 100) Plugin().plPrint("curPointLayerName:: %s" % curPointLayerName) Plugin().plPrint("curPolygonLayerName:: %s" % curPolygonLayerName) Plugin().plPrint("curFiledName:: %s" % curFiledName) self.setWindowTitle(Plugin().getPluginName()) self.__mainLayout = QtGui.QVBoxLayout(self) self.__layout = QtGui.QGridLayout(self) # self.__layout.addWidget(QtGui.QLabel(self.tr("Point layer name") + ":"), 0, 0) l1 = QtGui.QLabel(u"Имя точечного слоя" + ":") l1.setSizePolicy( QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed ) self.__layout.addWidget(l1, 0, 0) self.pointsLayersComboBox = QgsMapLayerComboBox() self.pointsLayersComboBox.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed ) self.pointsLayersComboBox.setFilters(QgsMapLayerProxyModel.PointLayer) self.pointsLayersComboBox.setEditable(True) self.pointsLayersComboBox.setEditText(curPointLayerName) self.pointsLayersComboBox.layerChanged.connect(self.layerChooze1) self.__layout.addWidget(self.pointsLayersComboBox, 0, 1) # self.__layout.addWidget(QtGui.QLabel(self.tr("Field name") + ":"), 2, 0) self.__layout.addWidget(QtGui.QLabel(u"Имя поля" + ":"), 2, 0) self.fieldName = QgsFieldComboBox() self.fieldName.setFilters(QgsFieldProxyModel.Int) self.fieldName.setEditable(True) self.fieldName.setEditText(curFiledName) self.fieldName.fieldChanged.connect(self.filedChooze) self.__layout.addWidget(self.fieldName, 2, 1) # self.__layout.addWidget(QtGui.QLabel(self.tr("Polypon layer name") + ":"), 1, 0) self.__layout.addWidget(QtGui.QLabel(u"Имя полигонального слоя" + ":"), 1, 0) self.polygonsLayersComboBox = QgsMapLayerComboBox() self.polygonsLayersComboBox.setFilters(QgsMapLayerProxyModel.PolygonLayer) self.polygonsLayersComboBox.setEditable(True) self.polygonsLayersComboBox.setEditText(curPolygonLayerName) self.polygonsLayersComboBox.layerChanged.connect(self.layerChooze2) self.polygonsLayersComboBox.layerChanged.connect(self.fieldName.setLayer) self.__layout.addWidget(self.polygonsLayersComboBox, 1, 1) # self.startButton = QtGui.QPushButton(self.tr("Start")) # self.startButton.clicked.connect(self.startCalculation) # self.__layout.addWidget(self.startButton, 3, 1) self.__mainLayout.addLayout(self.__layout) # self.progress = QtGui.QLabel() # self.__mainLayout.addWidget(self.progress) self.__bbox = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok) self.__bbox.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed) self.__bbox.accepted.connect(self.accept) self.__mainLayout.addWidget(self.__bbox) def layerChooze1(self, qgsMapLayer): self.pointsLayersComboBox.setEditText(qgsMapLayer.name()) def layerChooze2(self, qgsMapLayer): self.polygonsLayersComboBox.setEditText(qgsMapLayer.name()) def filedChooze(self, fieldName): self.sender().setEditText(fieldName) # def layernameSave(self, csTargetLayerName): # if csTargetLayerName == u"": # return # setCSLayerName(csTargetLayerName) def getSettings(self): return [ self.pointsLayersComboBox.currentText(), self.polygonsLayersComboBox.currentText(), self.fieldName.currentText() ]
class Dialog(QtGui.QDialog): def __init__( self, curPointsLayerFrom, curPointsLayerTo, curFNIdFrom, curFNLink, curFNIdTo, curResultLayerName, parent=None): QtGui.QDialog.__init__(self, parent) self.resize(500, 200) self.setWindowTitle(QgisPlugin().pluginName) self.__mainLayout = QtGui.QVBoxLayout(self) self.__layout = QtGui.QGridLayout(self) l1 = QtGui.QLabel(self.tr(u"Point layer 'FROM'") + ":") l1.setSizePolicy( QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed ) self.__layout.addWidget(l1, 0, 0) self.pointsLayerFrom = QgsMapLayerComboBox() self.pointsLayerFrom.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed ) self.pointsLayerFrom.setFilters(QgsMapLayerProxyModel.PointLayer) self.pointsLayerFrom.setEditable(True) # self.pointsLayerFrom.setEditText(curPointsLayerFrom) self.pointsLayerFrom.layerChanged.connect(self.choozeLayerFrom) self.__layout.addWidget(self.pointsLayerFrom, 0, 1) l2 = QtGui.QLabel(self.tr(u"Point layer 'TO'") + ":") l2.setSizePolicy( QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed ) self.__layout.addWidget(l2, 1, 0) self.pointsLayerTo = QgsMapLayerComboBox() self.pointsLayerTo.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed ) self.pointsLayerTo.setFilters(QgsMapLayerProxyModel.PointLayer) self.pointsLayerTo.setEditable(True) # self.pointsLayerTo.setEditText(curPointsLayerTo) self.pointsLayerTo.layerChanged.connect(self.choozeLayerTo) self.__layout.addWidget(self.pointsLayerTo, 1, 1) self.__layout.addWidget( QtGui.QLabel(self.tr(u"Point 'FROM' id field") + ":"), 2, 0 ) self.fnIdFrom = QgsFieldComboBox() self.fnIdFrom.setFilters(QgsFieldProxyModel.Int | QgsFieldProxyModel.LongLong) self.fnIdFrom.setEditable(True) # self.fnIdFrom.setEditText(curFNIdFrom) self.fnIdFrom.fieldChanged.connect(self.filedChooze) self.__layout.addWidget(self.fnIdFrom, 2, 1) self.__layout.addWidget( QtGui.QLabel(self.tr(u"Link field") + ":"), 3, 0 ) self.fnLink = QgsFieldComboBox() self.fnLink.setFilters(QgsFieldProxyModel.Int | QgsFieldProxyModel.LongLong) self.fnLink.setEditable(True) # self.fnLink.setEditText(curFNLink) self.fnLink.fieldChanged.connect(self.filedChooze) self.__layout.addWidget(self.fnLink, 3, 1) self.__layout.addWidget( QtGui.QLabel(self.tr(u"Point 'TO' id field") + ":"), 4, 0) self.fnIdTo = QgsFieldComboBox() self.fnIdTo.setFilters(QgsFieldProxyModel.Int | QgsFieldProxyModel.LongLong) self.fnIdTo.setEditable(True) # self.fnIdTo.setEditText(curFNIdTo) self.fnIdTo.fieldChanged.connect(self.filedChooze) self.__layout.addWidget(self.fnIdTo, 4, 1) self.__layout.addWidget( QtGui.QLabel(self.tr(u"Save result in layer") + ":"), 5, 0 ) self.linesLayer = QgsMapLayerComboBox() self.linesLayer.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed ) self.linesLayer.setFilters(QgsMapLayerProxyModel.LineLayer) self.linesLayer.setEditable(True) self.linesLayer.layerChanged.connect(self.choozeResultLayer) self.__layout.addWidget(self.linesLayer, 5, 1) # self.__layout4resultFileChoose = QtGui.QHBoxLayout() # self.leResultFilename = QtGui.QLineEdit(curResultFilename) # self.__layout4resultFileChoose.addWidget(self.leResultFilename) # self.pbChooseResultFilename = QtGui.QPushButton(u"Выбрать") # self.pbChooseResultFilename.released.connect(self.chooseResultFilename) # self.__layout4resultFileChoose.addWidget(self.pbChooseResultFilename) # self.__layout.addLayout(self.__layout4resultFileChoose, 6, 0, 2, 0) self.pointsLayerFrom.layerChanged.connect(self.fnIdFrom.setLayer) self.pointsLayerFrom.layerChanged.connect(self.fnLink.setLayer) self.pointsLayerTo.layerChanged.connect(self.fnIdTo.setLayer) self.__mainLayout.addLayout(self.__layout) self.__bbox = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok) self.__bbox.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed) self.__bbox.accepted.connect(self.accept) self.__mainLayout.addWidget(self.__bbox) self.fillControls( curPointsLayerFrom, curPointsLayerTo, curFNIdFrom, curFNLink, curFNIdTo, curResultLayerName ) def fillControls( self, curPointsLayerFrom, curPointsLayerTo, curFNIdFrom, curFNLink, curFNIdTo, curResultLayerName ): QgisPlugin().plPrint("curPointsLayerFrom: " + curPointsLayerFrom) QgisPlugin().plPrint("curPointsLayerTo: " + curPointsLayerTo) QgisPlugin().plPrint("curFNIdFrom: " + curPointsLayerFrom) QgisPlugin().plPrint("curFNLink: " + curFNIdFrom) QgisPlugin().plPrint("curPointsLayerFrom: " + curFNLink) QgisPlugin().plPrint("curFNIdTo: " + curFNIdTo) QgisPlugin().plPrint("curResultLayerName: " + curResultLayerName) layerFrom = self.getQGISLayer(curPointsLayerFrom) layerTo = self.getQGISLayer(curPointsLayerTo) layerResult = self.getQGISLayer(curResultLayerName, True) if layerFrom is None: self.pointsLayerFrom.setCurrentIndex(-1) self.pointsLayerFrom.setEditText(curPointsLayerFrom) else: self.pointsLayerFrom.setLayer(layerFrom) if layerTo is None: self.pointsLayerTo.setCurrentIndex(-1) self.pointsLayerTo.setEditText(curPointsLayerTo) else: self.pointsLayerTo.setLayer(layerTo) if layerResult is None: self.linesLayer.setCurrentIndex(-1) self.linesLayer.setEditText(curResultLayerName) else: self.linesLayer.setLayer(layerResult) # self.fnIdFrom.clear() # self.fnLink.clear() # self.fnIdTo.clear() # self.fnIdFrom.setField(curFNIdFrom) self.fnIdFrom.setCurrentIndex(-1) self.fnIdFrom.setEditText(curFNIdFrom) # self.fnLink.setField(curFNLink) self.fnLink.setCurrentIndex(-1) self.fnLink.setEditText(curFNLink) # self.fnIdTo.setField(curFNIdTo) self.fnIdTo.setCurrentIndex(-1) self.fnIdTo.setEditText(curFNIdTo) def getQGISLayer(self, layerName, silent=False): if layerName is None: return if layerName == "": return layers = QgsMapLayerRegistry.instance().mapLayersByName(layerName) if len(layers) == 0: if silent is False: QgisPlugin().showMessageForUser( self.tr(u"Layer with name '%s' not found!") % layerName, QgsMessageBar.CRITICAL, 0 ) return None return layers[0] def choozeLayerFrom(self, qgsMapLayer): self.pointsLayerFrom.setEditText(qgsMapLayer.name()) def choozeLayerTo(self, qgsMapLayer): self.pointsLayerTo.setEditText(qgsMapLayer.name()) def choozeResultLayer(self, qgsMapLayer): self.linesLayer.setEditText(qgsMapLayer.name()) def filedChooze(self, fieldName): self.sender().setEditText(fieldName) def chooseResultFilename(self): filename = QtGui.QFileDialog.getSaveFileName( self, self.tr(u"Choose file for save result"), self.curResultFilename # QtCore.QFileInfo(self.curResultFilename).absolutePath() ) self.leResultFilename.setText(filename) def getSettings(self): return [ self.pointsLayerFrom.currentText(), self.pointsLayerTo.currentText(), self.fnIdFrom.currentText(), self.fnLink.currentText(), self.fnIdTo.currentText(), self.linesLayer.currentText(), ]
class UAVPreparer: """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join( self.plugin_dir, 'i18n', 'UAVPreparer_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) # Declare instance attributes self.actions = [] self.menu = self.tr(u'&UAV Preparer') # TODO: We are going to let the user set this up in a future iteration self.toolbar = self.iface.addToolBar(u'UAVPreparer') self.toolbar.setObjectName(u'UAVPreparer') # Declare variables self.outputfile = None # noinspection PyMethodMayBeStatic def tr(self, message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('UAVPreparer', message) def add_action( self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): """Add a toolbar icon to the toolbar. :param icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :type icon_path: str :param text: Text that should be shown in menu items for this action. :type text: str :param callback: Function to be called when the action is triggered. :type callback: function :param enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :type enabled_flag: bool :param add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :type add_to_menu: bool :param add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :type add_to_toolbar: bool :param status_tip: Optional text to show in a popup when mouse pointer hovers over the action. :type status_tip: str :param parent: Parent widget for the new action. Defaults None. :type parent: QWidget :param whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.actions list. :rtype: QAction """ # Create the dialog (after translation) and keep reference self.dlg = UAVPreparerDialog() icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.iface.addPluginToMenu( self.menu, action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/UAVPreparer/icon.png' self.add_action( icon_path, text=self.tr(self.tr(u'Unmanned Aerial Vehicle Preparer')), callback=self.run, parent=self.iface.mainWindow()) # Access the raster layer self.layerComboManagerDSM = QgsMapLayerComboBox(self.dlg.widgetDSM) self.layerComboManagerDSM.setFilters(QgsMapLayerProxyModel.RasterLayer) self.layerComboManagerDSM.setFixedWidth(175) self.layerComboManagerDSM.setCurrentIndex(-1) # Access the vector layer and an attribute field self.layerComboManagerPoint = QgsMapLayerComboBox(self.dlg.widgetPoint) self.layerComboManagerPoint.setCurrentIndex(-1) self.layerComboManagerPoint.setFilters(QgsMapLayerProxyModel.PointLayer) self.layerComboManagerPoint.setFixedWidth(175) self.layerComboManagerPointField = QgsFieldComboBox(self.dlg.widgetField) self.layerComboManagerPointField.setFilters(QgsFieldProxyModel.Numeric) self.layerComboManagerPoint.layerChanged.connect(self.layerComboManagerPointField.setLayer) # Set up of file save dialog self.fileDialog = QFileDialog() self.dlg.selectButton.clicked.connect(self.savefile) # Set up for the Help button self.dlg.helpButton.clicked.connect(self.help) # Set up for the Run button self.dlg.runButton.clicked.connect(self.start_progress) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for action in self.actions: self.iface.removePluginMenu( self.tr(u'&UAV Preparer'), action) self.iface.removeToolBarIcon(action) # remove the toolbar del self.toolbar def run(self): """Run method that performs all the real work""" # show the dialog self.dlg.show() # Run the dialog event loop result = self.dlg.exec_() # See if OK was pressed if result: # Do something useful here - delete the line containing pass and # substitute with your code. pass def savefile(self): self.outputfile = self.fileDialog.getSaveFileName(None, "Save File As:", None, "Text Files (*.txt)") self.dlg.textOutput.setText(self.outputfile) def help(self): url = "https://github.com/nilswallenberg/UAVPreparer" webbrowser.open_new_tab(url) def start_progress(self): if not self.outputfile: QMessageBox.critical(None, "Error", "Specify an output file") return # Acquiring geodata and attributes dsm_layer = self.layerComboManagerDSM.currentLayer() if dsm_layer is None: QMessageBox.critical(None, "Error", "No valid raster layer is selected") return else: provider = dsm_layer.dataProvider() filepath_dsm = str(provider.dataSourceUri()) point_layer = self.layerComboManagerPoint.currentLayer() if point_layer is None: QMessageBox.critical(None, "Error", "No valid vector point layer is selected") return else: vlayer = QgsVectorLayer(point_layer.source(), "point", "ogr") point_field = self.layerComboManagerPointField.currentField() idx = vlayer.fieldNameIndex(point_field) if idx == -1: QMessageBox.critical(None, "Error", "An attribute with unique fields must be selected") return ### main code ### # set radius rSquare = int(self.dlg.spinBox.value()) # half picture size # finding ID column idx = vlayer.fieldNameIndex(point_field) numfeat = vlayer.featureCount() result = np.zeros([numfeat, 4]) self.dlg.progressBar.setRange(0, numfeat) counter = 0 for feature in vlayer.getFeatures(): self.dlg.progressBar.setValue (counter + 1) geom = feature.geometry() pp = geom.asPoint() x = pp[0] y = pp[1] gdalclipdsm = "gdalwarp -dstnodata -9999 -q -overwrite -te " + str(x - rSquare) + " " + str(y - rSquare) + \ " " + str(x + rSquare) + " " + str(y + rSquare) + " -of GTiff " + filepath_dsm + " " + self.plugin_dir + "/clipdsm.tif" #QMessageBox.critical(None, "Bla", gdalclipdsm) # call the gdal function si = subprocess.STARTUPINFO() # used to suppress cmd window si.dwFlags |= subprocess.STARTF_USESHOWWINDOW subprocess.call(gdalclipdsm, startupinfo=si) #subprocess.call(gdalclipdsm) dataset = gdal.Open(self.plugin_dir + "/clipdsm.tif") dsm_array = dataset.ReadAsArray().astype(np.float) result[counter, 0] = int(feature.attributes()[idx]) result[counter, 1] = np.mean(dsm_array) result[counter, 2] = np.max(dsm_array) result[counter, 3] = np.min(dsm_array) counter += 1 numformat = "%d " + "%6.2f " * 3 headertext = "id mean max min" np.savetxt(self.outputfile, result, fmt=numformat, header=headertext, comments="", delimiter="/t") self.iface.messageBar().pushMessage("UAV Preparer. Operation successful!", level=QgsMessageBar.INFO, duration=5)
class DSMGenerator: """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'DSMGenerator_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) # Create the dialog (after translation) and keep reference self.dlg = DSMGeneratorDialog() # Declare instance attributes self.actions = [] self.menu = self.tr(u'&DSM Generator') # TODO: We are going to let the user set this up in a future iteration # self.toolbar = self.iface.addToolBar(u'DSMGenerator') # self.toolbar.setObjectName(u'DSMGenerator') # Declare variables self.OSMoutputfile = None self.DSMoutputfile = None if not (os.path.isdir(self.plugin_dir + '/temp')): os.mkdir(self.plugin_dir + '/temp') # Access the raster layer self.layerComboManagerDEM = QgsMapLayerComboBox(self.dlg.widgetRaster) self.layerComboManagerDEM.setFilters(QgsMapLayerProxyModel.RasterLayer) self.layerComboManagerDEM.setFixedWidth(175) self.layerComboManagerDEM.setCurrentIndex(-1) # Access the vector layer and an attribute field self.layerComboManagerPolygon = QgsMapLayerComboBox( self.dlg.widgetPolygon) self.layerComboManagerPolygon.setCurrentIndex(-1) self.layerComboManagerPolygon.setFilters( QgsMapLayerProxyModel.PolygonLayer) self.layerComboManagerPolygon.setFixedWidth(175) self.layerComboManagerPolygonField = QgsFieldComboBox( self.dlg.widgetField) self.layerComboManagerPolygonField.setFilters( QgsFieldProxyModel.Numeric) self.layerComboManagerPolygonField.setFixedWidth(150) self.layerComboManagerPolygon.layerChanged.connect( self.layerComboManagerPolygonField.setLayer) # Set up of DSM file save dialog self.DSMfileDialog = QFileDialog() self.dlg.saveButton.clicked.connect(self.savedsmfile) # Set up of OSM polygon file save dialog self.OSMfileDialog = QFileDialog() self.dlg.savePolygon.clicked.connect(self.saveosmfile) # Set up for the Help button self.dlg.helpButton.clicked.connect(self.help) # Set up for the Close button self.dlg.closeButton.clicked.connect(self.resetPlugin) # Set up for the Run button self.dlg.runButton.clicked.connect(self.start_progress) # Set up extent self.dlg.canvasButton.toggled.connect(self.checkbox_canvas) # self.dlg.layerButton.toggled.connect(self.checkbox_layer) self.layerComboManagerExtent = QgsMapLayerComboBox( self.dlg.widgetLayerExtent) self.layerComboManagerExtent.setCurrentIndex(-1) self.layerComboManagerExtent.layerChanged.connect(self.checkbox_layer) self.layerComboManagerExtent.setFixedWidth(175) # noinspection PyMethodMayBeStatic def tr(self, message): return QCoreApplication.translate('DSMGenerator', message) def add_action(self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.iface.addPluginToMenu(self.menu, action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/DSMGenerator/icon.png' self.add_action(icon_path, text=self.tr(u'DSM Generator'), callback=self.run, parent=self.iface.mainWindow()) def savedsmfile(self): self.DSMoutputfile = self.DSMfileDialog.getSaveFileName( None, "Save File As:", None, "Raster Files (*.tif)") self.dlg.DSMtextOutput.setText(self.DSMoutputfile) def saveosmfile(self): self.OSMoutputfile = self.OSMfileDialog.getSaveFileName( None, "Save File As:", None, "Shapefiles (*.shp)") self.dlg.OSMtextOutput.setText(self.OSMoutputfile) def checkbox_canvas(self): extent = self.iface.mapCanvas().extent() self.dlg.lineEditNorth.setText(str(extent.yMaximum())) self.dlg.lineEditSouth.setText(str(extent.yMinimum())) self.dlg.lineEditWest.setText(str(extent.xMinimum())) self.dlg.lineEditEast.setText(str(extent.xMaximum())) def checkbox_layer(self): dem_layer_extent = self.layerComboManagerExtent.currentLayer() if dem_layer_extent: extent = dem_layer_extent.extent() self.dlg.lineEditNorth.setText(str(extent.yMaximum())) self.dlg.lineEditSouth.setText(str(extent.yMinimum())) self.dlg.lineEditWest.setText(str(extent.xMinimum())) self.dlg.lineEditEast.setText(str(extent.xMaximum())) # Help button def help(self): url = "http://umep-docs.readthedocs.io/en/latest/pre-processor/Spatial%20Data%20DSM%20Generator.html" webbrowser.open_new_tab(url) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for action in self.actions: self.iface.removePluginMenu(self.tr(u'&DSM Generator'), action) # self.iface.removeToolBarIcon(action) # remove the toolbar # del self.toolbar def run(self): self.dlg.show() self.dlg.exec_() def start_progress(self): import datetime start = datetime.datetime.now() # Check OS and dep if sys.platform == 'darwin': gdal_os_dep = '/Library/Frameworks/GDAL.framework/Versions/Current/Programs/' else: gdal_os_dep = '' if self.dlg.canvasButton.isChecked(): # Map Canvas extentCanvasCRS = self.iface.mapCanvas() srs = extentCanvasCRS.mapSettings().destinationCrs() crs = str(srs.authid()) # old_crs = osr.SpatialReference() # old_crs.ImportFromEPSG(int(crs[5:])) can_crs = QgsCoordinateReferenceSystem(int(crs[5:])) # can_wkt = extentCanvasCRS.mapRenderer().destinationCrs().toWkt() # can_crs = osr.SpatialReference() # can_crs.ImportFromWkt(can_wkt) # Raster Layer dem_layer = self.layerComboManagerDEM.currentLayer() dem_prov = dem_layer.dataProvider() dem_path = str(dem_prov.dataSourceUri()) dem_raster = gdal.Open(dem_path) projdsm = osr.SpatialReference(wkt=dem_raster.GetProjection()) projdsm.AutoIdentifyEPSG() projdsmepsg = int(projdsm.GetAttrValue('AUTHORITY', 1)) dem_crs = QgsCoordinateReferenceSystem(projdsmepsg) # dem_wkt = dem_raster.GetProjection() # dem_crs = osr.SpatialReference() # dem_crs.ImportFromWkt(dem_wkt) if can_crs != dem_crs: extentCanvas = self.iface.mapCanvas().extent() extentDEM = dem_layer.extent() transformExt = QgsCoordinateTransform(can_crs, dem_crs) # transformExt = osr.CoordinateTransformation(can_crs, dem_crs) canminx = extentCanvas.xMinimum() canmaxx = extentCanvas.xMaximum() canminy = extentCanvas.yMinimum() canmaxy = extentCanvas.yMaximum() canxymin = transformExt.TransformPoint(canminx, canminy) canxymax = transformExt.TransformPoint(canmaxx, canmaxy) extDiffminx = canxymin[0] - extentDEM.xMinimum( ) # If smaller than zero = warning extDiffminy = canxymin[1] - extentDEM.yMinimum( ) # If smaller than zero = warning extDiffmaxx = canxymax[0] - extentDEM.xMaximum( ) # If larger than zero = warning extDiffmaxy = canxymax[0] - extentDEM.yMaximum( ) # If larger than zero = warning if extDiffminx < 0 or extDiffminy < 0 or extDiffmaxx > 0 or extDiffmaxy > 0: QMessageBox.warning( None, "Warning! Extent of map canvas is larger than raster extent.", "Change to an extent equal to or smaller than the raster extent." ) return # Extent self.yMax = self.dlg.lineEditNorth.text() self.yMin = self.dlg.lineEditSouth.text() self.xMin = self.dlg.lineEditWest.text() self.xMax = self.dlg.lineEditEast.text() if not self.DSMoutputfile: QMessageBox.critical(None, "Error", "Specify a raster output file") return if self.dlg.checkBoxPolygon.isChecked() and not self.OSMoutputfile: QMessageBox.critical(None, "Error", "Specify an output file for OSM data") return # Acquiring geodata and attributes dem_layer = self.layerComboManagerDEM.currentLayer() if dem_layer is None: QMessageBox.critical(None, "Error", "No valid raster layer is selected") return else: provider = dem_layer.dataProvider() filepath_dem = str(provider.dataSourceUri()) demRaster = gdal.Open(filepath_dem) dem_layer_crs = osr.SpatialReference() dem_layer_crs.ImportFromWkt(demRaster.GetProjection()) self.dem_layer_unit = dem_layer_crs.GetAttrValue("UNIT") posUnits = [ 'metre', 'US survey foot', 'meter', 'm', 'ft', 'feet', 'foot', 'ftUS', 'International foot' ] # Possible units if not self.dem_layer_unit in posUnits: QMessageBox.critical( None, "Error", "Raster projection is not in metre or foot. Please reproject.") return polygon_layer = self.layerComboManagerPolygon.currentLayer() osm_layer = self.dlg.checkBoxOSM.isChecked() if polygon_layer is None and osm_layer is False: QMessageBox.critical(None, "Error", "No valid building height layer is selected") return elif polygon_layer: vlayer = QgsVectorLayer(polygon_layer.source(), "buildings", "ogr") fileInfo = QFileInfo(polygon_layer.source()) polygon_ln = fileInfo.baseName() polygon_field = self.layerComboManagerPolygonField.currentField() idx = vlayer.fieldNameIndex(polygon_field) flname = vlayer.attributeDisplayName(idx) if idx == -1: QMessageBox.critical( None, "Error", "An attribute with unique fields must be selected") return ### main code ### self.dlg.progressBar.setRange(0, 5) self.dlg.progressBar.setValue(1) if self.dlg.checkBoxOSM.isChecked(): # TODO replace osr.CoordinateTransformation with QgsCoordinateTransform dem_original = gdal.Open(filepath_dem) dem_wkt = dem_original.GetProjection() ras_crs = osr.SpatialReference() ras_crs.ImportFromWkt(dem_wkt) rasEPSG = ras_crs.GetAttrValue("PROJCS|AUTHORITY", 1) if self.dlg.layerButton.isChecked(): old_crs = ras_crs elif self.dlg.canvasButton.isChecked(): canvasCRS = self.iface.mapCanvas() outputWkt = canvasCRS.mapRenderer().destinationCrs().toWkt() old_crs = osr.SpatialReference() old_crs.ImportFromWkt(outputWkt) wgs84_wkt = """ GEOGCS["WGS 84", DATUM["WGS_1984", SPHEROID["WGS 84",6378137,298.257223563, AUTHORITY["EPSG","7030"]], AUTHORITY["EPSG","6326"]], PRIMEM["Greenwich",0, AUTHORITY["EPSG","8901"]], UNIT["degree",0.01745329251994328, AUTHORITY["EPSG","9122"]], AUTHORITY["EPSG","4326"]]""" new_crs = osr.SpatialReference() new_crs.ImportFromWkt(wgs84_wkt) transform = osr.CoordinateTransformation(old_crs, new_crs) minx = float(self.xMin) miny = float(self.yMin) maxx = float(self.xMax) maxy = float(self.yMax) lonlatmin = transform.TransformPoint(minx, miny) lonlatmax = transform.TransformPoint(maxx, maxy) if ras_crs != old_crs: rasTrans = osr.CoordinateTransformation(old_crs, ras_crs) raslonlatmin = rasTrans.TransformPoint(float(self.xMin), float(self.yMin)) raslonlatmax = rasTrans.TransformPoint(float(self.xMax), float(self.yMax)) #else: #raslonlatmin = [float(self.xMin), float(self.yMin)] #raslonlatmax = [float(self.xMax), float(self.yMax)] self.xMin = raslonlatmin[0] self.yMin = raslonlatmin[1] self.xMax = raslonlatmax[0] self.yMax = raslonlatmax[1] # Make data queries to overpass-api urlStr = 'http://overpass-api.de/api/map?bbox=' + str( lonlatmin[0]) + ',' + str(lonlatmin[1]) + ',' + str( lonlatmax[0]) + ',' + str(lonlatmax[1]) osmXml = urllib.urlopen(urlStr).read() #print urlStr # Make OSM building file osmPath = self.plugin_dir + '/temp/OSM_building.osm' osmFile = open(osmPath, 'w') osmFile.write(osmXml) if os.fstat(osmFile.fileno()).st_size < 1: urlStr = 'http://api.openstreetmap.org/api/0.6/map?bbox=' + str( lonlatmin[0]) + ',' + str(lonlatmin[1]) + ',' + str( lonlatmax[0]) + ',' + str(lonlatmax[1]) osmXml = urllib.urlopen(urlStr).read() osmFile.write(osmXml) #print 'Open Street Map' if os.fstat(osmFile.fileno()).st_size < 1: QMessageBox.critical(None, "Error", "No OSM data available") return osmFile.close() outputshp = self.plugin_dir + '/temp/' osmToShape = gdal_os_dep + 'ogr2ogr --config OSM_CONFIG_FILE "' + self.plugin_dir + '/osmconf.ini" -skipfailures -t_srs EPSG:' + str( rasEPSG ) + ' -overwrite -nlt POLYGON -f "ESRI Shapefile" "' + outputshp + '" "' + osmPath + '"' if sys.platform == 'win32': si = subprocess.STARTUPINFO() si.dwFlags |= subprocess.STARTF_USESHOWWINDOW subprocess.call(osmToShape, startupinfo=si) else: os.system(osmToShape) driver = ogr.GetDriverByName('ESRI Shapefile') driver.DeleteDataSource(outputshp + 'lines.shp') driver.DeleteDataSource(outputshp + 'multilinestrings.shp') driver.DeleteDataSource(outputshp + 'other_relations.shp') driver.DeleteDataSource(outputshp + 'points.shp') osmPolygonPath = outputshp + 'multipolygons.shp' vlayer = QgsVectorLayer(osmPolygonPath, 'multipolygons', 'ogr') polygon_layer = vlayer fileInfo = QFileInfo(polygon_layer.source()) polygon_ln = fileInfo.baseName() def renameField(srcLayer, oldFieldName, newFieldName): ds = gdal.OpenEx(srcLayer.source(), gdal.OF_VECTOR | gdal.OF_UPDATE) ds.ExecuteSQL('ALTER TABLE {} RENAME COLUMN {} TO {}'.format( srcLayer.name(), oldFieldName, newFieldName)) srcLayer.reload() vlayer.startEditing() renameField(vlayer, 'building_l', 'bld_levels') renameField(vlayer, 'building_h', 'bld_hght') renameField(vlayer, 'building_c', 'bld_colour') renameField(vlayer, 'building_m', 'bld_materi') renameField(vlayer, 'building_u', 'bld_use') vlayer.commitChanges() vlayer.startEditing() vlayer.dataProvider().addAttributes( [QgsField('bld_height', QVariant.Double, 'double', 3, 2)]) vlayer.updateFields() bld_lvl = vlayer.fieldNameIndex('bld_levels') hght = vlayer.fieldNameIndex('height') bld_hght = vlayer.fieldNameIndex('bld_hght') bld_height = vlayer.fieldNameIndex('bld_height') bldLvlHght = float(self.dlg.doubleSpinBoxBldLvl.value()) illegal_chars = string.ascii_letters + "!#$%&'*+^_`|~:" + " " counterNone = 0 counter = 0 #counterWeird = 0 for feature in vlayer.getFeatures(): if feature[hght]: try: #feature[bld_height] = float(re.sub("[^0-9]", ".", str(feature[hght]))) feature[bld_height] = float( str(feature[hght]).translate(None, illegal_chars)) except: counterNone += 1 elif feature[bld_hght]: try: #feature[bld_height] = float(re.sub("[^0-9]", ".", str(feature[bld_hght]))) feature[bld_height] = float( str(feature[bld_hght]).translate( None, illegal_chars)) except: counterNone += 1 elif feature[bld_lvl]: try: #feature[bld_height] = float(re.sub("[^0-9]", "", str(feature[bld_lvl])))*bldLvlHght feature[bld_height] = float( str(feature[bld_lvl]).translate( None, illegal_chars)) * bldLvlHght except: counterNone += 1 else: counterNone += 1 vlayer.updateFeature(feature) counter += 1 vlayer.commitChanges() flname = vlayer.attributeDisplayName(bld_height) counterDiff = counter - counterNone # Zonal statistics vlayer.startEditing() zoneStat = QgsZonalStatistics(vlayer, filepath_dem, "stat_", 1, QgsZonalStatistics.Mean) zoneStat.calculateStatistics(None) vlayer.dataProvider().addAttributes( [QgsField('height_asl', QVariant.Double)]) vlayer.updateFields() e = QgsExpression('stat_mean + ' + flname) e.prepare(vlayer.pendingFields()) idx = vlayer.fieldNameIndex('height_asl') for f in vlayer.getFeatures(): f[idx] = e.evaluate(f) vlayer.updateFeature(f) vlayer.commitChanges() vlayer.startEditing() idx2 = vlayer.fieldNameIndex('stat_mean') vlayer.dataProvider().deleteAttributes([idx2]) vlayer.updateFields() vlayer.commitChanges() self.dlg.progressBar.setValue(2) # Convert polygon layer to raster # Define pixel_size and NoData value of new raster pixel_size = self.dlg.spinBox.value() # half picture size # Create the destination data source gdalrasterize = gdal_os_dep + 'gdal_rasterize -a ' + 'height_asl' + ' -te ' + str(self.xMin) + ' ' + str(self.yMin) + ' ' + str(self.xMax) + ' ' + str(self.yMax) +\ ' -tr ' + str(pixel_size) + ' ' + str(pixel_size) + ' -l "' + str(polygon_ln) + '" "' \ + str(polygon_layer.source()) + '" "' + self.plugin_dir + '/temp/clipdsm.tif"' # gdalclipdem = gdal_os_dep + 'gdalwarp -dstnodata -9999 -q -overwrite -te ' + str(self.xMin) + ' ' + str(self.yMin) + ' ' + str(self.xMax) + ' ' + str(self.yMax) +\ # ' -tr ' + str(pixel_size) + ' ' + str(pixel_size) + \ # ' -of GTiff ' + '"' + filepath_dem + '" "' + self.plugin_dir + '/temp/clipdem.tif"' # Rasterize if sys.platform == 'win32': si = subprocess.STARTUPINFO() si.dwFlags |= subprocess.STARTF_USESHOWWINDOW subprocess.call(gdalrasterize, startupinfo=si) # subprocess.call(gdalclipdem, startupinfo=si) gdal.Warp(self.plugin_dir + '/temp/clipdem.tif', filepath_dem, xRes=pixel_size, yRes=pixel_size) else: os.system(gdalrasterize) # os.system(gdalclipdem) gdal.Warp(self.plugin_dir + '/temp/clipdem.tif', filepath_dem, xRes=pixel_size, yRes=pixel_size) # Remove gdalwarp with gdal.Translate # bigraster = gdal.Open(filepath_dem) # bbox = (self.xMin, self.yMax, self.xMax, self.yMin) # gdal.Translate(self.plugin_dir + '/data/clipdem.tif', bigraster, projWin=bbox) self.dlg.progressBar.setValue(3) # Adding DSM to DEM # Read DEM dem_raster = gdal.Open(self.plugin_dir + '/temp/clipdem.tif') dem_array = np.array(dem_raster.ReadAsArray().astype(np.float)) dsm_raster = gdal.Open(self.plugin_dir + '/temp/clipdsm.tif') dsm_array = np.array(dsm_raster.ReadAsArray().astype(np.float)) indx = dsm_array.shape for ix in range(0, int(indx[0])): for iy in range(0, int(indx[1])): if int(dsm_array[ix, iy]) == 0: dsm_array[ix, iy] = dem_array[ix, iy] if self.dlg.checkBoxPolygon.isChecked(): vlayer.startEditing() idxHght = vlayer.fieldNameIndex('height_asl') idxBld = vlayer.fieldNameIndex('building') features = vlayer.getFeatures() #for f in vlayer.getFeatures(): for f in features: geom = f.geometry() posUnitsMetre = ['metre', 'meter', 'm'] # Possible metre units posUnitsFt = [ 'US survey foot', 'ft', 'feet', 'foot', 'ftUS', 'International foot' ] # Possible foot units if self.dem_layer_unit in posUnitsMetre: sqUnit = 1 elif self.dem_layer_unit in posUnitsFt: sqUnit = 10.76 if int(geom.area()) > 50000 * sqUnit: vlayer.deleteFeature(f.id()) #if not f[idxHght]: #vlayer.deleteFeature(f.id()) #elif not f[idxBld]: #vlayer.deleteFeature(f.id()) vlayer.updateFields() vlayer.commitChanges() QgsVectorFileWriter.writeAsVectorFormat(vlayer, str(self.OSMoutputfile), "UTF-8", None, "ESRI Shapefile") else: vlayer.startEditing() idx3 = vlayer.fieldNameIndex('height_asl') vlayer.dataProvider().deleteAttributes([idx3]) vlayer.updateFields() vlayer.commitChanges() self.dlg.progressBar.setValue(4) # Save raster def saveraster( gdal_data, filename, raster ): # gdal_data = raster extent, filename = output filename, raster = numpy array (raster to be saved) rows = gdal_data.RasterYSize cols = gdal_data.RasterXSize outDs = gdal.GetDriverByName("GTiff").Create( filename, cols, rows, int(1), gdal.GDT_Float32) outBand = outDs.GetRasterBand(1) # write the data outBand.WriteArray(raster, 0, 0) # flush data to disk, set the NoData value and calculate stats outBand.FlushCache() outBand.SetNoDataValue(-9999) # georeference the image and set the projection outDs.SetGeoTransform(gdal_data.GetGeoTransform()) outDs.SetProjection(gdal_data.GetProjection()) saveraster(dsm_raster, self.DSMoutputfile, dsm_array) # Load result into canvas rlayer = self.iface.addRasterLayer(self.DSMoutputfile) # Trigger a repaint if hasattr(rlayer, "setCacheImage"): rlayer.setCacheImage(None) rlayer.triggerRepaint() self.dlg.progressBar.setValue(5) #runTime = datetime.datetime.now() - start if self.dlg.checkBoxOSM.isChecked(): QMessageBox.information( self.dlg, 'DSM Generator', 'Operation successful! ' + str(counterDiff) + ' building polygons out of ' + str(counter) + ' contained height values.') #self.iface.messageBar().pushMessage("DSM Generator. Operation successful! " + str(counterDiff) + " buildings out of " + str(counter) + " contained height values.", level=QgsMessageBar.INFO, duration=5) else: #self.iface.messageBar().pushMessage("DSM Generator. Operation successful!", level=QgsMessageBar.INFO, duration=5) QMessageBox.information(self.dlg, 'DSM Generator', 'Operation successful!') self.resetPlugin() #print "finished run: %s\n\n" % (datetime.datetime.now() - start) def resetPlugin(self): # Reset plugin self.dlg.canvasButton.setAutoExclusive(False) self.dlg.canvasButton.setChecked(False) self.dlg.layerButton.setAutoExclusive(False) self.dlg.layerButton.setChecked(False) self.dlg.checkBoxOSM.setCheckState(0) self.dlg.checkBoxPolygon.setCheckState(0) # Extent self.layerComboManagerExtent.setCurrentIndex(-1) self.dlg.lineEditNorth.setText("") self.dlg.lineEditSouth.setText("") self.dlg.lineEditWest.setText("") self.dlg.lineEditEast.setText("") # Output boxes self.dlg.OSMtextOutput.setText("") self.dlg.DSMtextOutput.setText("") # Input raster self.layerComboManagerDEM.setCurrentIndex(-1) # Input polygon self.layerComboManagerPolygon.setCurrentIndex(-1) # Progress bar self.dlg.progressBar.setValue(0) # Spin boxes self.dlg.spinBox.setValue(2) self.dlg.doubleSpinBoxBldLvl.setValue(2.5)
class UAVPreparer: """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'UAVPreparer_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) # Declare instance attributes self.actions = [] self.menu = self.tr(u'&UAV Preparer') # Check if plugin was started the first time in current QGIS session # Must be set in initGui() to survive plugin reloads self.first_start = None # Declare variables self.outputfile = None # noinspection PyMethodMayBeStatic def tr(self, message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('UAVPreparer', message) def add_action(self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): """Add a toolbar icon to the toolbar. :param icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :type icon_path: str :param text: Text that should be shown in menu items for this action. :type text: str :param callback: Function to be called when the action is triggered. :type callback: function :param enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :type enabled_flag: bool :param add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :type add_to_menu: bool :param add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :type add_to_toolbar: bool :param status_tip: Optional text to show in a popup when mouse pointer hovers over the action. :type status_tip: str :param parent: Parent widget for the new action. Defaults None. :type parent: QWidget :param whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.actions list. :rtype: QAction """ icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: # Adds plugin icon to Plugins toolbar self.iface.addToolBarIcon(action) if add_to_menu: self.iface.addPluginToMenu(self.menu, action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/uav_preparer/icon.png' self.add_action(icon_path, text=self.tr(u'UAV Preparer'), callback=self.run, parent=self.iface.mainWindow()) # will be set False in run() self.first_start = True def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for action in self.actions: self.iface.removePluginMenu(self.tr(u'&UAV Preparer'), action) self.iface.removeToolBarIcon(action) def run(self): """Run method that performs all the real work""" # Create the dialog with elements (after translation) and keep reference # Only create GUI ONCE in callback, so that it will only load when the plugin is started if self.first_start == True: self.first_start = False self.dlg = UAVPreparerDialog() # Access the raster layer self.layerComboManagerDSM = QgsMapLayerComboBox(self.dlg.widgetDSM) self.layerComboManagerDSM.setFilters(QgsMapLayerProxyModel.RasterLayer) self.layerComboManagerDSM.setFixedWidth(175) self.layerComboManagerDSM.setCurrentIndex(-1) # Access the vector layer and an attribute field self.layerComboManagerPoint = QgsMapLayerComboBox( self.dlg.widgetPointLayer) self.layerComboManagerPoint.setCurrentIndex(-1) self.layerComboManagerPoint.setFilters( QgsMapLayerProxyModel.PointLayer) self.layerComboManagerPoint.setFixedWidth(175) self.layerComboManagerPointField = QgsFieldComboBox( self.dlg.widgetField) self.layerComboManagerPointField.setFilters(QgsFieldProxyModel.Numeric) self.layerComboManagerPoint.layerChanged.connect( self.layerComboManagerPointField.setLayer) # Set up of file save dialog self.fileDialog = QFileDialog() self.dlg.pushButtonSave.clicked.connect(self.savefile) # Set up for the Help button self.dlg.helpButton.clicked.connect(self.help) # Set up for the Run button self.dlg.runButton.clicked.connect(self.start_progress) # show the dialog self.dlg.show() # Run the dialog event loop result = self.dlg.exec_() # See if OK was pressed if result: # Do something useful here - delete the line containing pass and # substitute with your code. pass def savefile(self): self.outputfile = self.fileDialog.getSaveFileName( None, "Save File As:", None, "Text Files (*.txt)") self.dlg.textOutput.setText(self.outputfile[0]) def help(self): url = "https://github.com/biglimp/UAVPreparer" webbrowser.open_new_tab(url) def start_progress(self): if not self.outputfile: QMessageBox.critical(None, "Error", "Specify an output file") return # Acquiring geodata and attributes dsm_layer = self.layerComboManagerDSM.currentLayer() if dsm_layer is None: QMessageBox.critical(None, "Error", "No valid raster layer is selected") return else: provider = dsm_layer.dataProvider() filepath_dsm = str(provider.dataSourceUri()) point_layer = self.layerComboManagerPoint.currentLayer() if point_layer is None: QMessageBox.critical(None, "Error", "No valid vector point layer is selected") return else: vlayer = QgsVectorLayer(point_layer.source(), "polygon", "ogr") point_field = self.layerComboManagerPointField.currentField() idx = vlayer.fields().indexFromName(point_field) if idx == -1: QMessageBox.critical( None, "Error", "An attribute with unique fields must be selected") return ### main code ### # set radius r = 100 # half picture size numfeat = vlayer.featureCount() result = np.zeros([numfeat, 4]) # load big raster bigraster = gdal.Open(filepath_dsm) filepath_tempdsm = self.plugin_dir + '/clipdsm.tif' self.dlg.progressBar.setRange(0, numfeat) i = 0 for f in vlayer.getFeatures(): self.dlg.progressBar.setValue(i + 1) # get the coordinate for the point y = f.geometry().centroid().asPoint().y() x = f.geometry().centroid().asPoint().x() bbox = (x - r, y + r, x + r, y - r) gdal.Translate(filepath_tempdsm, bigraster, projWin=bbox) data = gdal.Open(filepath_tempdsm) mat = np.array(data.ReadAsArray()) result[i, 0] = int(f.attributes()[idx]) result[i, 1] = np.mean(mat) result[i, 2] = np.max(mat) result[i, 3] = np.min(mat) i = i + 1 # Saving to file numformat = '%d ' + '%6.2f ' * 3 headertext = 'id mean max min' np.savetxt(self.outputfile[0], result, fmt=numformat, delimiter=' ', header=headertext) self.iface.messageBar().pushMessage( 'UAV Preparer. Operation successful!', level=Qgis.Success, duration=5)