Esempio n. 1
0
 def selectDatasource(self):
     """
     Opens dialog for file/directory selection.
     """
     # model of implementation for reimplementation
     fd = QFileDialog()
     fd.setFileMode(QFileDialog.Directory)
     fd.setOption(QFileDialog.ShowDirsOnly, True)
     directory = fd.getExistingDirectory(caption=self.selectionWidget.connectionSelectorLineEdit.caption)
     if directory:
         if len(directory) > 4:
             # datasource connection name for a shape 'database' is its parent folder
             directory = directory if directory[-4:].lower() != '.shp' else directory[:-4]
         # set only directories as line text
         self.selectionWidget.connectionSelectorLineEdit.lineEdit.setText(directory)
     self.selectionWidget.loadDatabase(currentText=directory)
    def upload_data(self):
        if self.check_login():
            if self.local_data_sources.count() == 0:
                return

            if self.db_connections.count() == 0:
                QMessageBox.warning(self, self.tr("No database available"), self.tr("Please create a database in the 'Account' tab."))
                return

            if not self.ui.cbUploadDatabase.currentIndex() >= 0:
                QMessageBox.warning(self, self.tr("No database selected"), self.tr("Please select a database to upload data."))
                return

            db_name = self.ui.cbUploadDatabase.currentText()

            if not self.db_connections.isPortOpen(db_name):
                uri = self.db_connections.cloud_layer_uri(db_name, "", "")
                host = str(uri.host())
                port = uri.port()
                QMessageBox.critical(self, self.tr("Network Error"),
                                     self.tr("Could not connect to database server ({0}) on port {1}. Please contact your system administrator or internet provider to open port {1} in the firewall".format(host, port)))
                return

            # disable update of local data sources during upload, as there are
            # temporary layers added and removed
            self.do_update_local_data_sources = False
            self.statusBar().showMessage(self.tr("Uploading data..."))
            self.setCursor(Qt.WaitCursor)
            self.ui.btnUploadData.hide()
            self.ui.spinner.start()
            self.ui.progressWidget.show()

            # Map<data_source, {table: table, layers: layers}>
            data_sources_items = {}
            for row in range(0, self.ui.tblLocalLayers.rowCount()):
                data_source = unicode(
                    self.ui.tblLocalLayers.item(
                        row, self.COLUMN_DATA_SOURCE).text())
                layers = self.local_data_sources.layers(data_source)
                if layers is not None:
                    table_name = unicode(
                        self.ui.tblLocalLayers.item(
                            row, self.COLUMN_TABLE_NAME).text())
                    data_sources_items[data_source] = {
                        u'table': unicode(table_name), u'layers': layers}

            login_info = self.api.check_login(version_info=self._version_info())
            try:            
                self.maxSize = login_info['max_storage']
                self.maxDBs = login_info['max_dbs']
            except:
                self.maxSize = 50
                self.maxDBs = 5

            try:
                self.data_upload.upload(self.db_connections.db(unicode(db_name)), data_sources_items, unicode(self.maxSize))
                upload_ok = True
            except Exception as e:
                ErrorReportDialog(self.tr("Upload errors occurred"), self.tr("Upload errors occurred. Not all data could be uploaded."), str(e) + "\n" + traceback.format_exc(), self.user, self).exec_()
                upload_ok = False

            self.ui.spinner.stop()
            self.ui.progressWidget.hide()
            self.ui.btnUploadData.show()
            self.unsetCursor()
            self.statusBar().showMessage("")
            # Refresh local layers
            self.do_update_local_data_sources = True
            self.update_local_layers()
            # Refresh used space after upload
            self.db_size(self.db_connections)

            if upload_ok:
                # Show save project dialog
                save_dialog = QDialog(self)
                save_dialog.setWindowTitle(self.tr("Save Project"))
                save_dialog.setLayout(QVBoxLayout())
                header = QWidget()
                header.setLayout(QVBoxLayout())
                label = QLabel(self.tr("Upload complete. The local layers in the project were replaced with the layers uploaded to the qgiscloud database."))
                label.setWordWrap(True)
                header.layout().addWidget(label)
                label = QLabel(self.tr("Choose were to save the modified project:"))
                label.setWordWrap(True)
                header.layout().addWidget(label)
                save_dialog.layout().setContentsMargins(0, 0, 0, 0)
                save_dialog.layout().addWidget(header)
                initialPath = QgsProject.instance().fileName()
                if not initialPath:
                    initialPath = QSettings().value("/UI/lastProjectDir", ".")
                fd = QFileDialog(None, self.tr("Save Project"), initialPath, "%s (*.qgz *.qgs)" % self.tr("QGIS Project Files"))
                fd.setParent(save_dialog, Qt.Widget)
                fd.setOption(QFileDialog.DontUseNativeDialog)
                fd.setAcceptMode(QFileDialog.AcceptSave)
                save_dialog.layout().addWidget(fd)
                header.layout().setContentsMargins(fd.layout().contentsMargins())
                fd.accepted.connect(save_dialog.accept)
                fd.rejected.connect(save_dialog.reject)
                if save_dialog.exec_() == QDialog.Accepted:
                    files = list(fd.selectedFiles())
                    if files:
                        QgsProject.instance().setFileName(files[0])
                        self.iface.actionSaveProject().trigger()

                # Switch to map tab
                self.ui.tabWidget.setCurrentWidget(self.ui.mapTab)
Esempio n. 3
0
class TreeGenerator(object):
    """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',
            'TreeGenerator_{}.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 = TreeGeneratorDialog()
        self.dlg.runButton.clicked.connect(self.start_progress)
        self.dlg.pushButtonSave.clicked.connect(self.folder_path)
        self.dlg.helpButton.clicked.connect(self.help)

        self.fileDialog = QFileDialog()
        # self.fileDialog.setFileMode(4)
        # self.fileDialog.setAcceptMode(1)
        self.fileDialog.setFileMode(QFileDialog.Directory)
        self.fileDialog.setOption(QFileDialog.ShowDirsOnly, True)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&Tree Generator')
        # TODO: We are going to let the user set this up in a future iteration
        # self.toolbar = self.iface.addToolBar(u'TreeGenerator')
        # self.toolbar.setObjectName(u'TreeGenerator')

        # self.layerComboManagerPoint = VectorLayerCombo(self.dlg.comboBox_pointlayer)
        # fieldgen = VectorLayerCombo(self.dlg.comboBox_pointlayer, initLayer="", options={"geomType": QGis.Point})
        # self.layerComboManagerTreeTypeField = FieldCombo(self.dlg.comboBox_ttype, fieldgen, initField="")
        # self.layerComboManagerTotalHeightField = FieldCombo(self.dlg.comboBox_totalheight, fieldgen, initField="")
        # self.layerComboManagerTrunkHeightField = FieldCombo(self.dlg.comboBox_trunkheight, fieldgen, initField="")
        # self.layerComboManagerDiameterField = FieldCombo(self.dlg.comboBox_diameter, fieldgen, initField="")
        self.layerComboManagerPoint = QgsMapLayerComboBox(self.dlg.widgetPointLayer)
        self.layerComboManagerPoint.setCurrentIndex(-1)
        self.layerComboManagerPoint.setFilters(QgsMapLayerProxyModel.PointLayer)
        self.layerComboManagerPoint.setFixedWidth(175)
        self.layerComboManagerTreeTypeField = QgsFieldComboBox(self.dlg.widgetTreeType)
        self.layerComboManagerTreeTypeField.setFilters(QgsFieldProxyModel.Numeric)
        self.layerComboManagerPoint.layerChanged.connect(self.layerComboManagerTreeTypeField.setLayer)
        self.layerComboManagerTotalHeightField = QgsFieldComboBox(self.dlg.widgetTotalHeight)
        self.layerComboManagerTotalHeightField.setFilters(QgsFieldProxyModel.Numeric)
        self.layerComboManagerPoint.layerChanged.connect(self.layerComboManagerTotalHeightField.setLayer)
        self.layerComboManagerTrunkHeightField = QgsFieldComboBox(self.dlg.widgetTrunkHeight)
        self.layerComboManagerTrunkHeightField.setFilters(QgsFieldProxyModel.Numeric)
        self.layerComboManagerPoint.layerChanged.connect(self.layerComboManagerTrunkHeightField.setLayer)
        self.layerComboManagerDiameterField = QgsFieldComboBox(self.dlg.widgetDiameter)
        self.layerComboManagerDiameterField.setFilters(QgsFieldProxyModel.Numeric)
        self.layerComboManagerPoint.layerChanged.connect(self.layerComboManagerDiameterField.setLayer)

        # self.layerComboManagerDSM = RasterLayerCombo(self.dlg.comboBox_DSM)
        # RasterLayerCombo(self.dlg.comboBox_DSM, initLayer="")
        # self.layerComboManagerDEM = RasterLayerCombo(self.dlg.comboBox_DEM)
        # RasterLayerCombo(self.dlg.comboBox_DEM, initLayer="")
        # self.layerComboManagerBuild = RasterLayerCombo(self.dlg.comboBox_Build)
        # RasterLayerCombo(self.dlg.comboBox_Build, initLayer="")
        # self.layerComboManagerCDSM = RasterLayerCombo(self.dlg.comboBox_CDSM)
        # RasterLayerCombo(self.dlg.comboBox_CDSM, initLayer="")
        # self.layerComboManagerTDSM = RasterLayerCombo(self.dlg.comboBox_TDSM)
        # RasterLayerCombo(self.dlg.comboBox_TDSM, initLayer="")
        self.layerComboManagerDSM = QgsMapLayerComboBox(self.dlg.widgetDSM)
        self.layerComboManagerDSM.setFilters(QgsMapLayerProxyModel.RasterLayer)
        self.layerComboManagerDSM.setFixedWidth(175)
        self.layerComboManagerDSM.setCurrentIndex(-1)
        self.layerComboManagerDEM = QgsMapLayerComboBox(self.dlg.widgetDEM)
        self.layerComboManagerDEM.setFilters(QgsMapLayerProxyModel.RasterLayer)
        self.layerComboManagerDEM.setFixedWidth(175)
        self.layerComboManagerDEM.setCurrentIndex(-1)
        self.layerComboManagerBuild = QgsMapLayerComboBox(self.dlg.widgetBuild)
        self.layerComboManagerBuild.setFilters(QgsMapLayerProxyModel.RasterLayer)
        self.layerComboManagerBuild.setFixedWidth(175)
        self.layerComboManagerBuild.setCurrentIndex(-1)
        self.layerComboManagerCDSM = QgsMapLayerComboBox(self.dlg.widgetCDSM)
        self.layerComboManagerCDSM.setFilters(QgsMapLayerProxyModel.RasterLayer)
        self.layerComboManagerCDSM.setFixedWidth(175)
        self.layerComboManagerCDSM.setCurrentIndex(-1)
        self.layerComboManagerTDSM = QgsMapLayerComboBox(self.dlg.widgetTDSM)
        self.layerComboManagerTDSM.setFilters(QgsMapLayerProxyModel.RasterLayer)
        self.layerComboManagerTDSM.setFixedWidth(175)
        self.layerComboManagerTDSM.setCurrentIndex(-1)

    # 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('TreeGenerator', 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):

        # Create the dialog (after translation) and keep reference
        self.dlg = TreeGeneratorDialog()

        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/TreeGenerator/icon.png'
        self.add_action(
            icon_path,
            text=self.tr(u''),
            callback=self.run,
            parent=self.iface.mainWindow())


    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(
                self.tr(u'&Tree Generator'),
                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
        self.dlg.exec_()

        gdal.UseExceptions()
        gdal.AllRegister()

    def folder_path(self):
        self.fileDialog.open()
        result = self.fileDialog.exec_()
        if result == 1:
            self.folderPath = self.fileDialog.selectedFiles()
            self.dlg.textOutput.setText(self.folderPath[0])

    def start_progress(self):
        self.steps = 0
        point = self.layerComboManagerPoint.currentLayer()
        if point is None:
            QMessageBox.critical(self.dlg, "Error", "No valid Point layer is selected")
            return

        if self.dlg.checkBoxOnlyBuilding.isChecked():  # Only building heights
            build = self.layerComboManagerBuild.currentLayer()
            dsm = None
            dem = None
            if build is None:
                QMessageBox.critical(self.dlg, "Error", "No valid building raster layer is selected")
                return

            provider = build.dataProvider()
            filePath_build = str(provider.dataSourceUri())
            dataset = gdal.Open(filePath_build)
            build_array = dataset.ReadAsArray().astype(np.float)

        else:  # Both building ground heights
            dsm = self.layerComboManagerDSM.currentLayer()
            dem = self.layerComboManagerDEM.currentLayer()
            build = None
            if dsm is None:
                QMessageBox.critical(self.dlg, "Error", "No valid ground and building DSM raster layer is selected")
                return
            if dem is None:
                QMessageBox.critical(self.dlg, "Error", "No valid ground DEM raster layer is selected")
                return

            provider = dsm.dataProvider()
            filePath_dsm = str(provider.dataSourceUri())
            provider = dem.dataProvider()
            filePath_dem = str(provider.dataSourceUri())

            dataset = gdal.Open(filePath_dsm)
            dsm_array = dataset.ReadAsArray().astype(np.float)
            dataset2 = gdal.Open(filePath_dem)
            dem_array = dataset2.ReadAsArray().astype(np.float)

            if not (dsm_array.shape[0] == dem_array.shape[0]) & (dsm_array.shape[1] == dem_array.shape[1]):
                QMessageBox.critical(self.dlg, "Error", "All grids must be of same pixel resolution")
                return

            build_array = dsm_array - dem_array
            build_array[build_array < 2.] = 1.
            build_array[build_array >= 2.] = 0.

        sizey = build_array.shape[0]
        sizex = build_array.shape[1]

        if self.dlg.checkBoxMergeCDSM.isChecked():  # vegetation cdsm
            cdsm = self.layerComboManagerCDSM.currentLayer()
            if cdsm is None:
                QMessageBox.critical(self.dlg, "Error", "No valid vegetation CDSM raster layer is selected")
                return

            provider = cdsm.dataProvider()
            filePath_cdsm = str(provider.dataSourceUri())

            dataset = gdal.Open(filePath_cdsm)
            cdsm_array = dataset.ReadAsArray().astype(np.float)
            tdsm = self.layerComboManagerCDSM.currentLayer()
            if tdsm is None:
                QMessageBox.critical(self.dlg, "Error", "No valid vegetation TDSM raster layer is selected")
                return

            provider = tdsm.dataProvider()
            filePath_tdsm = str(provider.dataSourceUri())

            dataset = gdal.Open(filePath_tdsm)
            tdsm_array = dataset.ReadAsArray().astype(np.float)

        else:
            cdsm_array = np.zeros((sizey, sizex))
            tdsm_array = np.zeros((sizey, sizex))

        geotransform = dataset.GetGeoTransform()
        scale = 1 / geotransform[1]
        # nd = dataset.GetRasterBand(1).GetNoDataValue()
        # dem_array = np.zeros((sizex, sizey))

        # Get attributes
        vlayer = QgsVectorLayer(point.source(), "point", "ogr")
        # prov = vlayer.dataProvider()
        # fields = prov.fields()

        ttype_field = self.layerComboManagerTreeTypeField.currentField()
        trunk_field = self.layerComboManagerTrunkHeightField.currentField()
        tot_field = self.layerComboManagerTotalHeightField.currentField()
        dia_field = self.layerComboManagerDiameterField.currentField()

        # idx_ttype = vlayer.fieldNameIndex(ttype_field)
        # idx_trunk = vlayer.fieldNameIndex(trunk_field)
        # idx_tot = vlayer.fieldNameIndex(tot_field)
        # idx_dia = vlayer.fieldNameIndex(dia_field)
        idx_ttype = vlayer.fields().indexFromName(ttype_field)
        idx_trunk = vlayer.fields().indexFromName(trunk_field)
        idx_tot = vlayer.fields().indexFromName(tot_field)
        idx_dia = vlayer.fields().indexFromName(dia_field)

        if self.folderPath == 'None':
            QMessageBox.critical(self.dlg, "Error", "Select a valid output folder")
            return

        numfeat = vlayer.featureCount()
        width = dataset.RasterXSize
        height = dataset.RasterYSize
        minx = geotransform[0]
        miny = geotransform[3] + width * geotransform[4] + height * geotransform[5]
        rows = build_array.shape[0]
        cols = build_array.shape[1]

        self.dlg.progressBar.setRange(0, numfeat)
        index = 0
        # Main loop
        for f in vlayer.getFeatures():  # looping through each grid polygon

            # self.dlg.progressBar.setValue(0)
            index = index + 1
            self.dlg.progressBar.setValue(index)

            attributes = f.attributes()
            geometry = f.geometry()
            feature = QgsFeature()
            feature.setAttributes(attributes)
            feature.setGeometry(geometry)

            y = f.geometry().centroid().asPoint().y()
            x = f.geometry().centroid().asPoint().x()
            ttype = f.attributes()[idx_ttype]
            trunk = f.attributes()[idx_trunk]
            height = f.attributes()[idx_tot]
            dia = f.attributes()[idx_dia]
            cola = np.round((x - minx) * scale)
            rowa = np.round((miny + rows / scale - y) * scale)

            # QMessageBox.information(None, "scale=", str(scale))
            # QMessageBox.information(None, "x=", str(x))
            # QMessageBox.information(None, "y=", str(y))
            # QMessageBox.information(None, "minx=", str(minx))
            # QMessageBox.information(None, "miny=", str(miny))
            # QMessageBox.information(None, "cola=", str(cola))
            # QMessageBox.information(None, "rowa=", str(rowa))
            # QMessageBox.information(None, "rows=", str(rows))

            cdsm_array, tdsm_array = makevegdems.vegunitsgeneration(build_array, cdsm_array, tdsm_array, ttype, height,
                                                                    trunk, dia, rowa, cola, sizex, sizey, scale)

        # temporary fix for mac, ISSUE #15
        pf = sys.platform
        if pf == 'darwin' or pf == 'linux2':
            if not os.path.exists(self.folderPath[0]):
                os.makedirs(self.folderPath[0])

        self.saveraster(dataset, self.folderPath[0] + '/cdsm.tif', cdsm_array)
        self.saveraster(dataset, self.folderPath[0] + '/tdsm.tif', tdsm_array)

        QMessageBox.information(self.dlg, "TreeGenerator", "Vegetation DSMs succesfully generated")

    def help(self):
        url = "https://umep-docs.readthedocs.io/en/latest/pre-processor/Spatial%20Data%20Tree%20Generator.html"
        webbrowser.open_new_tab(url)

    def saveraster(self, gdal_data, filename, raster):
        rows = gdal_data.RasterYSize
        cols = gdal_data.RasterXSize

        outDs = gdal.GetDriverByName("GTiff").Create(filename, cols, rows, int(1), 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())
    def upload_data(self):
        if self.check_login():
            if self.local_data_sources.count() == 0:
                return

            if self.db_connections.count() == 0:
                QMessageBox.warning(self, self.tr("No database available"), self.tr("Please create a database in the 'Account' tab."))
                return

            if not self.ui.cbUploadDatabase.currentIndex() >= 0:
                QMessageBox.warning(self, self.tr("No database selected"), self.tr("Please select a database to upload data."))
                return

            db_name = self.ui.cbUploadDatabase.currentText()

            if not self.db_connections.isPortOpen(db_name):
                uri = self.db_connections.cloud_layer_uri(db_name, "", "")
                host = str(uri.host())
                port = uri.port()
                QMessageBox.critical(self, self.tr("Network Error"),
                                     self.tr("Could not connect to database server ({0}) on port {1}. Please contact your system administrator or internet provider to open port {1} in the firewall".format(host, port)))
                return

            # disable update of local data sources during upload, as there are
            # temporary layers added and removed
            self.do_update_local_data_sources = False
            self.statusBar().showMessage(self.tr("Uploading data..."))
            self.setCursor(Qt.WaitCursor)
            self.ui.btnUploadData.hide()
            self.ui.spinner.start()
            self.ui.progressWidget.show()

            # Map<data_source, {schema: schema, table: table, layers: layers}>
            data_sources_items = {}
            for row in range(0, self.ui.tblLocalLayers.rowCount()):
                data_source = unicode(
                    self.ui.tblLocalLayers.item(
                        row, self.COLUMN_DATA_SOURCE).text())
                layers = self.local_data_sources.layers(data_source)
                if layers is not None:
                    schema_name = unicode(
                        self.ui.tblLocalLayers.cellWidget(
                            row, self.COLUMN_SCHEMA_NAME).currentText())                    
                    table_name = unicode(
                        self.ui.tblLocalLayers.item(
                            row, self.COLUMN_TABLE_NAME).text())
                    data_sources_items[data_source] = {
                        u'schema': unicode(schema_name), u'table': unicode(table_name), u'layers': layers}

            login_info = self.api.check_login(version_info=self._version_info())
            try:            
                self.maxSize = login_info['max_storage']
                self.maxDBs = login_info['max_dbs']
            except:
                self.maxSize = 50
                self.maxDBs = 5

            try:
                self.data_upload.upload(self.db_connections.db(unicode(db_name)), data_sources_items, unicode(self.maxSize))
                upload_ok = True
            except Exception as e:
                ErrorReportDialog(self.tr("Upload errors occurred"), self.tr("Upload errors occurred. Not all data could be uploaded."), str(e) + "\n" + traceback.format_exc(), self.user, self).exec_()
                upload_ok = False

            self.ui.spinner.stop()
            self.ui.progressWidget.hide()
            self.ui.btnUploadData.show()
            self.unsetCursor()
            self.statusBar().showMessage("")
            # Refresh local layers
            self.do_update_local_data_sources = True
            self.update_local_layers()
            # Refresh used space after upload
            self.db_size(self.db_connections)

            if upload_ok:
                # Show save project dialog
                save_dialog = QDialog(self)
                save_dialog.setWindowTitle(self.tr("Save Project"))
                save_dialog.setLayout(QVBoxLayout())
                header = QWidget()
                header.setLayout(QVBoxLayout())
                label = QLabel(self.tr("Upload complete. The local layers in the project were replaced with the layers uploaded to the qgiscloud database."))
                label.setWordWrap(True)
                header.layout().addWidget(label)
                label = QLabel(self.tr("Choose were to save the modified project:"))
                label.setWordWrap(True)
                header.layout().addWidget(label)
                save_dialog.layout().setContentsMargins(0, 0, 0, 0)
                save_dialog.layout().addWidget(header)
                initialPath = QgsProject.instance().fileName()
                if not initialPath:
                    initialPath = QSettings().value("/UI/lastProjectDir", ".")
                fd = QFileDialog(None, self.tr("Save Project"), initialPath, "%s (*.qgz *.qgs)" % self.tr("QGIS Project Files"))
                fd.setParent(save_dialog, Qt.Widget)
                fd.setOption(QFileDialog.DontUseNativeDialog)
                fd.setAcceptMode(QFileDialog.AcceptSave)
                save_dialog.layout().addWidget(fd)
                header.layout().setContentsMargins(fd.layout().contentsMargins())
                fd.accepted.connect(save_dialog.accept)
                fd.rejected.connect(save_dialog.reject)
                if save_dialog.exec_() == QDialog.Accepted:
                    files = list(fd.selectedFiles())
                    if files:
                        QgsProject.instance().setFileName(files[0])
                        self.iface.actionSaveProject().trigger()

                # Switch to map tab
                self.ui.tabWidget.setCurrentWidget(self.ui.mapTab)
Esempio n. 5
0
class PotentialSlopeFailure(object):
    """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',
            'PotentialSlopeFailure_{}.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)

        self.dlg = PotentialSlopeFailureDialog(self.iface)
        self.dlg.runButton.clicked.connect(self.start_progress)
        self.dlg.pushButtonHelp.clicked.connect(self.help)
        self.dlg.pushButtonSave.clicked.connect(self.folder_path)
        self.fileDialog = QFileDialog()
        self.fileDialog.setFileMode(QFileDialog.Directory)
        self.fileDialog.setOption(QFileDialog.ShowDirsOnly, True)

        # Declare instance attributes
        #self.actions = []
        #self.menu = self.tr(u'&Potential Slope Failure')
        # TODO: We are going to let the user set this up in a future iteration
        #self.toolbar = self.iface.addToolBar(u'PotentialSlopeFailure')
        #self.toolbar.setObjectName(u'PotentialSlopeFailure')

        # self.layerComboManagerDEM = RasterLayerCombo(self.dlg.comboBoxDem)
        # RasterLayerCombo(self.dlg.comboBoxDem, initLayer="")
        # self.layerComboManagerSOIL = RasterLayerCombo(self.dlg.comboBoxSoil)
        # RasterLayerCombo(self.dlg.comboBoxSoil, initLayer="")
        self.layerComboManagerDEM = QgsMapLayerComboBox(self.dlg.widgetDEM)
        self.layerComboManagerDEM.setFilters(QgsMapLayerProxyModel.RasterLayer)
        self.layerComboManagerDEM.setFixedWidth(175)
        self.layerComboManagerSOIL = QgsMapLayerComboBox(self.dlg.widgetSOIL)
        self.layerComboManagerSOIL.setFilters(
            QgsMapLayerProxyModel.RasterLayer)
        self.layerComboManagerSOIL.setFixedWidth(175)
        self.folderPath = '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('PotentialSlopeFailure', 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 = PotentialSlopeFailureDialog()
    #
    #     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 action that will start plugin configuration
        self.action = QAction(
            QIcon(':/plugins/PotentialSlopeFailure/slopeicon.png'),
            'Calculates areas prone to slope failures in cohesive soils',
            self.iface.mainWindow())
        # connect the action to the run method
        self.action.triggered.connect(self.run)

        # Add toolbar button and menu item
        self.iface.addToolBarIcon(self.action)
        self.iface.addPluginToMenu(self.tr("&Potential Slope Failure"),
                                   self.action)

        #"""Create the menu entries and toolbar icons inside the QGIS GUI."""
        #
        #icon_path = ':/plugins/PotentialSlopeFailure/icon.png'
        #self.add_action(
        #    icon_path,
        #   text=self.tr(u'Calculates areas prone to slope failures in cohesive soils'),
        #   callback=self.run,
        #   parent=self.iface.mainWindow())

    def unload(self):
        # Remove the plugin menu item and icon
        self.iface.removePluginMenu("&Potential Slope Failure", self.action)
        self.iface.removeToolBarIcon(self.action)
        # """Removes the plugin menu item and icon from QGIS GUI."""
        # for action in self.actions: self.iface.removePluginMenu(
        #         self.tr(u'&Potential Slope Failure'),
        #         action)
        #     self.iface.removeToolBarIcon(action)
        # remove the toolbar
        # del self.toolbar

    def run(self):
        self.dlg.show()
        self.dlg.exec_()

    def folder_path(self):
        self.fileDialog.open()
        result = self.fileDialog.exec_()
        if result == 1:
            self.folderPath = self.fileDialog.selectedFiles()
            self.dlg.textOutput.setText(self.folderPath[0])

    def start_progress(self):
        if self.folderPath == 'None':
            QMessageBox.critical(None, "Error", "Select a valid output folder")
            return

        # Load DEM
        demlayer = self.layerComboManagerDEM.currentLayer()

        if demlayer is None:
            QMessageBox.critical(None, "Error",
                                 "No valid DEM raster layer is selected")
            return

        provider = demlayer.dataProvider()
        filepath_dem = str(provider.dataSourceUri())

        gdal_dem = gdal.Open(filepath_dem)

        dem = gdal_dem.ReadAsArray().astype(np.float)
        sizex = dem.shape[0]
        sizey = dem.shape[1]

        geotransform = gdal_dem.GetGeoTransform()
        scale = 1 / geotransform[1]

        # Load Soil
        soillayer = self.layerComboManagerSOIL.currentLayer()

        if soillayer is None:
            QMessageBox.critical(None, "Error",
                                 "No valid Soil raster selected")
            return

        # load raster
        gdal.AllRegister()
        provider = soillayer.dataProvider()
        filePathOld = str(provider.dataSourceUri())
        dataSet = gdal.Open(filePathOld)
        soil = dataSet.ReadAsArray().astype(np.float)

        soilsizex = soil.shape[0]
        soilsizey = soil.shape[1]

        if not (soilsizex == sizex) & (soilsizey == sizey):
            QMessageBox.critical(
                None, "Error",
                "The grids must be of same extent and resolution")
            return

        itera = int(360 / self.dlg.spinBoxIter.value())
        alt = self.dlg.spinBoxAlt.value()
        shtot = np.zeros((sizex, sizey))
        index = 0

        # Inverting dem
        dem = dem * (-1.) + np.max(dem)

        self.dlg.progressBar.setRange(0, self.dlg.spinBoxIter.value())

        for i in range(0, self.dlg.spinBoxIter.value()):
            azi = itera * i
            self.dlg.progressBar.setValue(i + 1)
            # self.iface.messageBar().pushMessage("ShadowGenerator", str(azi))
            sh = shadow.shadowingfunctionglobalradiation(
                dem, azi, alt, scale, self.dlg, 1)
            shtot = shtot + sh
            index += 1

        zon1 = shtot / index

        zon1[zon1 == 1] = 2
        zon1[zon1 < 1] = 1
        karta1a = zon1 * soil
        karta1a[karta1a == 0] = 3

        filename = self.folderPath[0] + '/map1a.tif'
        self.saveraster(gdal_dem, filename, karta1a)

        # load result into canvas
        if self.dlg.checkBoxIntoCanvas.isChecked():
            rlayer = self.iface.addRasterLayer(filename)

            # Trigger a repaint
            if hasattr(rlayer, "setCacheImage"):
                rlayer.setCacheImage(None)
            rlayer.triggerRepaint()

            rlayer.loadNamedStyle(self.plugin_dir + '/misc/map1a.qml')

            if hasattr(rlayer, "setCacheImage"):
                rlayer.setCacheImage(None)
            rlayer.triggerRepaint()

        self.dlg.progressBar.setValue(0)

        QMessageBox.information(
            self.dlg, "Calculation done!",
            "Output (map1a.tif) created in: " + self.folderPath[0] + "/")

    def help(self):
        url = "https://github.com/biglimp/PotentialSlopeFailure/wiki/Potential-Slope-Failure-plugin-for-QGIS"
        webbrowser.open_new_tab(url)

    def saveraster(self, gdal_data, filename, raster):
        rows = gdal_data.RasterYSize
        cols = gdal_data.RasterXSize

        outDs = gdal.GetDriverByName("GTiff").Create(filename, cols, rows,
                                                     int(1), 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())