def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        algRunner = AlgRunner()
        inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context)
        if inputLyr is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))
        onlySelected = self.parameterAsBool(parameters, self.SELECTED, context)
        multiStepFeedback = QgsProcessingMultiStepFeedback(2, feedback)
        multiStepFeedback.setCurrentStep(0)
        multiStepFeedback.pushInfo(
            self.tr(
                'Identifying duplicated geometries in layer {0}...').format(
                    inputLyr.name()))
        flagLyr = algRunner.runIdentifyDuplicatedGeometries(
            inputLyr,
            context,
            feedback=multiStepFeedback,
            onlySelected=onlySelected)

        multiStepFeedback.setCurrentStep(1)
        multiStepFeedback.pushInfo(
            self.tr('Removing duplicated geometries in layer {0}...').format(
                inputLyr.name()))
        self.removeFeatures(inputLyr, flagLyr, multiStepFeedback)

        return {self.OUTPUT: inputLyr}
예제 #2
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        layerHandler = LayerHandler()
        algRunner = AlgRunner()
        inputPolygonLyrList = self.parameterAsLayerList(
            parameters, self.INPUT_POLYGONS, context)
        constraintLineLyrList = self.parameterAsLayerList(
            parameters, self.CONSTRAINT_LINE_LAYERS, context)
        constraintPolygonLyrList = self.parameterAsLayerList(
            parameters, self.CONSTRAINT_POLYGON_LAYERS, context)
        if set(constraintPolygonLyrList).intersection(
                set(inputPolygonLyrList)):
            raise QgsProcessingException(
                self.
                tr('Input polygon layers must not be in constraint polygon list.'
                   ))
        onlySelected = self.parameterAsBool(parameters, self.SELECTED, context)
        boundaryLyr = self.parameterAsLayer(parameters,
                                            self.GEOGRAPHIC_BOUNDARY, context)
        # Compute the number of steps to display within the progress bar and
        # get features from source
        # alg steps:
        # 1- Build single polygon layer
        # 2- Compute center points
        # 3- Compute boundaries
        multiStepFeedback = QgsProcessingMultiStepFeedback(3, feedback)
        multiStepFeedback.setCurrentStep(0)
        multiStepFeedback.pushInfo(self.tr('Building single polygon layer'))
        singlePolygonLayer = layerHandler.getMergedLayer(
            inputPolygonLyrList,
            onlySelected=onlySelected,
            feedback=multiStepFeedback,
            context=context,
            algRunner=algRunner)
        multiStepFeedback.setCurrentStep(1)
        (output_center_point_sink,
         output_center_point_sink_id) = self.parameterAsSink(
             parameters, self.OUTPUT_CENTER_POINTS, context,
             singlePolygonLayer.fields(), QgsWkbTypes.Point,
             singlePolygonLayer.sourceCrs())
        (output_boundaries_sink,
         output_boundaries_sink_id) = self.parameterAsSink(
             parameters, self.OUTPUT_BOUNDARIES, context, QgsFields(),
             QgsWkbTypes.LineString, singlePolygonLayer.sourceCrs())
        layerHandler.getCentroidsAndBoundariesFromPolygons(
            singlePolygonLayer,
            output_center_point_sink,
            output_boundaries_sink,
            constraintLineLyrList=constraintLineLyrList,
            constraintPolygonLyrList=constraintPolygonLyrList,
            context=context,
            feedback=multiStepFeedback,
            algRunner=algRunner)

        return {
            self.OUTPUT_CENTER_POINTS: output_center_point_sink_id,
            self.OUTPUT_BOUNDARIES: output_boundaries_sink_id
        }
예제 #3
0
 def make_inventory_from_processing(self,
                                    parent_folder,
                                    format_list,
                                    destination_folder=None,
                                    make_copy=False,
                                    onlyGeo=True,
                                    feedback=None):
     featList = []
     fileList = []
     format_set = self.get_format_set(format_list)
     tuple_list = [i for i in os.walk(parent_folder)]
     nSteps = len(tuple_list) if make_copy else len(tuple_list) - 1
     multiStepFeedback = QgsProcessingMultiStepFeedback(
         nSteps, feedback) if feedback else None
     for current_step, [root, dirs, files] in enumerate(tuple_list):
         if feedback is not None:
             if feedback.isCanceled():
                 return []
             multiStepFeedback.setCurrentStep(current_step)
         n_files = len(files)
         files_progress = 100 / n_files if n_files else 0
         for current, current_file in enumerate(files):
             if multiStepFeedback is not None and multiStepFeedback.isCanceled(
             ):
                 break
             extension = current_file.split('.')[-1]
             if extension not in format_set:
                 continue
             full_path = self.get_full_path(current_file, root)
             if gdal.Open(full_path) or ogr.Open(full_path):
                 bbox_geom, attributes = self.computeBoxAndAttributes(
                     None, full_path, extension, insertIntoMemory=False)
                 new_feat = self.get_new_feat(bbox_geom, attributes)
                 featList.append(new_feat)
                 fileList.append(full_path)
             if multiStepFeedback is not None:
                 multiStepFeedback.setProgress(files_progress * current)
     if make_copy:
         if multiStepFeedback is not None:
             multiStepFeedback.setCurrentStep(nSteps)
         copy_len = len(fileList)
         for current, file_ in fileList:
             if multiStepFeedback is not None and multiStepFeedback.isCanceled:
                 break
             try:
                 self.copy_single_file(file_, destination_folder)
                 if multiStepFeedback is not None:
                     multiStepFeedback.pushInfo(
                         self.tr(
                             'File {file} copied to {destination}').format(
                                 file=file_,
                                 destination=destination_folder))
             except Exception as e:
                 if multiStepFeedback is not None:
                     multiStepFeedback.pushInfo(
                         self.tr('Error copying file {file}: {exception}\n'
                                 ).format(file=file_,
                                          exception='\n'.join(e.args)))
     return featList
    def processAlgorithm(self, parameters, context, feedback):
        communes = self.parameterAsString(parameters, self.LISTE_CODE_INSEE,
                                          context)
        filtre = self.parameterAsString(parameters, self.FILTRE, context)
        date = self.parameterAsString(parameters, self.DATE, context)
        url = self.parameterAsString(parameters, self.URL_TEMPLATE, context)
        directory = Path(
            self.parameterAsString(parameters, self.DOSSIER, context))

        if not directory.exists():
            feedback.pushDebugInfo(
                "Création du répertoire {}".format(directory))
            os.makedirs(directory, exist_ok=True)

        filtre = [c.strip() for c in filtre.split(',')]

        communes = [c.strip() for c in communes.split(',')]
        departements = []
        self.results = {
            self.DOSSIER: str(directory),
            self.NB_COMMUNES: len(communes),
            self.NB_FEUILLES: 0,
            self.DEPARTEMENTS: "",
        }

        multi_feedback = QgsProcessingMultiStepFeedback(
            len(communes), feedback)

        for i, commune_insee in enumerate(communes):

            commune = Commune(commune_insee, date=date, base_url=url)
            if not self.download_commune(directory, commune, filtre,
                                         multi_feedback, context):
                multi_feedback.reportError("Erreur sur la commune {}".format(
                    commune.insee))
                break

            if multi_feedback.isCanceled():
                break

            multi_feedback.setCurrentStep(i)

            if commune.departement not in departements:
                departements.append(commune.departement)

        self.results[self.DEPARTEMENTS] = ','.join(departements)

        multi_feedback.pushInfo("\n")
        multi_feedback.pushInfo("\n")
        multi_feedback.pushInfo(
            "Téléchargement terminé pour {} communes".format(len(communes)))
        multi_feedback.pushInfo("{} feuilles".format(
            self.results[self.NB_FEUILLES]))
        multi_feedback.pushInfo("dans {}".format(str(directory)))
        multi_feedback.pushInfo("\n")
        multi_feedback.pushInfo("\n")
        return self.results
예제 #5
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        layerCsv = self.parameterAsString(parameters, self.INPUTLAYERS,
                                          context)
        algParameterDict = self.loadAlgorithmParametersDict(
            parameters, context, feedback)
        algName = self.parameterAsString(parameters, self.ALG_NAME, context)
        inputKey = self.parameterAsString(parameters,
                                          self.INPUT_LAYER_PARAMETER_NAME,
                                          context)
        outputKey = self.parameterAsString(parameters,
                                           self.OUTPUT_LAYER_PARAMETER_NAME,
                                           context)
        layerNameList = layerCsv.split(',')
        nSteps = len(layerNameList)
        if not nSteps:
            return {self.OUTPUT: None}
        multiStepFeedback = QgsProcessingMultiStepFeedback(nSteps, feedback)
        for idx, layerName in enumerate(layerNameList):
            multiStepFeedback.setCurrentStep(idx)
            multiStepFeedback.pushInfo(
                self.
                tr('Step {idx}/{total}: Running algorithm {algName} on {layerName}'
                   ).format(idx=idx,
                            total=nSteps,
                            algName=algName,
                            layerName=layerName))
            if QgsProcessingUtils.mapLayerFromString(layerName,
                                                     context) is None:
                multiStepFeedback.pushInfo(
                    self.tr('Layer {layerName} not found. Skipping step.').
                    format(layerName=layerName))
                continue

            currentDict = dict(algParameterDict)  #copy of the dict
            currentDict[inputKey] = layerName
            output = self.runProcessingAlg(algName,
                                           outputKey,
                                           currentDict,
                                           context=context,
                                           feedback=multiStepFeedback)
            outputLyr = QgsProcessingUtils.mapLayerFromString(
                output, context) if isinstance(output, str) else output
            if outputLyr is None:
                continue
            if self.flagSink is None:
                self.prepareFlagSink(parameters, outputLyr, context)
            self.flagFeatures(outputLyr, algName, layerName, context)

        return {self.OUTPUT: self.flag_id}
예제 #6
0
 def processAlgorithm(self, parameters, context, feedback):
     """
     Method that triggers the data processing algorithm.
     :param parameters: (dict) mapping from algorithms input's name to its
                        value.
     :param context: (QgsProcessingContext) execution's environmental info.
     :param feedback: (QgsProcessingFeedback) QGIS object to keep track of
                      algorithm's progress/status.
     :return: (dict) output mapping for identified flags.
     """
     layers, selected, silent, ratio = self.getParameters(
         parameters, context, feedback)
     if not layers:
         raise QgsProcessingException(self.tr("No layers were provided."))
     for layer in layers:
         if layer.featureCount() > 0:
             geomType = next(layer.getFeatures()).geometry().wkbType()
             break
     else:
         raise QgsProcessingException(self.tr("All layers are empty."))
     self.prepareFlagSink(parameters, layers[0], geomType, context)
     flags = dict()
     lh = LayerHandler()
     flagCount = 0
     # a step for each input + 1 for loading flags into sink
     multiStepFeedback = QgsProcessingMultiStepFeedback(
         len(layers) + 1, feedback)
     multiStepFeedback.setCurrentStep(0)
     for step, layer in enumerate(layers):
         if multiStepFeedback.isCanceled():
             break
         # running polygon slivers to purposely raise an exception if an
         # empty geometry is found
         multiStepFeedback.pushInfo(
             self.tr("Checking {0}...").format(layer.name()))
         slivers = lh.getPolygonSlivers(layer, ratio, selected, silent,
                                        multiStepFeedback)
         if slivers:
             # pushWarnign is only avalailable on 3.16.2+
             # multiStepFeedback.pushWarning(
             multiStepFeedback.pushDebugInfo(
                 self.tr("{0} slivers were found on {1}!")\
                     .format(len(slivers), layer.name())
             )
             flags[layer] = slivers
             flagCount += len(slivers)
         multiStepFeedback.setCurrentStep(step + 1)
     self.tr("Populating flags layer...")
     self.flagPolygonSlivers(flags, flagCount, multiStepFeedback)
     multiStepFeedback.setCurrentStep(step + 2)
     return {self.FLAGS: self.flag_id}
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        layerHandler = LayerHandler()
        algRunner = AlgRunner()
        inputLyrList = self.parameterAsLayerList(parameters, self.INPUTLAYERS,
                                                 context)
        if inputLyrList is None or inputLyrList == []:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUTLAYERS))
        onlySelected = self.parameterAsBool(parameters, self.SELECTED, context)
        tol = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        multiStepFeedback = QgsProcessingMultiStepFeedback(5, feedback)
        multiStepFeedback.setCurrentStep(0)
        multiStepFeedback.pushInfo(self.tr('Building unified layer...'))
        coverage = layerHandler.createAndPopulateUnifiedVectorLayer(
            inputLyrList,
            geomType=QgsWkbTypes.MultiPolygon,
            onlySelected=onlySelected,
            feedback=multiStepFeedback)

        multiStepFeedback.setCurrentStep(1)
        multiStepFeedback.pushInfo(
            self.tr('Identifying dangles on {layer}...').format(
                layer=coverage.name()))
        dangleLyr = algRunner.runIdentifyDangles(coverage,
                                                 tol,
                                                 context,
                                                 feedback=multiStepFeedback,
                                                 onlySelected=onlySelected)

        multiStepFeedback.setCurrentStep(2)
        layerHandler.filterDangles(dangleLyr, tol, feedback=multiStepFeedback)

        multiStepFeedback.setCurrentStep(3)
        multiStepFeedback.pushInfo(
            self.tr('Snapping layer {layer} to dangles...').format(
                layer=coverage.name()))
        algRunner.runSnapLayerOnLayer(coverage,
                                      dangleLyr,
                                      tol,
                                      context,
                                      feedback=multiStepFeedback,
                                      onlySelected=onlySelected,
                                      behavior=0)

        multiStepFeedback.setCurrentStep(4)
        multiStepFeedback.pushInfo(self.tr('Updating original layers...'))
        layerHandler.updateOriginalLayersFromUnifiedLayer(
            inputLyrList, coverage, feedback=multiStepFeedback)

        return {self.INPUTLAYERS: inputLyrList}
예제 #8
0
class DownloadOSMDataAroundAreaQuery(DownloadOSMData,
                                     BuildQueryAroundAreaAlgorithm):
    """Run the process of the plugin as an algorithm with a query input."""
    @staticmethod
    def name() -> str:
        """Return the name of the algorithm."""
        return 'downloadosmdataaroundareaquery'

    @staticmethod
    def displayName() -> str:
        """Return the display name of the algorithm."""
        return tr('Download OSM data from a query around an area')

    def flags(self):
        """Return the flags."""
        return DownloadOSMData.flags(self)

    def fetch_based_parameters(self, parameters, context):
        """Get the parameters."""
        BuildQueryAroundAreaAlgorithm.fetch_based_parameters(
            self, parameters, context)
        DownloadOSMData.fetch_based_parameters(self, parameters, context)

    def processAlgorithm(self, parameters, context, feedback):
        """Run the algorithm."""
        self.feedback = QgsProcessingMultiStepFeedback(8, feedback)
        self.fetch_based_parameters(parameters, context)

        self.feedback.setCurrentStep(0)
        self.feedback.pushInfo('Building the query.')

        query = processing.run("quickosm:buildqueryaroundarea", {
            'AREA': self.area,
            'DISTANCE': self.distance,
            'KEY': self.key,
            'SERVER': self.server,
            'TIMEOUT': self.timeout,
            'VALUE': self.value
        },
                               feedback=self.feedback)
        url = query['OUTPUT_URL']

        return self.process_road(context, url)
예제 #9
0
 def processAlgorithm(self, parameters, context, model_feedback):
     """
     Process the algorithm
     :param parameters: parameters of the process
     :param context: context of the process
     :param model_feedback: feedback instance for the process
     :return:
     """
     # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the
     # overall progress through the model
     self.xml_path = parameters["XMLPATH"]
     if not self.xml_path.lower().endswith(".xml"):
         feedback = QgsProcessingMultiStepFeedback(0, model_feedback)
         feedback.reportError("XML Workspace Definition is not an XML file!", True)
         return {}
     self.pg_conn_name = parameters["DBNAME"]
     self.pg_schema = parameters["SCHEMA"]
     self.pg_drop_before = parameters["DROPIFEXISTS"]
     domain_list = self.getDomains()
     feedback = QgsProcessingMultiStepFeedback(1+len(domain_list), model_feedback)        
     step=0
     for domain in domain_list:
         step+=1
         definition = self.getDomainDef(domain)
         try:
             alg_params = {
                 'DATABASE': self.pg_conn_name,
                 'SQL': definition[1]
             }
             processing.run(
                 'qgis:postgisexecutesql',
                 alg_params, context=context, feedback=feedback, is_child_algorithm=True)
             feedback.pushInfo("Domain: " + definition[0])
             feedback.pushInfo("   SQL: " + definition[1])
             feedback.pushInfo("   Rows: " + str(definition[2]))
         except Exception as e:
             feedback.reportError("Error importing domain " + definition[0] + ": " + str(e), False)
         feedback.setCurrentStep(step)
     results = {}
     outputs = {}
     return results
예제 #10
0
class DownloadOSMDataRawQuery(DownloadOSMData, BuildRaw):
    """Run the process of the plugin as an algorithm with a raw query input."""
    @staticmethod
    def name() -> str:
        """Return the name of the algorithm."""
        return 'downloadosmdatarawquery'

    @staticmethod
    def displayName() -> str:
        """Return the display name of the algorithm."""
        return tr('Download OSM data from a raw query')

    def flags(self):
        """Return the flags."""
        return DownloadOSMData.flags(self)

    def fetch_based_parameters(self, parameters, context):
        """Get the parameters."""
        BuildRaw.fetch_based_parameters(self, parameters, context)
        DownloadOSMData.fetch_based_parameters(self, parameters, context)

    def processAlgorithm(self, parameters, context, feedback):
        """Run the algorithm."""
        self.feedback = QgsProcessingMultiStepFeedback(8, feedback)
        self.fetch_based_parameters(parameters, context)

        self.feedback.setCurrentStep(0)
        self.feedback.pushInfo('Building the query.')

        raw_query = processing.run("quickosm:buildrawquery", {
            'AREA': self.area,
            'EXTENT': self.extent,
            'QUERY': self.query,
            'SERVER': self.server
        },
                                   feedback=self.feedback)
        url = raw_query['OUTPUT_URL']

        return self.process_road(context, url)
예제 #11
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        layerHandler = LayerHandler()
        self.algRunner = AlgRunner()

        inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context)
        if inputLyr is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))
        overlayLyr = self.parameterAsVectorLayer(parameters, self.OVERLAY,
                                                 context)
        if overlayLyr is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.OVERLAY))
        onlySelected = self.parameterAsBool(parameters, self.SELECTED, context)
        onlySelectedOverlay = self.parameterAsBool(parameters,
                                                   self.SELECTED_OVERLAY,
                                                   context)
        behavior = self.parameterAsEnum(parameters, self.BEHAVIOR, context)

        multiStepFeedback = QgsProcessingMultiStepFeedback(4, feedback)
        multiStepFeedback.setCurrentStep(0)
        multiStepFeedback.pushInfo(self.tr('Populating temp layer...'))
        auxLyr = layerHandler.createAndPopulateUnifiedVectorLayer(
            [inputLyr],
            geomType=inputLyr.wkbType(),
            onlySelected=onlySelected,
            feedback=multiStepFeedback)
        multiStepFeedback.setCurrentStep(1)
        if onlySelectedOverlay:
            overlayLyr = layerHandler.createAndPopulateUnifiedVectorLayer(
                [overlayLyr],
                geomType=overlayLyr.wkbType(),
                onlySelected=onlySelectedOverlay,
                feedback=multiStepFeedback)
            overlayLyr.startEditing()
            overlayLyr.renameAttribute(0, 'fid')
            overlayLyr.renameAttribute(1, 'cl')
            overlayLyr.commitChanges()
        # 1- check method
        # 2- if overlay and keep, use clip and symetric difference
        # 3- if remove outside, use clip
        # 4- if remove inside, use symetric difference
        multiStepFeedback.setCurrentStep(2)
        multiStepFeedback.pushInfo(self.tr('Running overlay...'))
        outputLyr = self.runOverlay(auxLyr, overlayLyr, behavior, context,
                                    multiStepFeedback)
        multiStepFeedback.setCurrentStep(3)
        multiStepFeedback.pushInfo(self.tr('Updating original layer...'))
        layerHandler.updateOriginalLayersFromUnifiedLayer(
            [inputLyr],
            outputLyr,
            feedback=multiStepFeedback,
            onlySelected=onlySelected)

        return {self.OUTPUT: inputLyr}
예제 #12
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        layerHandler = LayerHandler()
        algRunner = AlgRunner()
        inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context)
        if inputLyr is None:
            raise QgsProcessingException(
                self.invalidSourceError(
                    parameters,
                    self.INPUT
                    )
                )
        onlySelected = self.parameterAsBool(
            parameters,
            self.SELECTED,
            context
            )
        tol = self.parameterAsDouble(
            parameters,
            self.TOLERANCE,
            context
            )

        multiStepFeedback = QgsProcessingMultiStepFeedback(3, feedback)
        multiStepFeedback.setCurrentStep(0)
        multiStepFeedback.pushInfo(self.tr('Populating temp layer...'))
        auxLyr = layerHandler.createAndPopulateUnifiedVectorLayer(
            [inputLyr],
            geomType=inputLyr.wkbType(),
            onlySelected=onlySelected,
            feedback=multiStepFeedback
            )
        
        multiStepFeedback.setCurrentStep(1)
        multiStepFeedback.pushInfo(
            self.tr(
                'Snapping geometries from layer {input} to grid with size {tol}...'
                ).format(input=inputLyr.name(), tol=tol)
            )
        snappedLayer = algRunner.runSnapToGrid(
            auxLyr,
            tol,
            context,
            feedback=multiStepFeedback
            )

        multiStepFeedback.setCurrentStep(2)
        multiStepFeedback.pushInfo(self.tr('Updating original layer...'))
        layerHandler.updateOriginalLayersFromUnifiedLayer(
            [inputLyr],
            snappedLayer,
            feedback=multiStepFeedback,
            onlySelected=onlySelected
            )

        return {self.OUTPUT: inputLyr}
예제 #13
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        layerHandler = LayerHandler()
        algRunner = AlgRunner()
        inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context)
        onlySelected = self.parameterAsBool(parameters, self.SELECTED, context)
        tol = self.parameterAsDouble(parameters, self.TOLERANCE, context)

        multiStepFeedback = QgsProcessingMultiStepFeedback(3, feedback)
        multiStepFeedback.setCurrentStep(0)
        multiStepFeedback.pushInfo(self.tr('Identifying dangles on {layer}...').format(layer=inputLyr.name()))
        dangleLyr = algRunner.runIdentifyDangles(inputLyr, tol, context, feedback=multiStepFeedback, onlySelected=onlySelected)

        multiStepFeedback.setCurrentStep(1)
        layerHandler.filterDangles(dangleLyr, tol, feedback=multiStepFeedback)

        multiStepFeedback.setCurrentStep(2)
        multiStepFeedback.pushInfo(self.tr('Snapping layer {layer} to dangles...').format(layer=inputLyr.name()))
        algRunner.runSnapLayerOnLayer(inputLyr, dangleLyr, tol, context, feedback=multiStepFeedback, onlySelected=onlySelected, behavior=0)
        QgsProject.instance().removeMapLayer(dangleLyr.id())
        return {self.OUTPUT: inputLyr}
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        layerHandler = LayerHandler()
        snapDict = self.parameterAsSnapHierarchy(parameters,
                                                 self.SNAP_HIERARCHY, context)

        onlySelected = self.parameterAsBool(parameters, self.SELECTED, context)

        behavior = self.parameterAsEnum(parameters, self.BEHAVIOR, context)
        nSteps = 0
        for item in snapDict:
            nSteps += len(item['snapLayerList'])
        currStep = 0
        multiStepFeedback = QgsProcessingMultiStepFeedback(nSteps, feedback)
        for current, item in enumerate(snapDict):
            refLyr = self.layerFromProject(item['referenceLayer'])
            for i, lyr in enumerate(item['snapLayerList']):
                lyr = self.layerFromProject(lyr)
                if multiStepFeedback.isCanceled():
                    break
                multiStepFeedback.setCurrentStep(currStep)
                multiStepFeedback.pushInfo(
                    self.
                    tr('Snapping geometries from layer {input} to {reference} with snap {snap}...'
                       ).format(input=lyr.name(),
                                reference=refLyr.name(),
                                snap=item['snap']))
                layerHandler.snapToLayer(lyr,
                                         refLyr,
                                         item['snap'],
                                         behavior,
                                         onlySelected=onlySelected,
                                         feedback=multiStepFeedback)
                currStep += 1
        return {}
예제 #15
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        layerHandler = LayerHandler()
        algRunner = AlgRunner()

        inputLyrList = self.parameterAsLayerList(parameters, self.INPUTLAYERS,
                                                 context)
        if inputLyrList is None or inputLyrList == []:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUTLAYERS))
        for layer in inputLyrList:
            if layer.featureCount() > 0:
                geomType = next(layer.getFeatures()).geometry().wkbType()
                break
        else:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUTLAYERS),
                self.tr("Provided layers have no features in it."))
        onlySelected = self.parameterAsBool(parameters, self.SELECTED, context)
        snap = self.parameterAsDouble(parameters, self.TOLERANCE, context)
        minArea = self.parameterAsDouble(parameters, self.MINAREA, context)
        self.prepareFlagSink(parameters, inputLyrList[0], geomType, context)

        multiStepFeedback = QgsProcessingMultiStepFeedback(3, feedback)
        multiStepFeedback.setCurrentStep(0)
        multiStepFeedback.pushInfo(self.tr('Building unified layer...'))
        # in order to check the topology of all layers as a whole, all features
        # are handled as if they formed a single layer
        coverage = layerHandler.createAndPopulateUnifiedVectorLayer(
            inputLyrList,
            geomType=geomType,
            onlySelected=onlySelected,
            feedback=multiStepFeedback)
        multiStepFeedback.setCurrentStep(1)
        multiStepFeedback.pushInfo(
            self.tr('Running clean on unified layer...'))
        cleanedCoverage, error = algRunner.runClean(coverage, [
            algRunner.RMSA, algRunner.Break, algRunner.RmDupl,
            algRunner.RmDangle
        ],
                                                    context,
                                                    returnError=True,
                                                    snap=snap,
                                                    minArea=minArea,
                                                    feedback=multiStepFeedback)

        multiStepFeedback.setCurrentStep(2)
        multiStepFeedback.pushInfo(self.tr('Updating original layer...'))
        layerHandler.updateOriginalLayersFromUnifiedLayer(
            inputLyrList, cleanedCoverage, feedback=multiStepFeedback)
        self.flagCoverageIssues(cleanedCoverage, error, feedback)

        return {self.INPUTLAYERS: inputLyrList, self.FLAGS: self.flagSink}
예제 #16
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        layerHandler = LayerHandler()
        algRunner = AlgRunner()
        inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context)
        onlySelected = self.parameterAsBool(parameters, self.SELECTED, context)
        tol = self.parameterAsDouble(parameters, self.MIN_AREA, context)
        attributeBlackList = self.parameterAsFields(parameters,
                                                    self.ATTRIBUTE_BLACK_LIST,
                                                    context)
        ignoreVirtual = self.parameterAsBool(parameters,
                                             self.IGNORE_VIRTUAL_FIELDS,
                                             context)
        ignorePK = self.parameterAsBool(parameters, self.IGNORE_PK_FIELDS,
                                        context)

        tol = -1 if tol is None else tol
        nSteps = 4 if tol > 0 else 3
        multiStepFeedback = QgsProcessingMultiStepFeedback(nSteps, feedback)
        currentStep = 0
        multiStepFeedback.setCurrentStep(currentStep)
        multiStepFeedback.pushInfo(self.tr('Populating temp layer...\n'))
        unifiedLyr = layerHandler.createAndPopulateUnifiedVectorLayer(
            [inputLyr],
            geomType=QgsWkbTypes.MultiPolygon,
            attributeBlackList=attributeBlackList,
            onlySelected=onlySelected,
            feedback=multiStepFeedback)
        currentStep += 1

        if tol > 0:
            multiStepFeedback.setCurrentStep(currentStep)
            multiStepFeedback.pushInfo(
                self.tr('Adding size constraint field...\n'))
            unifiedLyr = layerHandler.addDissolveField(
                unifiedLyr, tol, feedback=multiStepFeedback)
            currentStep += 1

        multiStepFeedback.setCurrentStep(currentStep)
        multiStepFeedback.pushInfo(self.tr('Running dissolve...\n'))
        dissolvedLyr = algRunner.runDissolve(unifiedLyr,
                                             context,
                                             feedback=multiStepFeedback,
                                             field=['tupple'])
        layerHandler.updateOriginalLayersFromUnifiedLayer(
            [inputLyr],
            dissolvedLyr,
            feedback=multiStepFeedback,
            onlySelected=onlySelected)

        return {self.OUTPUT: inputLyr}
예제 #17
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        layerHandler = LayerHandler()
        algRunner = AlgRunner()

        inputLyrList = self.parameterAsLayerList(parameters, self.INPUTLAYERS,
                                                 context)
        if inputLyrList is None or inputLyrList == []:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUTLAYERS))
        onlySelected = self.parameterAsBool(parameters, self.SELECTED, context)
        snap = self.parameterAsDouble(parameters, self.SNAP, context)
        threshold = self.parameterAsDouble(parameters, self.DOUGLASPARAMETER,
                                           context)
        minArea = self.parameterAsDouble(parameters, self.MINAREA, context)
        self.prepareFlagSink(parameters, inputLyrList[0],
                             QgsWkbTypes.MultiPolygon, context)

        multiStepFeedback = QgsProcessingMultiStepFeedback(3, feedback)
        multiStepFeedback.setCurrentStep(0)
        multiStepFeedback.pushInfo(self.tr('Building unified layer...'))
        coverage = layerHandler.createAndPopulateUnifiedVectorLayer(
            inputLyrList,
            geomType=QgsWkbTypes.MultiPolygon,
            onlySelected=onlySelected,
            feedback=multiStepFeedback)

        multiStepFeedback.setCurrentStep(1)
        multiStepFeedback.pushInfo(
            self.tr('Running clean on unified layer...'))
        simplifiedCoverage, error = algRunner.runDouglasSimplification(
            coverage,
            threshold,
            context,
            returnError=True,
            snap=snap,
            minArea=minArea,
            feedback=multiStepFeedback)

        multiStepFeedback.setCurrentStep(2)
        multiStepFeedback.pushInfo(self.tr('Updating original layer...'))
        layerHandler.updateOriginalLayersFromUnifiedLayer(
            inputLyrList,
            simplifiedCoverage,
            feedback=multiStepFeedback,
            onlySelected=onlySelected)

        self.flagCoverageIssues(simplifiedCoverage, error, feedback)

        return {self.INPUTLAYERS: inputLyrList, self.FLAGS: self.flag_id}
예제 #18
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        layerHandler = LayerHandler()
        algRunner = AlgRunner()

        inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context)
        if inputLyr is None:
            raise QgsProcessingException(
                self.invalidSourceError(parameters, self.INPUT))
        onlySelected = self.parameterAsBool(parameters, self.SELECTED, context)
        snap = self.parameterAsDouble(parameters, self.TOLERANCE, context)
        # if snap < 0 and snap != -1:
        #     raise QgsProcessingException(self.invalidParameterError(parameters, self.TOLERANCE))
        minArea = self.parameterAsDouble(parameters, self.MINAREA, context)
        self.prepareFlagSink(parameters, inputLyr, inputLyr.wkbType(), context)

        multiStepFeedback = QgsProcessingMultiStepFeedback(3, feedback)
        multiStepFeedback.setCurrentStep(0)
        multiStepFeedback.pushInfo(self.tr('Populating temp layer...'))
        auxLyr = layerHandler.createAndPopulateUnifiedVectorLayer(
            [inputLyr],
            geomType=inputLyr.wkbType(),
            onlySelected=onlySelected,
            feedback=multiStepFeedback)
        multiStepFeedback.setCurrentStep(1)
        multiStepFeedback.pushInfo(self.tr('Running clean...'))
        cleanedLyr, error = algRunner.runClean(auxLyr, \
                                                    [algRunner.RMSA, algRunner.Break, algRunner.RmDupl, algRunner.RmDangle], \
                                                    context, \
                                                    returnError=True, \
                                                    snap=snap, \
                                                    minArea=minArea,
                                                    feedback=multiStepFeedback)
        multiStepFeedback.setCurrentStep(2)
        multiStepFeedback.pushInfo(self.tr('Updating original layer...'))
        layerHandler.updateOriginalLayersFromUnifiedLayer(
            [inputLyr],
            cleanedLyr,
            feedback=multiStepFeedback,
            onlySelected=onlySelected)
        self.flagIssues(cleanedLyr, error, feedback)

        return {self.OUTPUT: inputLyr, self.FLAGS: self.flag_id}
예제 #19
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        layerHandler = LayerHandler()
        algRunner = AlgRunner()

        layerHandler = LayerHandler()
        inputLyr = self.parameterAsVectorLayer(
            parameters,
            self.INPUT,
            context
            )
        onlySelected = self.parameterAsBool(
            parameters,
            self.SELECTED,
            context
            )
        tol = self.parameterAsDouble(
            parameters,
            self.TOLERANCE,
            context
            )
        attributeBlackList = self.parameterAsFields(
            parameters,
            self.ATTRIBUTE_BLACK_LIST,
            context
            )
        ignoreVirtual = self.parameterAsBool(
            parameters,
            self.IGNORE_VIRTUAL_FIELDS,
            context
            )
        ignorePK = self.parameterAsBool(
            parameters,
            self.IGNORE_PK_FIELDS,
            context
            )

        layerHandler.mergeLinesOnLayer(
            inputLyr,
            feedback=feedback,
            onlySelected=onlySelected,
            ignoreVirtualFields=ignoreVirtual,
            attributeBlackList=attributeBlackList,
            excludePrimaryKeys=ignorePK
            )
        #aux layer
        multiStepFeedback = QgsProcessingMultiStepFeedback(8, feedback)
        multiStepFeedback.setCurrentStep(0)
        if onlySelected:
            multiStepFeedback.pushInfo(self.tr('Building auxiliar layer...'))
            coverage = layerHandler.createAndPopulateUnifiedVectorLayer(
                [inputLyr],
                geomType=QgsWkbTypes.MultiPolygon,
                onlySelected=onlySelected,
                feedback=multiStepFeedback
                )
        else:
            coverage = inputLyr
        #dangles
        multiStepFeedback.setCurrentStep(1)
        multiStepFeedback.pushInfo(self.tr('Identifying dangles on {layer}...').format(layer=coverage.name()))
        dangleLyr = algRunner.runIdentifyDangles(
            inputLayer=coverage,
            searchRadius=tol,
            context=context,
            feedback=multiStepFeedback,
            onlySelected=False
            )
        #filter dangles
        multiStepFeedback.setCurrentStep(2)
        layerHandler.filterDangles(
            dangleLyr,
            tol,
            feedback=multiStepFeedback
            )
        #snap layer to dangles
        multiStepFeedback.setCurrentStep(3)
        multiStepFeedback.pushInfo(self.tr('Snapping layer {layer} to dangles...').format(layer=coverage.name()))
        algRunner.runSnapLayerOnLayer(
            coverage,
            dangleLyr,
            tol,
            context,
            feedback=multiStepFeedback,
            onlySelected=False, #this is done due to the aux layer usage
            behavior=0
            )
        #inner layer snap
        multiStepFeedback.setCurrentStep(4)
        multiStepFeedback.pushInfo(self.tr('Snapping layer {layer} with {layer}...').format(layer=coverage.name()))
        algRunner.runSnapLayerOnLayer(
            coverage,
            coverage,
            tol,
            context,
            feedback=multiStepFeedback,
            onlySelected=False, #this is done due to the aux layer usage
            behavior=0
            )
        #clean to break lines
        multiStepFeedback.setCurrentStep(5)
        multiStepFeedback.pushInfo(self.tr('Running clean on {layer}...').format(layer=coverage.name()))
        multiStepFeedback.pushInfo(self.tr('Running clean on unified layer...'))
        cleanedCoverage, error = algRunner.runClean(
            coverage,
            [
                algRunner.RMSA,
                algRunner.Break,
                algRunner.RmDupl,
                algRunner.RmDangle
                ],
            context,
            returnError=True,
            snap=snap,
            minArea=minArea,
            feedback=multiStepFeedback
            )
        #remove duplicated features
        multiStepFeedback.setCurrentStep(6)
        multiStepFeedback.pushInfo(self.tr('Removing duplicated features from {layer}...').format(layer=coverage.name()))
        algRunner.runRemoveDuplicatedFeatures(
            inputLyr=cleanedCoverage,
            context=context,
            onlySelected=False,
            attributeBlackList=attributeBlackList,
            excludePrimaryKeys=excludePrimaryKeys,
            ignorePK=ignorePK,
            ignoreVirtual=ignoreVirtual
        )
        #merging lines with same attributes
        multiStepFeedback.setCurrentStep(6)
        multiStepFeedback.pushInfo(self.tr('Merging lines from {layer} with same attribute set...').format(layer=coverage.name()))

        multiStepFeedback.setCurrentStep(7)
        multiStepFeedback.pushInfo(self.tr('Updating original layers...'))
        layerHandler.updateOriginalLayersFromUnifiedLayer(
            [inputLyr],
            coverage,
            feedback=multiStepFeedback,
            onlySelected=onlySelected
            )

        return {self.INPUTLAYERS : inputLyrList}
예제 #20
0
    def getSystematicGridFeaturesWithConstraint(self, featureList, inputLyr, stopScale,
                                                coordinateTransformer, fields, feedback=None, predicate=None):
        """
        TODO: Progress
        """
        if feedback is not None and feedback.isCanceled():
            return
        predicate = 'intersects' if predicate is None else predicate
        multiStepFeedback = QgsProcessingMultiStepFeedback(2, feedback)
        multiStepFeedback.setCurrentStep(0)
        multiStepFeedback.pushInfo(self.tr('Creating spatial index'))
        spatialIdx, idDict = self.buildSpatialIndexAndIdDict(
            inputLyr,
            feedback=multiStepFeedback
        )
        multiStepFeedback.pushInfo(self.tr('Getting candidate start indexes'))
        xmin, ymin, xmax, ymax = self.getLyrUnprojectedGeographicBounds(
            inputLyr
        )
        inomenList = self.utmGrid.get_INOM_range_from_BB(
            xmin, ymin, xmax, ymax
        )
        multiStepFeedback.setCurrentStep(1)
        multiStepFeedback.pushInfo(self.tr('Building grid'))
        gridMultistepFeedback = QgsProcessingMultiStepFeedback(
            len(inomenList),
            multiStepFeedback
        )
        constraintDict = {
            'spatialIdx': spatialIdx,
            'idDict': idDict,
            'predicate': predicate
        }
        sys.setrecursionlimit(10**7)

        def compute(x):
            self.getSystematicGridFeatures(
                featureList,
                x,
                stopScale,
                coordinateTransformer,
                fields,
                constraintDict=constraintDict,
                feedback=gridMultistepFeedback
            )
        pool = concurrent.futures.ThreadPoolExecutor(os.cpu_count())
        futures = []
        current_idx = 0
        for inomen in inomenList:
            # gridMultistepFeedback.setCurrentStep(i)
            if gridMultistepFeedback.isCanceled():
                break
            futures.append(
                pool.submit(compute, inomen)
            )

        for x in concurrent.futures.as_completed(futures):
            if gridMultistepFeedback.isCanceled():
                break
            gridMultistepFeedback.setCurrentStep(current_idx)
            current_idx += 1
    def processAlgorithm(self, parameters, context, model_feedback):
        # variables propres à Processing
        feedback = QgsProcessingMultiStepFeedback(2, model_feedback)
        results = {}

        # entrées
        lignes = self.parameterAsVectorLayer(parameters, 'lignes', context)
        rasters = parameters['rasters']

        # sorties
        output = self.parameterAsOutputLayer(parameters, 'OUTPUT', context)
        profils = []

        # paramètres
        echantillons_nb = parameters['echantillons_nb']

        # traitement
        if len(rasters) == 0:
            feedback.pushInfo(
                "⚠ Il est nécessaire de fournir au moins un raster en entrée.\n"
            )
            return {}
        for ligne_f in lignes.getFeatures():
            ligne_g = ligne_f.geometry()
            freq = ligne_g.length() / (echantillons_nb - 1)
            echantillons_g = [
                QgsGeometry().fromPointXY(ligne_g.asMultiPolyline()[0][0])
            ]
            for i in range(1, echantillons_nb - 1):
                echantillons_g.append(ligne_g.interpolate(freq * i))
            echantillons_g.append(QgsGeometry().fromPointXY(
                ligne_g.asMultiPolyline()[0][-1]))
            feedback.pushInfo(str(echantillons_g))
            for raster in rasters:
                elevations = []
                for echantillon_g in echantillons_g:
                    elevation = raster.dataProvider().sample(
                        echantillon_g.asPoint(), 1)[0]
                    elevations.append(elevation)
                profils.append([
                    echantillons_g,
                    ligne_f.attributes(),
                    raster.name(), elevations
                ])

        feedback.setCurrentStep(1)
        if feedback.isCanceled():
            return {}

        # écriture des données en sortie
        fields = lignes.fields()
        fields.append(QgsField("ordre", QVariant.Int))
        fields.append(QgsField("raster", QVariant.String))
        fields.append(QgsField("elevation", QVariant.Double))
        writer = QgsVectorFileWriter(output, "System", fields,
                                     QgsWkbTypes.Point,
                                     QgsCoordinateReferenceSystem(2154),
                                     "ESRI Shapefile")
        for echantillons_g, attributes, raster_name, elevations in profils:
            ordre = 0
            for echantillon_g, elevation in zip(echantillons_g, elevations):
                f = QgsFeature()
                f.setGeometry(echantillon_g)
                echantillon_att = attributes.copy()
                echantillon_att.append(ordre)
                echantillon_att.append(raster_name)
                echantillon_att.append(elevation)
                f.setAttributes(echantillon_att)
                feedback.pushInfo(str(f.attributes()))
                writer.addFeature(f)
                ordre += 1

        feedback.setCurrentStep(2)

        results['OUTPUT'] = output
        return results
예제 #22
0
    def relateDrainagesWithContours(self, drainageLyr, contourLyr, frameLinesLyr, heightFieldName, threshold, topologyRadius, feedback=None):
        """
        Checks the conformity between directed drainages and contours.
        Drainages must be propperly directed.
        :param drainageLyr: QgsVectorLayer (line) with drainage lines.
        This must have a primary key field;
        :param contourLyr: QgsVectorLayer (line) with contour lines.
        This must have a primary key field;
        :param frameLinesLyrLyr: QgsVectorLayer (line) with frame lines;
        :param heightFieldName: (str) name of the field that stores
        contour's height;
        :param threshold: (int) equidistance between contour lines;
        :param threshold: (float) topology radius;
        Process steps:
        1- Build spatial indexes;
        2- Compute intersections between drainages and contours;
        3- Relate intersections grouping by drainages: calculate the
        distance between the start point and each intersection, then
        order the points by distance. If the height of each point does
        not follow this order, flag the intersection.
        4- After relating everything,
        """
        maxSteps = 4
        multiStepFeedback = QgsProcessingMultiStepFeedback(maxSteps, feedback) if feedback is not None else None
        currentStep = 0
        if multiStepFeedback is not None:
            if multiStepFeedback.isCanceled():
                return []
            multiStepFeedback.setCurrentStep(currentStep)
            currentStep += 1
            multiStepFeedback.pushInfo(
                self.tr('Building contour structures...')
                )
        contourSpatialIdx, contourIdDict, contourNodeDict, heightsDict = self.buildSpatialIndexAndIdDictRelateNodesAndAttributeGroupDict(
            inputLyr=contourLyr,
            attributeName=heightFieldName,
            feedback=multiStepFeedback
        )
        if multiStepFeedback is not None:
            if multiStepFeedback.isCanceled():
                return []
            multiStepFeedback.setCurrentStep(currentStep)
            currentStep += 1
            multiStepFeedback.pushInfo(
                self.tr('Validating contour structures. Check 1/4...')
                )
        invalidDict = self.validateContourRelations(
            contourNodeDict,
            feedback=multiStepFeedback
            )
        if invalidDict:
            multiStepFeedback.setCurrentStep(maxSteps-1)
            return invalidDict

        if multiStepFeedback is not None:
            if multiStepFeedback.isCanceled():
                return []
            multiStepFeedback.setCurrentStep(currentStep)
            currentStep += 1
            multiStepFeedback.pushInfo(
                self.tr('Building drainage spatial index...')
                )
        drainageSpatialIdx, drainageIdDict, drainageNodeDict = self.buildSpatialIndexAndIdDictAndRelateNodes(
            inputLyr=drainageLyr,
            feedback=multiStepFeedback
        )
        if multiStepFeedback is not None:
            if multiStepFeedback.isCanceled():
                return []
            multiStepFeedback.setCurrentStep(currentStep)
            currentStep += 1
            multiStepFeedback.pushInfo(
                self.tr('Relating contours with drainages...')
                )
        intersectionDict = self.buildIntersectionDict(
            drainageLyr,
            drainageIdDict,
            drainageSpatialIdx,
            contourIdDict,
            contourIdDict
            )
    def processAlgorithm(self, parameters, context, model_feedback):
        # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the
        # overall progress through the model
        feedback = QgsProcessingMultiStepFeedback(13, model_feedback)
        results = {}
        outputs = {}

        input_layer = self.parameterAsVectorLayer(parameters, "inputlayer",
                                                  context)
        overlay_layer = self.parameterAsVectorLayer(parameters, "overlaylayer",
                                                    context)

        input_epsg_code = input_layer.crs().authid()
        overlay_epsg_code = overlay_layer.crs().authid()

        crs_input = QgsCoordinateReferenceSystem(input_epsg_code)
        crs_overlay = QgsCoordinateReferenceSystem(overlay_epsg_code)

        if crs_input.isGeographic():
            feedback.reportError(
                "CRS of the Input Layer is Geographic. Results accuracy may get impacted. For most accurate results, both input and overlay layers should be in the same Projected CRS\n"
            )

        if crs_overlay.isGeographic():
            feedback.reportError(
                "CRS of the Input Layer is Geographic. Results accuracy may get impacted. For most accurate results, both input and overlay layers should be in the same Projected CRS\n"
            )

        if input_epsg_code == overlay_epsg_code:
            pass
        else:
            feedback.reportError(
                "Input and Overlay Layers are in different CRS. For most accurate results, both input and overlay layers should be in the same Projected CRS\n"
            )

        # add_ID_field to input layer
        alg_params = {
            "FIELD_NAME": "input_feat_id",
            "GROUP_FIELDS": [""],
            "INPUT": parameters["inputlayer"],
            "SORT_ASCENDING": True,
            "SORT_EXPRESSION": "",
            "SORT_NULLS_FIRST": False,
            "START": 1,
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
        }
        outputs["Add_id_field"] = processing.run(
            "native:addautoincrementalfield",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(1)
        if feedback.isCanceled():
            return {}

        # add_area_field to input layer
        alg_params = {
            "FIELD_LENGTH": 0,
            "FIELD_NAME": "area_awa",
            "FIELD_PRECISION": 0,
            "FIELD_TYPE": 0,
            "FORMULA": "area($geometry)",
            "INPUT": outputs["Add_id_field"]["OUTPUT"],
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
        }
        outputs["Add_area_field"] = processing.run(
            "qgis:fieldcalculator",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(2)
        if feedback.isCanceled():
            return {}

        # dissolve all overlay fields so as not to repeat record in reporting
        alg_params = {
            "FIELD": [parameters["fieldtoaverage"]] + [
                field for field in parameters["additionalfields"]
                if field != str(parameters["fieldtoaverage"])
            ],
            "INPUT":
            parameters["overlaylayer"],
            "OUTPUT":
            QgsProcessing.TEMPORARY_OUTPUT,
        }
        outputs["Dissolve"] = processing.run(
            "native:dissolve",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(3)
        if feedback.isCanceled():
            return {}

        # intersection between input and overlay layer
        # delete no field in input layer and all fields in overlay layer
        # except field to average and additional fields
        alg_params = {
            "INPUT":
            outputs["Add_area_field"]["OUTPUT"],
            "INPUT_FIELDS": [""],
            "OVERLAY":
            outputs["Dissolve"]["OUTPUT"],
            "OVERLAY_FIELDS": [str(parameters["fieldtoaverage"])] +
            parameters["additionalfields"],
            "OVERLAY_FIELDS_PREFIX":
            "",
            "OUTPUT":
            QgsProcessing.TEMPORARY_OUTPUT,
        }
        outputs["Intersection"] = processing.run(
            "native:intersection",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(4)
        if feedback.isCanceled():
            return {}

        # add_Weight
        alg_params = {
            "FIELD_LENGTH": 0,
            "FIELD_NAME": parameters["fieldtoaverage"] + "_area",
            "FIELD_PRECISION": 0,
            "FIELD_TYPE": 0,
            "FORMULA":
            ' "' + parameters["fieldtoaverage"] + '"  *  area($geometry)',
            "INPUT": outputs["Intersection"]["OUTPUT"],
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
        }
        outputs["Add_Weight"] = processing.run(
            "qgis:fieldcalculator",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(5)
        if feedback.isCanceled():
            return {}

        # area_average
        weighted_field = "weighted_" + parameters["fieldtoaverage"]
        alg_params = {
            "FIELD_LENGTH": 0,
            "FIELD_NAME": weighted_field,
            "FIELD_PRECISION": 0,
            "FIELD_TYPE": 0,
            "FORMULA": ' sum("' + parameters["fieldtoaverage"] + "_area"
            '","input_feat_id")/"area_awa"',
            "INPUT": outputs["Add_Weight"]["OUTPUT"],
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
        }
        outputs["area_average"] = processing.run(
            "qgis:fieldcalculator",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(6)
        if feedback.isCanceled():
            return {}

        # remerge input layer elements
        alg_params = {
            "FIELD": ["input_feat_id"],
            "INPUT": outputs["area_average"]["OUTPUT"],
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
        }
        outputs["Dissolve2"] = processing.run(
            "native:dissolve",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(7)
        if feedback.isCanceled():
            return {}

        input_layer = self.parameterAsVectorLayer(parameters, "inputlayer",
                                                  context)
        result_name = input_layer.name() + "_" + parameters["fieldtoaverage"]
        parameters["result"].destinationName = result_name

        # drop field(s) for Result
        alg_params = {
            "COLUMN":
            ["input_feat_id", "area_awa"] + [parameters["fieldtoaverage"]] + [
                field for field in parameters["additionalfields"]
                if field != str(parameters["fieldtoaverage"])
            ] + [parameters["fieldtoaverage"] + "_area"],
            "INPUT":
            outputs["Dissolve2"]["OUTPUT"],
            "OUTPUT":
            parameters["result"],
        }
        outputs["Drop1"] = processing.run(
            "qgis:deletecolumn",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(8)
        if feedback.isCanceled():
            return {}

        results["result"] = outputs["Drop1"]["OUTPUT"]

        # Reporting

        # Drop field(s) for Report
        int_layer = context.takeResultLayer(outputs["area_average"]["OUTPUT"])
        all_fields = [f.name() for f in int_layer.fields()]
        fields_to_keep = (["input_feat_id", weighted_field] + [
            field for field in parameters["additionalfields"]
            if field != str(parameters["fieldtoaverage"])
        ] + [parameters["fieldtoaverage"]] +
                          [parameters["identifierfieldforreport"]])
        fields_to_drop = [f for f in all_fields if f not in fields_to_keep]
        alg_params = {
            "COLUMN": fields_to_drop,
            "INPUT": int_layer,
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
        }
        outputs["Drop2"] = processing.run(
            "qgis:deletecolumn",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(9)
        if feedback.isCanceled():
            return {}

        # update area
        alg_params = {
            "FIELD_LENGTH": 20,
            "FIELD_NAME": "area_crs_units",
            "FIELD_PRECISION": 5,
            "FIELD_TYPE": 0,
            "FORMULA": "round(area($geometry),5)",
            "INPUT": outputs["Drop2"]["OUTPUT"],
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
        }
        outputs["update_area"] = processing.run(
            "qgis:fieldcalculator",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(10)
        if feedback.isCanceled():
            return {}

        parameters["reportaslayer"].destinationName = "Report as Layer"
        # add area %
        alg_params = {
            "FIELD_LENGTH": 9,
            "FIELD_NAME": "area_prcnt",
            "FIELD_PRECISION": 5,
            "FIELD_TYPE": 0,
            "FORMULA":
            ' round("area_crs_units" *100/  sum(  "area_crs_units" ,  "input_feat_id" ),5)',
            "INPUT": outputs["update_area"]["OUTPUT"],
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
        }
        outputs["area_prcnt"] = processing.run(
            "qgis:fieldcalculator",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(11)
        if feedback.isCanceled():
            return {}

        # Order by expression
        alg_params = {
            "ASCENDING": True,
            "EXPRESSION": ' "input_feat_id" + area_prcnt" ',
            "INPUT": outputs["area_prcnt"]["OUTPUT"],
            "NULLS_FIRST": False,
            "OUTPUT": parameters["reportaslayer"],
        }
        outputs["OrderByExpression"] = processing.run(
            "native:orderbyexpression",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(12)
        if feedback.isCanceled():
            return {}

        results["reportaslayer"] = outputs["OrderByExpression"]["OUTPUT"]

        output_file = self.parameterAsFileOutput(parameters, "reportasHTML",
                                                 context)

        # create HTML report
        if output_file:

            try:
                try:
                    import pandas as pd
                except ImportError:
                    feedback.pushInfo(
                        "Python library pandas was not found. Installing pandas to QGIS python ..."
                    )
                    import pathlib as pl
                    import subprocess

                    qgis_Path = pl.Path(sys.executable)
                    qgis_python_path = (qgis_Path.parent /
                                        "python3.exe").as_posix()

                    subprocess.check_call([
                        qgis_python_path, "-m", "pip", "install", "--user",
                        "pandas"
                    ])
                    import pandas as pd

                    feedback.pushInfo(
                        "Python library pandas was successfully installed for QGIS python"
                    )
            except:
                feedback.reportError(
                    "Failed to import pandas. Tried installing pandas but failed.\nPlease manually install pandas for the python that comes with your QGIS.",
                    True,
                )
                return results

            # Drop geometries
            alg_params = {
                "INPUT": outputs["area_prcnt"]["OUTPUT"],
                "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
            }
            outputs["DropGeometries"] = processing.run(
                "native:dropgeometries",
                alg_params,
                context=context,
                feedback=feedback,
                is_child_algorithm=True,
            )

            feedback.setCurrentStep(13)
            if feedback.isCanceled():
                return {}

            with tempfile.TemporaryDirectory() as td:
                f_name = os.path.join(td, "report_df.csv")

                report_layer = context.takeResultLayer(
                    outputs["DropGeometries"]["OUTPUT"])

                QgsVectorFileWriter.writeAsVectorFormat(
                    report_layer,
                    f_name,
                    fileEncoding="utf-8",
                    driverName="CSV",
                )

                df = pd.read_csv(f_name)

            total_FIDs = df["input_feat_id"].max()
            ident_name = parameters["identifierfieldforreport"]
            html = ""
            df.sort_values(by="area_prcnt", ascending=False, inplace=True)
            pd.set_option("display.float_format", "{:.5f}".format)

            for i in range(1, total_FIDs + 1):
                df_sub = df.loc[df["input_feat_id"] == i]
                df_sub.reset_index(inplace=True, drop=True)
                avg_value = df_sub.at[0, weighted_field]
                if ident_name:
                    feature_name = df_sub.at[0, ident_name]
                    df_sub.drop(
                        columns=["input_feat_id", ident_name, weighted_field],
                        inplace=True,
                    )
                    html += f"<p><b>{i}. {feature_name}</b><br>{weighted_field}: {avg_value}<br>count of distinct intersecting features: {len(df_sub.index)}<br></p>\n"
                else:
                    df_sub.drop(columns=["input_feat_id", weighted_field],
                                inplace=True)
                    html += f"<p><b>Feature ID: {i}</b><br>{weighted_field}: {avg_value}<br>count of distinct intersecting features: {len(df_sub.index)}<br></p>\n"
                html += f"{df_sub.to_html(bold_rows=False, index=False, na_rep='Null',justify='left')}<br>\n"

                with codecs.open(output_file, "w", encoding="utf-8") as f:
                    f.write("<html><head>\n")
                    f.write(
                        '<meta http-equiv="Content-Type" content="text/html; \
                            charset=utf-8" /></head><body>\n')
                    f.write(html)
                    f.write("</body></html>\n")

                results["reportasHTML"] = output_file

        # log usage
        with open(os.path.join(cmd_folder, "usage_counter.log"), "r+") as f:
            counter = int(f.readline())
            f.seek(0)
            f.write(str(counter + 1))

        # check if counter is a milestone
        if (counter + 1) % 25 == 0:
            appeal_file = NamedTemporaryFile("w", suffix=".html", delete=False)
            self.createHTML(appeal_file.name, counter + 1)
            results["Message"] = appeal_file.name

        return results
예제 #24
0
    def processAlgorithm(self, parameters, context, model_feedback):
        feedback = QgsProcessingMultiStepFeedback(2, model_feedback)

        source = self.parameterAsSource(parameters, self.INPUT, context)
        field_segment_id = self.parameterAsString(parameters, self.FIELD_SEGMENT_ID, context)
        segment_attribute_index = self.parameterAsInt(parameters, self.SEGMENT_ATTRIBUTE, context)
        segment_attribute = self.segment_attribute_options[segment_attribute_index]
        target_field = self.parameterAsString(parameters, self.TARGET_FIELD, context)

        server_name = self.connection_options[self.parameterAsInt(parameters, self.SERVER_NAME, context)]
        graph_name = self.parameterAsString(parameters, self.GRAPH_NAME, context)
        graph_version = self.parameterAsString(parameters, self.GRAPH_VERSION, context)

        feedback.pushInfo("Connect to Graphium server '" + server_name + "' ...")

        graphium = GraphiumGraphDataApi(feedback)
        selected_connection = self.connection_manager.select_graphium_server(server_name)

        if selected_connection is None:
            feedback.reportError('Cannot select connection to Graphium', True)
            return {self.OUTPUT: None}

        if graphium.connect(selected_connection) is False:
            feedback.reportError('Cannot connect to [' + server_name + ']', True)
            return {self.OUTPUT: None}

        feedback.pushInfo("Start downloading task on Graphium server '" + server_name + "' ...")

        total = 100.0 / source.featureCount() if source.featureCount() else 0

        # Read segment IDs
        segment_ids = []
        attributes_per_segment = dict()
        for current, feature in enumerate(source.getFeatures()):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                break

            if not feature[field_segment_id]:
                continue

            if not feature[field_segment_id] in segment_ids:
                segment_ids.append(feature[field_segment_id])
            if len(segment_ids) > 50:
                self.get_segment_attributes(feedback, graphium, graph_name, graph_version, segment_attribute,
                                            segment_ids, attributes_per_segment)
            # Update the progress bar
            feedback.setProgress(int(current * total))
        if len(segment_ids) > 0:
            self.get_segment_attributes(feedback, graphium, graph_name, graph_version, segment_attribute,
                                        segment_ids, attributes_per_segment)

        feedback.setCurrentStep(1)
        feedback.pushInfo("Add attributes to features")

        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, source.fields(),
                                               source.wkbType(), source.sourceCrs())

        for current, feature in enumerate(source.getFeatures()):
            # Stop the algorithm if cancel button has been clicked
            if feedback.isCanceled():
                break

            if feature[field_segment_id]:
                if int(feature[field_segment_id]) in attributes_per_segment:
                    feature[target_field] = attributes_per_segment[int(feature[field_segment_id])]
                else:
                    feedback.pushInfo("No attribute for segment " + str(feature[field_segment_id]))

            sink.addFeature(feature, QgsFeatureSink.FastInsert)

            # Update the progress bar
            feedback.setProgress(int(current * total))

        feedback.setProgress(100)

        return {
            self.OUTPUT: dest_id
        }
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        #get the network handler
        layerHandler = LayerHandler()
        networkHandler = NetworkHandler()
        algRunner = AlgRunner()
        self.nodeTypeNameDict = networkHandler.nodeTypeDict
        # get network layer
        networkLayer = self.parameterAsLayer(parameters, self.NETWORK_LAYER, context)
        if networkLayer is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.NETWORK_LAYER))
        attributeBlackList = self.parameterAsFields(parameters, self.ATTRIBUTE_BLACK_LIST, context)
        ignoreVirtual = self.parameterAsBool(parameters, self.IGNORE_VIRTUAL_FIELDS, context)
        ignorePK = self.parameterAsBool(parameters, self.IGNORE_PK_FIELDS, context)
        # get network node layer
        (nodeSink, dest_id) = self.parameterAsSink(parameters, self.NETWORK_NODES,
                context, self.getFields(), QgsWkbTypes.MultiPoint, networkLayer.sourceCrs())
        #prepairs flag sink for raising errors
        self.prepareFlagSink(parameters, networkLayer, QgsWkbTypes.MultiPoint, context)
        
        waterBodyClasses = self.parameterAsLayer(parameters, self.WATER_BODY_LAYERS, context)
        waterBodyClasses = waterBodyClasses if waterBodyClasses is not None else []
        # get water sink layer
        waterSinkLayer = self.parameterAsLayer(parameters, self.SINK_LAYER, context)
        # get spillway layer
        spillwayLayer = self.parameterAsLayer(parameters, self.SPILLWAY_LAYER, context)
        # get frame layer
        frameLayer = self.parameterAsLayer(parameters, self.REF_LAYER, context)
        currStep = 0
        if frameLayer is None:
            raise QgsProcessingException(self.invalidSourceError(parameters, self.REF_LAYER))
        multiStepFeedback = QgsProcessingMultiStepFeedback(3, feedback)
        multiStepFeedback.setCurrentStep(currStep)
        multiStepFeedback.pushInfo(self.tr('Preparing bounds...'))
        frame = layerHandler.getFrameOutterBounds(frameLayer, algRunner, context, feedback=multiStepFeedback)
        currStep += 1
        # get search radius
        searchRadius = self.parameterAsDouble(parameters, self.SEARCH_RADIUS, context)
        # get ditch layer
        ditchLayer = self.parameterAsLayer(parameters, self.DITCH_LAYER, context)

        #new step
        multiStepFeedback.setCurrentStep(currStep)
        multiStepFeedback.pushInfo(self.tr('Performing node identification...'))
        self.nodeDict = networkHandler.identifyAllNodes(networkLayer=networkLayer, feedback=multiStepFeedback) #zoado, mudar lógica
        multiStepFeedback.pushInfo(self.tr('{node_count} node(s) identificated...').format(node_count=len(self.nodeDict)))
        currStep += 1
        #new step
        multiStepFeedback.setCurrentStep(currStep)
        multiStepFeedback.pushInfo(self.tr('Performing node classification...'))
        networkHandler.nodeDict = self.nodeDict
        self.nodeTypeDict, nodeFlagDict = networkHandler.classifyAllNodes(
                networkLayer=networkLayer,
                frameLyrContourList=frame,
                waterBodiesLayers=waterBodyClasses,
                searchRadius=searchRadius,
                waterSinkLayer=waterSinkLayer,
                spillwayLayer=spillwayLayer,
                feedback=multiStepFeedback,
                attributeBlackList=attributeBlackList,
                excludePrimaryKeys=ignorePK,
                ignoreVirtualFields=ignoreVirtual,
                ditchLayer=ditchLayer
            )
        currStep += 1
        #new step
        multiStepFeedback.setCurrentStep(currStep)
        multiStepFeedback.pushInfo(self.tr('Writing nodes...'))
        self.fillNodeSink(
            nodeSink=nodeSink,
            networkLineLayerName=networkLayer.name(),
            nodeFlagDict=nodeFlagDict,
            feedback=multiStepFeedback)
        return {self.NETWORK_NODES : dest_id, self.FLAGS : self.flag_id}
    def processAlgorithm(self, parameters, context, model_feedback):

        # source: 'export as python script' in processing modeler
        feedback = QgsProcessingMultiStepFeedback(3, model_feedback)

        # pass
        source = self.parameterAsFile(parameters, self.INPUT, context)
        server_name = self.server_name_options[self.parameterAsInt(
            parameters, self.SERVER_NAME, context)]
        graph_name = self.parameterAsString(parameters, self.GRAPH_NAME,
                                            context)
        graph_version = self.graph_version_options[self.parameterAsInt(
            parameters, self.GRAPH_VERSION, context)]
        routing_mode = self.routing_mode_options[self.parameterAsInt(
            parameters, self.ROUTING_MODE, context)]

        if os.path.splitext(source)[-1].lower() == '.json':
            feedback.pushInfo('Load json track file')
            with open(source) as json_data:
                track_data = json.load(json_data)
        elif os.path.splitext(source)[-1].lower() == '.gpx':
            feedback.pushInfo(
                'Convert track file from GPX to JSON format using Graphium:Gpx2JsonConverter'
            )
            try:
                output = processing.run("Graphium:gpx2jsonconverter",
                                        parameters={
                                            'INPUT': source,
                                            'OUTPUT': 'TEMPORARY_OUTPUT'
                                        },
                                        is_child_algorithm=True,
                                        context=context,
                                        feedback=feedback)['OUTPUT']
                with open(output) as json_data:
                    track_data = json.load(json_data)
            except QgsProcessingException as e:
                feedback.reportError(
                    "Could not convert GPX file to JSON: " + str(e), True)
                return {self.OUTPUT_MATCHED_SEGMENTS: None}
        else:
            feedback.reportError(
                "Wrong track file format (" +
                os.path.splitext(source)[-1].lower() + ")", True)
            return {self.OUTPUT_MATCHED_SEGMENTS: None}

        # Connect to Graphium
        feedback.setCurrentStep(2)
        feedback.pushInfo("Connect to Graphium server '" + server_name +
                          "' ...")

        graphium = GraphiumUtilitiesApi(feedback)
        selected_connection = self.connection_manager.select_graphium_server(
            server_name)
        if selected_connection is None:
            feedback.reportError('Cannot select connection to Graphium', True)
            return {self.OUTPUT_MATCHED_SEGMENTS: None}

        if graphium.connect(selected_connection) is False:
            feedback.reportError('Cannot connect to Graphium', True)
            return {self.OUTPUT_MATCHED_SEGMENTS: None}

        feedback.pushInfo("Start Map-Matching task on Graphium server '" +
                          server_name + "' ...")
        response = graphium.do_map_matching(track_data, graph_name,
                                            graph_version, routing_mode)

        # Process map matching result
        if 'segments' in response:
            feedback.pushInfo('Finished map matching task!')
        elif 'error' in response:
            if 'msg' in response['error']:
                if response['error']['msg'] == 'ContentNotFoundError':
                    feedback.reportError(
                        'Graphium server "' + server_name +
                        '" does not support map matching', True)
                else:
                    feedback.reportError(response['error']['msg'], True)
            return {self.OUTPUT_MATCHED_SEGMENTS: None}
        elif 'exception' in response:
            feedback.reportError(response['exception'], True)
            return {self.OUTPUT_MATCHED_SEGMENTS: None}
        else:
            feedback.reportError('Unknown mapmatching error', True)
            return {self.OUTPUT_MATCHED_SEGMENTS: None}

        feedback.setCurrentStep(3)
        feedback.pushInfo("Prepare result vector layer ...")
        vector_layer = self.prepare_vector_layer('matched_track')

        (sink, dest_id) = self.parameterAsSink(parameters,
                                               self.OUTPUT_MATCHED_SEGMENTS,
                                               context, vector_layer.fields(),
                                               QgsWkbTypes.LineString,
                                               vector_layer.sourceCrs())

        total = 100.0 / len(response['segments'])
        for current, segment in enumerate(response['segments']):
            if feedback.isCanceled():
                break
            feature = QgsFeature()
            feature.setGeometry(QgsGeometry.fromWkt(segment['geometry']))
            feature.setFields(vector_layer.fields(), True)
            feature.setAttribute('order', current)
            for attribute_key in segment:
                try:
                    feature.setAttribute(attribute_key, segment[attribute_key])
                except KeyError:
                    pass
            sink.addFeature(feature, QgsFeatureSink.FastInsert)
            feedback.setProgress(int(current * total))

        feedback.pushInfo("Finished preparing vector layer " + dest_id)
        return {
            self.OUTPUT_MATCHED_SEGMENTS:
            dest_id,
            self.OUTPUT_NR_OF_U_TURNS:
            response['nrOfUTurns'],
            self.OUTPUT_NR_OF_SHORTEST_PATH_SEARCHES:
            response['nrOfShortestPathSearches'],
            self.OUTPUT_LENGTH:
            response['length'],
            self.OUTPUT_MATCHED_FACTOR:
            response['matchedFactor'],
            self.OUTPUT_MATCHED_POINTS:
            response['matchedPoints'],
            self.OUTPUT_CERTAIN_PATH_END_SEGMENT_ID:
            response['certainPathEndSegmentId']
        }
예제 #27
0
    def processAlgorithm(self, parameters, context, model_feedback):
        """
        Process algorithm.
        """
        feedback = QgsProcessingMultiStepFeedback(8, model_feedback)
        results = {}
        outputs = {}
        project = QgsProject.instance()

        feedback.setCurrentStep(1)
        if feedback.isCanceled():
            return {}

        feedback.pushInfo("Starting...")

        # Get some parameters
        chid = self.parameterAsString(parameters, "chid", context)
        project.writeEntry("QGIS2FDS", "chid", parameters["chid"])
        path = self.parameterAsFile(parameters, "path", context)
        project.writeEntry("QGIS2FDS", "path", parameters["path"])
        landuse_type = self.parameterAsEnum(parameters, "landuse_type", context)
        project.writeEntry("QGIS2FDS", "landuse_type", parameters["landuse_type"])

        # Get layers in their respective crs
        dem_layer = self.parameterAsRasterLayer(parameters, "dem_layer", context)
        project.writeEntry("QGIS2FDS", "dem_layer", parameters["dem_layer"])
        if parameters["landuse_layer"] is None:  # it is optional
            landuse_layer = None
        else:
            landuse_layer = self.parameterAsRasterLayer(
                parameters, "landuse_layer", context
            )
        project.writeEntry("QGIS2FDS", "landuse_layer", parameters["landuse_layer"])

        # Prepare CRS and their transformations
        project_crs = QgsProject.instance().crs()
        project.writeEntry(
            "QGIS2FDS", "project_crs", project_crs.description()
        )  # save to check if changed
        wgs84_crs = QgsCoordinateReferenceSystem("EPSG:4326")
        dem_crs = dem_layer.crs()

        project_to_wgs84_tr = QgsCoordinateTransform(
            project_crs, wgs84_crs, QgsProject.instance()
        )

        # Get extent in WGS84 CRS
        wgs84_extent = self.parameterAsExtent(
            parameters, "extent", context, crs=wgs84_crs
        )
        project.writeEntry("QGIS2FDS", "extent", parameters["extent"])

        # Get origin in WGS84 CRS
        if parameters["origin"] is not None:
            wgs84_origin = QgsPoint(
                self.parameterAsPoint(parameters, "origin", context)
            )
            wgs84_origin.transform(project_to_wgs84_tr)
            feedback.pushInfo(f"Using user origin: <{wgs84_origin}> WGS84")
        else:
            wgs84_origin = QgsPoint(
                (wgs84_extent.xMinimum() + wgs84_extent.xMaximum()) / 2.0,
                (wgs84_extent.yMinimum() + wgs84_extent.yMaximum()) / 2.0,
            )
            feedback.pushInfo(
                f"Using terrain extent centroid as origin: <{wgs84_origin}> WGS84"
            )
        project.writeEntry("QGIS2FDS", "origin", parameters["origin"])

        # Get fire origin in WGS84 CRS
        if parameters["fire_origin"] is not None:
            wgs84_fire_origin = QgsPoint(
                self.parameterAsPoint(parameters, "fire_origin", context)
            )
            wgs84_fire_origin.transform(project_to_wgs84_tr)
            feedback.pushInfo(f"Using user fire origin: <{wgs84_fire_origin}> WGS84")
        else:
            wgs84_fire_origin = QgsPoint(wgs84_origin.x(), wgs84_origin.y())
            feedback.pushInfo(
                f"Using origin as fire origin: <{wgs84_fire_origin}> WGS84"
            )
        project.writeEntry("QGIS2FDS", "fire_origin", parameters["fire_origin"])

        # Get UTM CRS from origin
        utm_epsg = utils.lonlat_to_epsg(lon=wgs84_origin.x(), lat=wgs84_origin.y())
        utm_crs = QgsCoordinateReferenceSystem(utm_epsg)
        feedback.pushInfo(f"Using UTM CRS: <{utm_crs.description()}>")

        # Get extent in UTM CRS and DEM CRS
        utm_extent = self.parameterAsExtent(parameters, "extent", context, crs=utm_crs,)
        dem_extent = self.parameterAsExtent(parameters, "extent", context, crs=dem_crs)

        # Get origin in UTM CRS
        wgs84_to_utm_tr = QgsCoordinateTransform(
            wgs84_crs, utm_crs, QgsProject.instance()
        )
        utm_origin = QgsPoint(wgs84_origin.x(), wgs84_origin.y())
        utm_origin.transform(wgs84_to_utm_tr)

        if utm_origin == wgs84_origin:  # check for QGIS bug
            raise QgsProcessingException(
                f"QGIS bug: UTM Origin <{utm_origin} and WGS84 Origin <{wgs84_origin}> cannot be the same!"
            )

        # Get fire origin in UTM CRS
        utm_fire_origin = QgsPoint(wgs84_fire_origin.x(), wgs84_fire_origin.y())
        utm_fire_origin.transform(wgs84_to_utm_tr)

        # Save texture

        feedback.pushInfo("Saving texture image...")

        utils.write_image(
            destination_crs=utm_crs,
            extent=utm_extent,
            filepath=f"{path}/{chid}_texture.png",
            imagetype="png",
        )

        feedback.setCurrentStep(2)
        if feedback.isCanceled():
            return {}

        # QGIS geographic transformations
        # Creating sampling grid in DEM crs

        feedback.pushInfo("Creating sampling grid layer from DEM...")

        xspacing = dem_layer.rasterUnitsPerPixelX()
        yspacing = dem_layer.rasterUnitsPerPixelY()
        x0, y0, x1, y1 = (  # terrain extent in DEM CRS
            dem_extent.xMinimum(),
            dem_extent.yMinimum(),
            dem_extent.xMaximum(),
            dem_extent.yMaximum(),
        )
        xd0, yd1 = (  # DEM extent in DEM CRS
            dem_layer.extent().xMinimum(),
            dem_layer.extent().yMaximum(),
        )
        # align terrain extent to DEM grid (gridding starts from top left corner)
        x0 = xd0 + round((x0 - xd0) / xspacing) * xspacing + xspacing / 2.0
        y1 = yd1 + round((y1 - yd1) / yspacing) * yspacing - yspacing / 2.0
        dem_extent = QgsRectangle(x0, y0, x1, y1)  # terrain extent in DEM CRS

        alg_params = {
            "CRS": dem_crs,
            "EXTENT": dem_extent,
            "HOVERLAY": 0,
            "HSPACING": xspacing,
            "TYPE": 0,  # Points
            "VOVERLAY": 0,
            "VSPACING": yspacing,
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
        }
        outputs["CreateGrid"] = processing.run(
            "native:creategrid",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(3)
        if feedback.isCanceled():
            return {}

        # QGIS geographic transformations
        # Draping Z values to sampling grid in DEM crs

        feedback.pushInfo("Setting Z values from DEM...")
        alg_params = {
            "BAND": 1,
            "INPUT": outputs["CreateGrid"]["OUTPUT"],
            "NODATA": 0,
            "RASTER": dem_layer,
            "SCALE": 1,
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
        }
        outputs["DrapeSetZValueFromRaster"] = processing.run(
            "native:setzfromraster",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(4)
        if feedback.isCanceled():
            return {}

        # QGIS geographic transformations
        # Reprojecting sampling grid to UTM CRS

        feedback.pushInfo("Reprojecting sampling grid layer to UTM CRS...")
        alg_params = {
            "INPUT": outputs["DrapeSetZValueFromRaster"]["OUTPUT"],
            "TARGET_CRS": utm_crs,
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
        }
        outputs["ReprojectLayer"] = processing.run(
            "native:reprojectlayer",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(5)
        if feedback.isCanceled():
            return {}

        # QGIS geographic transformations
        # Adding geom attributes (x, y, z) to sampling grid in UTM CRS

        feedback.pushInfo("Adding geometry attributes to sampling grid layer...")
        alg_params = {
            "CALC_METHOD": 0,  # Layer CRS
            "INPUT": outputs["ReprojectLayer"]["OUTPUT"],
            "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT,
        }
        outputs["AddGeometryAttributes"] = processing.run(
            "qgis:exportaddgeometrycolumns",
            alg_params,
            context=context,
            feedback=feedback,
            is_child_algorithm=True,
        )

        feedback.setCurrentStep(6)
        if feedback.isCanceled():
            return {}

        # QGIS geographic transformations
        # Sampling landuse layer with sampling grid in UTM CRS

        if landuse_layer:
            feedback.pushInfo("Sampling landuse...")
            alg_params = {
                "COLUMN_PREFIX": "landuse",
                "INPUT": outputs["AddGeometryAttributes"]["OUTPUT"],
                "RASTERCOPY": parameters["landuse_layer"],
                "OUTPUT": parameters["sampling_layer"],
            }
            outputs["sampling_layer"] = processing.run(
                "qgis:rastersampling",
                alg_params,
                context=context,
                feedback=feedback,
                is_child_algorithm=True,
            )

            results["sampling_layer"] = outputs["sampling_layer"]["OUTPUT"]
            point_layer = context.getMapLayer(results["sampling_layer"])
        else:
            feedback.pushInfo("No landuse sampling.")
            results["sampling_layer"] = outputs["AddGeometryAttributes"]["OUTPUT"]
            point_layer = context.getMapLayer(results["sampling_layer"])
            # add fake landuse
            point_layer.dataProvider().addAttributes(
                (QgsField("landuse", QVariant.Int),)
            )
            point_layer.updateFields()

        feedback.setCurrentStep(7)
        if feedback.isCanceled():
            return {}

        # Prepare geometry

        feedback.pushInfo("Building lists of vertices and faces with landuses...")

        verts, faces, landuses, landuses_set = geometry.get_geometry(
            layer=point_layer, utm_origin=utm_origin,
        )

        feedback.setCurrentStep(8)
        if feedback.isCanceled():
            return {}

        # Write the FDS case file

        feedback.pushInfo("Writing the FDS case file...")

        content = fds.get_case(
            dem_layer=dem_layer,
            landuse_layer=landuse_layer,
            chid=chid,
            wgs84_origin=wgs84_origin,
            utm_origin=utm_origin,
            wgs84_fire_origin=wgs84_fire_origin,
            utm_fire_origin=utm_fire_origin,
            utm_crs=utm_crs,
            verts=verts,
            faces=faces,
            landuses=landuses,
            landuse_type=landuse_type,
            landuses_set=landuses_set,
            utm_extent=utm_extent,
        )
        utils.write_file(filepath=f"{path}/{chid}.fds", content=content)

        return results
    def processAlgorithm(self, parameters, context, model_feedback):
        """
        Process the algorithm
        :param parameters: parameters of the process
        :param context: context of the process
        :param model_feedback: feedback instance for the process
        :return:
        """
        # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the
        # overall progress through the model
        self.xml_path = parameters["XMLPATH"]
        self.gpkg_path = parameters["GPKGPATH"]
        if not self.xml_path.lower().endswith(".xml"):
            feedback = QgsProcessingMultiStepFeedback(0, model_feedback)
            feedback.reportError(
                "XML Workspace Definition is not an XML file!", True)
            return {}
        if not self.gpkg_path.lower().endswith(".gpkg"):
            feedback = QgsProcessingMultiStepFeedback(0, model_feedback)
            feedback.reportError("GeoPackage is not an GPKG file!", True)
            return {}
        self.pg_conn_name = parameters["DBNAME"]
        self.pg_schema = parameters["SCHEMA"]
        self.pg_drop_before = parameters["DROPIFEXISTS"]
        dataset_list = self.getDatasets()
        feedback = QgsProcessingMultiStepFeedback(2 + len(dataset_list),
                                                  model_feedback)
        step = 0
        self.create_pk_metadata_table(context, feedback)
        step = 1
        for dataset in dataset_list:
            step += 1
            definition = self.getDatasetDef(dataset)
            if definition is not None:
                try:
                    in_layer = self.get_gpkg_vector_layer(definition[0])
                    if in_layer is not None:
                        feedback.pushInfo("Feature Class: " + definition[0])
                        try:
                            alg_params = {
                                'DATABASE': self.pg_conn_name,
                                'SQL': definition[1]
                            }
                            feedback.pushInfo(
                                "   processing (A) => qgis:postgisexecutesql")
                            processing.run('qgis:postgisexecutesql',
                                           alg_params,
                                           context=context,
                                           feedback=feedback,
                                           is_child_algorithm=True)
                        except Exception as e1:
                            feedback.reportError(
                                "Error creating table definition: \n" +
                                definition[1] + ": " + str(e1), False)
                            break

                        try:
                            # Esporta in PostgreSQL (connessioni disponibili)
                            alg_params = {
                                'ADDFIELDS': False,
                                'APPEND': False,
                                'A_SRS': None,
                                'CLIP': False,
                                'DATABASE': self.pg_conn_name,
                                'DIM': 0,
                                'GEOCOLUMN': 'geom',
                                'GT': '',
                                'GTYPE': definition[4],
                                'INDEX': False,
                                'INPUT':
                                self.get_gpkg_vector_layer(definition[0]),
                                'LAUNDER': False,
                                'OPTIONS': '',
                                'OVERWRITE': True,
                                'PK': '',
                                'PRECISION': True,
                                'PRIMARY_KEY': '',
                                'PROMOTETOMULTI': True,
                                'SCHEMA': self.pg_schema,
                                'SEGMENTIZE': '',
                                'SHAPE_ENCODING': '',
                                'SIMPLIFY': '',
                                'SKIPFAILURES': False,
                                'SPAT': None,
                                'S_SRS': None,
                                'TABLE': definition[0].lower() + '_tmp',
                                'T_SRS': None,
                                'WHERE': ''
                            }
                            feedback.pushInfo(
                                "   processing (B) => qgis:importvectorintopostgisdatabaseavailableconnections"
                            )
                            processing.run(
                                'gdal:importvectorintopostgisdatabaseavailableconnections',
                                alg_params,
                                context=context,
                                feedback=feedback,
                                is_child_algorithm=True)
                        except Exception as e2:
                            feedback.reportError(
                                "Error importing data: \n" + definition[0] +
                                ": " + str(e2), False)
                            break

                        try:
                            #Copy from TMP to FINAL table
                            sql_copy = "INSERT INTO %s.%s(%s) SELECT %s FROM %s.%s_tmp" % (
                                self.pg_schema, definition[0], definition[2],
                                definition[3], self.pg_schema,
                                definition[0]) + ";"
                            sql_drop = "DROP TABLE %s.%s_tmp" % (
                                self.pg_schema, definition[0]) + ";"
                            alg_params = {
                                'DATABASE': self.pg_conn_name,
                                'SQL': sql_copy + sql_drop
                            }
                            feedback.pushInfo(
                                "   processing (C) => qgis:postgisexecutesql")
                            processing.run('qgis:postgisexecutesql',
                                           alg_params,
                                           context=context,
                                           feedback=feedback,
                                           is_child_algorithm=True)
                        except Exception as e3:
                            feedback.reportError(
                                "Error moving data: \n" + sql_copy + sql_drop +
                                ": " + str(e3), False)
                            break
                except Exception as e:
                    feedback.reportError(
                        "Error importing domain " + definition[1] + ": " +
                        str(e), False)
            feedback.setCurrentStep(step)
        results = {}
        outputs = {}
        return results
예제 #29
0
    def processAlgorithm(self, parameters, context, feedback):
        """
        Here is where the processing itself takes place.
        """
        self.layerHandler = LayerHandler()
        inputLyr = self.parameterAsVectorLayer(parameters, self.INPUT, context)
        onlySelected = self.parameterAsBool(parameters, self.SELECTED, context)
        searchRadius = self.parameterAsDouble(parameters, self.TOLERANCE,
                                              context)
        lineFilterLyrList = self.parameterAsLayerList(parameters,
                                                      self.LINEFILTERLAYERS,
                                                      context)
        polygonFilterLyrList = self.parameterAsLayerList(
            parameters, self.POLYGONFILTERLAYERS, context)
        ignoreNotSplit = self.parameterAsBool(parameters, self.TYPE, context)
        ignoreInner = self.parameterAsBool(parameters, self.IGNOREINNER,
                                           context)
        self.prepareFlagSink(parameters, inputLyr, QgsWkbTypes.Point, context)

        # Compute the number of steps to display within the progress bar and
        # get features from source
        feedbackTotal = 3
        feedbackTotal += 1 if lineFilterLyrList or polygonFilterLyrList else 0
        feedbackTotal += 1 if not ignoreInner else 0
        multiStep = QgsProcessingMultiStepFeedback(feedbackTotal, feedback)
        currentStep = 0
        multiStep.setCurrentStep(currentStep)
        multiStep.pushInfo(self.tr('Building search structure...'))
        endVerticesDict = self.layerHandler.buildInitialAndEndPointDict(
            inputLyr, onlySelected=onlySelected, feedback=multiStep)

        #search for dangles candidates
        currentStep += 1
        multiStep.setCurrentStep(currentStep)
        multiStep.pushInfo(self.tr('Looking for dangles...'))
        pointList = self.searchDanglesOnPointDict(endVerticesDict, multiStep)
        #build filter layer
        currentStep += 1
        multiStep.setCurrentStep(currentStep)
        multiStep.pushInfo(self.tr('Filtering dangles candidates...'))
        filterLayer = self.buildFilterLayer(lineFilterLyrList,
                                            polygonFilterLyrList,
                                            context,
                                            multiStep,
                                            onlySelected=onlySelected)
        #filter pointList with filterLayer

        if filterLayer:
            currentStep += 1
            multiStep.setCurrentStep(currentStep)
            multiStep.pushInfo(
                self.tr('Filtering dangles candidates with filter...'))
            filteredPointList = self.filterPointListWithFilterLayer(
                pointList, filterLayer, searchRadius, multiStep)
        else:
            filteredPointList = pointList
        #filter with own layer
        if not ignoreInner:  #True when looking for dangles on contour lines
            currentStep += 1
            multiStep.setCurrentStep(currentStep)
            multiStep.pushInfo(self.tr('Filtering inner dangles...'))
            filteredPointList = self.filterPointListWithFilterLayer(
                filteredPointList,
                inputLyr,
                searchRadius,
                multiStep,
                isRefLyr=True,
                ignoreNotSplit=ignoreNotSplit)
        #build flag list with filtered points
        currentStep += 1
        multiStep.setCurrentStep(currentStep)
        multiStep.pushInfo(self.tr('Raising flags...'))
        if filteredPointList:
            # currentValue = feedback.progress()
            currentTotal = 100 / len(filteredPointList)
            for current, point in enumerate(filteredPointList):
                if multiStep.isCanceled():
                    break
                self.flagFeature(
                    QgsGeometry.fromPointXY(point),
                    self.tr('Dangle on {0}').format(inputLyr.name()))
                multiStep.setProgress(current * currentTotal)
        # feedback.setProgress(100)
        return {self.FLAGS: self.flag_id}
    def processAlgorithm(self, parameters, context, feedback):
        feedback = QgsProcessingMultiStepFeedback(1, feedback)
        results = {}
        outputs = {}

        # Pfade definieren + Timestamp
        timestamp = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
        temp_path = str(parameters[self.TEMP]) + '/temp_' + str(timestamp)
        final_path = str(parameters[self.TEMP]) + '/final_' + str(timestamp)

        if not os.path.exists(temp_path):
            os.makedirs(temp_path)
        if not os.path.exists(final_path):
            os.makedirs(final_path)

        #feedback.pushInfo(str(parameters[self.INPUT_extent]))

        ## Cell Size und EPSG-Code
        raster_cs = gdal.Open(str(parameters[self.INPUT_ALS_new]))
        gt_cs = raster_cs.GetGeoTransform()
        proj = osr.SpatialReference(wkt=raster_cs.GetProjection())
        cs = gt_cs[1]
        epsg = proj.GetAttrValue('AUTHORITY', 1)
        srs = osr.SpatialReference()
        srs.ImportFromEPSG(int(epsg))

        ## Buffer
        buffer = out = temp_path + '/' + 'extent.shp'
        alg_params = {
            'DISSOLVE': False,
            'DISTANCE': -0.1,
            'END_CAP_STYLE': 2,
            'INPUT': str(parameters[self.INPUT_Shape]),
            'JOIN_STYLE': 1,
            'MITER_LIMIT': 2,
            'SEGMENTS': 1,
            'OUTPUT': buffer
        }
        processing.run('native:buffer',
                       alg_params,
                       context=context,
                       feedback=feedback,
                       is_child_algorithm=True)

        ## Clip Rasters
        out_new = temp_path + '/' + 'dhm_new.tif'
        out_old = temp_path + '/' + 'dhm_old.tif'
        alg_params = {
            'ALPHA_BAND': False,
            'CROP_TO_CUTLINE': True,
            'DATA_TYPE': 0,
            'EXTRA': '',
            'INPUT': str(parameters[self.INPUT_ALS_new]),
            'KEEP_RESOLUTION': False,
            'MASK': str(buffer),
            'MULTITHREADING': False,
            'NODATA': None,
            'OPTIONS': '',
            'SET_RESOLUTION': False,
            'SOURCE_CRS': QgsCoordinateReferenceSystem('EPSG:' + str(epsg)),
            'TARGET_CRS': QgsCoordinateReferenceSystem('EPSG:' + str(epsg)),
            'X_RESOLUTION': None,
            'Y_RESOLUTION': None,
            'OUTPUT': out_new
        }
        processing.run('gdal:cliprasterbymasklayer',
                       alg_params,
                       context=context,
                       feedback=feedback,
                       is_child_algorithm=True)

        alg_params = {
            'ALPHA_BAND': False,
            'CROP_TO_CUTLINE': True,
            'DATA_TYPE': 0,
            'EXTRA': '',
            'INPUT': str(parameters[self.INPUT_ALS_old]),
            'KEEP_RESOLUTION': False,
            'MASK': str(buffer),
            'MULTITHREADING': False,
            'NODATA': None,
            'OPTIONS': '',
            'SET_RESOLUTION': False,
            'SOURCE_CRS': QgsCoordinateReferenceSystem('EPSG:' + str(epsg)),
            'TARGET_CRS': QgsCoordinateReferenceSystem('EPSG:' + str(epsg)),
            'X_RESOLUTION': None,
            'Y_RESOLUTION': None,
            'OUTPUT': out_old
        }
        processing.run('gdal:cliprasterbymasklayer',
                       alg_params,
                       context=context,
                       feedback=feedback,
                       is_child_algorithm=True)

        ## Cell Size/ Extent
        raster_cs = gdal.Open(out_new)
        gt_cs = raster_cs.GetGeoTransform()
        cs = gt_cs[1]

        del raster_cs
        del gt_cs

        dtm_clip_gdal = gdal.Open(out_new)
        format = "GTiff"
        driver = gdal.GetDriverByName(format)
        band1 = dtm_clip_gdal.GetRasterBand(1)
        im = Image.open(out_new)
        pix = im.load()
        gt = dtm_clip_gdal.GetGeoTransform()
        feedback.pushInfo(str(gt))
        width = dtm_clip_gdal.RasterXSize
        height = dtm_clip_gdal.RasterYSize
        minx = gt[0]
        miny = gt[3] + width * gt[4] + height * gt[5]
        maxx = gt[0] + width * gt[1] + height * gt[2]
        maxy = gt[3]
        extent = str(minx) + "," + str(maxx) + "," + str(miny) + "," + str(
            maxy)
        extent2 = (minx, maxx, miny, maxy)
        feedback.pushInfo(str(extent))
        feedback.pushInfo(str(width))
        feedback.pushInfo(str(height))

        # Create empty grids
        grid_diff = np.zeros(shape=(width, height), dtype=np.float32)
        grid_diff_uc = np.zeros(shape=(width, height), dtype=np.float32)

        ## DOD
        out2_old = temp_path + '/' + 'diff.tif'

        ##Rasters to Arrays
        new_rds = gdal.Open(out_new)
        format = "GTiff"
        driver1 = gdal.GetDriverByName(format)
        band_new = new_rds.GetRasterBand(1)
        im_new = Image.open(out_new)
        pix_new = im_new.load()

        old_rds = gdal.Open(out_old)
        format = "GTiff"
        driver2 = gdal.GetDriverByName(format)
        band_old = old_rds.GetRasterBand(1)
        im_old = Image.open(out_old)
        pix_old = im_old.load()

        for row in range(0, width):
            for col in range(0, height):
                val_new = pix_new[row, col]
                val_old = pix_old[row, col]
                if val_new > -9999.0:
                    val_diff = val_new - val_old
                    #feedback.pushInfo(str(val_new))
                    grid_diff[row, col] = val_diff

        grid_diff = np.flip(grid_diff, 1)
        grid_diff = np.rot90(grid_diff)
        imsave = Image.fromarray(grid_diff, mode='F')
        imsave.save(out2_old, "TIFF")

        ## Add Spatial Reference
        out2 = final_path + '/' + 'diff.tif'

        src_ds = gdal.Open(out2_old)
        format = "GTiff"
        driver = gdal.GetDriverByName(format)

        dst_ds = driver.CreateCopy(out2, src_ds, 0)
        dst_ds.SetGeoTransform(gt)
        srs = osr.SpatialReference()
        srs.ImportFromEPSG(int(epsg))
        dest_wkt = srs.ExportToWkt()
        dst_ds.SetProjection(dest_wkt)

        # Close files
        dst_ds = None
        src_ds = None

        ## ----------------------------------------------------------------------------------------------------------##
        ## ChangeDetection (Uncertainty Model)
        sel = self.SELECTIONS[self.parameterAsEnum(parameters, self.SELECTION,
                                                   context)]
        if str(sel) == str('UncertaintyModel'):
            feedback.pushInfo(str(sel))
            out_uc = temp_path + '/' + 'dhm_uc.tif'
            alg_params = {
                'ALPHA_BAND': False,
                'CROP_TO_CUTLINE': True,
                'DATA_TYPE': 0,
                'EXTRA': '',
                'INPUT': str(parameters[self.INPUT_UC]),
                'KEEP_RESOLUTION': False,
                'MASK': str(buffer),
                'MULTITHREADING': False,
                'NODATA': None,
                'OPTIONS': '',
                'SET_RESOLUTION': False,
                'SOURCE_CRS':
                QgsCoordinateReferenceSystem('EPSG:' + str(epsg)),
                'TARGET_CRS':
                QgsCoordinateReferenceSystem('EPSG:' + str(epsg)),
                'X_RESOLUTION': None,
                'Y_RESOLUTION': None,
                'OUTPUT': out_uc
            }
            processing.run('gdal:cliprasterbymasklayer',
                           alg_params,
                           context=context,
                           feedback=feedback,
                           is_child_algorithm=True)

            del (out_uc)

            analyse = open(final_path + '/' + 'change_detection_UC.txt', "w")
            analyse_csv = open(final_path + '/' + 'change_detection_UC.csv',
                               "w")
            analyse_csv.write(
                " ; AOI [m2]; Detectable Change [m2]; Detectable Change [%]; Surface Lowering [m2]; Surface Raising [m2]; Surface Lowering [m3]; Surface Raising [m3]; Volume of Difference [m3]; Net Volume of Difference [m3]"
                + "\n")

            ##Rasters to Arrays
            out_uc = temp_path + '/' + 'dhm_uc.tif'

            diff_rds = gdal.Open(out2)
            format = "GTiff"
            driver3 = gdal.GetDriverByName(format)
            band_diff = diff_rds.GetRasterBand(1)
            im_diff = Image.open(out2)
            pix_diff = im_diff.load()

            uc_rds = gdal.Open(out_uc)
            format = "GTiff"
            driver4 = gdal.GetDriverByName(format)
            band_uc = uc_rds.GetRasterBand(1)
            im_uc = Image.open(out_uc)
            pix_uc = im_uc.load()

            ## Classification1 - 0 % 0.1
            countAOI = 0
            countPosGes = 0
            countNegGes = 0
            countPos = 0
            countNeg = 0
            countPosArea = 0
            countNegArea = 0
            countPosAreaGes = 0
            countNegAreaGes = 0
            countAcc = 0
            countCell = 0
            countCellVol = 0

            for row in range(0, width):
                for col in range(0, height):
                    diff = pix_diff[row, col]
                    if diff > -9999.0 and diff < 100:
                        countAOI = countAOI + (cs * cs)
                    if diff < 0 and diff > -100:
                        volNegGes = cs * cs * (abs(diff))
                        countNegGes = countNegGes + volNegGes
                        countNegAreaGes = countNegAreaGes + (cs * cs)
                    if diff > 0 and diff < 100:
                        volPosGes = cs * cs * (abs(diff))
                        countPosGes = countPosGes + volPosGes
                        countPosAreaGes = countPosAreaGes + (cs * cs)
                    if diff < -0.1 and diff > -100:  # 0.1 m ist der Standardfehler zwischen den 2 Modellen
                        volNeg = cs * cs * (
                            abs(diff) - 0.1
                        )  # -0.1 Standardfehler wird bei GCD-Tool nicht abgezogen
                        countNeg = countNeg + volNeg
                        countNegArea = countNegArea + (cs * cs)
                        countAcc = countAcc + (cs * cs * 0.1)
                    if diff > 0.1 and diff < 100:
                        volPos = cs * cs * (diff - 0.1)
                        countPos = countPos + (volPos)
                        countPosArea = countPosArea + (cs * cs)
                        countAcc = countAcc + (cs * cs * 0.1)
                    if diff < 0 and diff > -0.1:
                        countCell = countCell + 1
                        countCellVol = countCellVol + (cs * cs * abs(diff))
                        #print countCell
                    if diff > 0 and diff < 0.1:
                        countCell = countCell + 1
                        countCellVol = countCellVol + (cs * cs * abs(diff))

            analyse.write("Total Area [m2] of Interest: " + str(countAOI) +
                          "\n")
            analyse.write("Total Area [km2] of Interest: " +
                          str(countAOI / 1000000) + "\n")
            analyse.write("\n")
            analyse.write("Total Area [m2] of Detectable Change: " +
                          str(countPosAreaGes + countNegAreaGes) + "\n")
            analyse.write(
                "Total Area of Interest [%] with Detectable Change: " +
                str(((countPosAreaGes + countNegAreaGes) / countAOI) * 100) +
                "\n")
            analyse.write("Total Area [m2] of Surface Lowering: " +
                          str(countNegAreaGes) + "\n")
            analyse.write("Total Area [m2] of Surface Raising: " +
                          str(countPosAreaGes) + "\n")
            analyse.write("Total Volume [m3] of Surface Lowering: " +
                          str(countNegGes) + "\n")
            analyse.write("Total Volume [m3] of Surface Raising: " +
                          str(countPosGes) + "\n")
            analyse.write("Total Volume [m3] of Difference: " +
                          str(countPosGes + countNegGes) + "\n")
            analyse.write("Total Net Volume [m3] of Difference: " +
                          str(countPosGes - countNegGes) + "\n")
            analyse.write("\n")
            analyse.write("\n")

            analyse_csv.write(
                "0.0; " + str(countAOI) + "; " +
                str(countPosAreaGes + countNegAreaGes) + "; " +
                str(((countPosAreaGes + countNegAreaGes) / countAOI) * 100) +
                "; " + str(countNegAreaGes) + "; " + str(countPosAreaGes) +
                "; " + str(countNegGes) + "; " + str(countPosGes) + "; " +
                str(countPosGes + countNegGes) + "; " +
                str(countPosGes - countNegGes) + "\n")
            net_v_0 = countPosGes - countNegGes
            sr_0 = countPosGes
            sl_0 = countNegGes

            analyse.write("Analysis with Threshold of +/- 0.1" + "\n")
            analyse.write(
                "Thresholded (0.1) Area [m2] of Detectable Change: " +
                str(countPosArea + countNegArea) + "\n")
            analyse.write(
                "Thresholded (0.1) Area [km2] of Detectable Change: " +
                str((countPosArea + countNegArea) / 1000000) + "\n")
            analyse.write(
                "Thresholded (0.1) Area of Interest [%] with Detectable Change: "
                + str(((countPosArea + countNegArea) / countAOI) * 100) + "\n")
            analyse.write("Thresholded (0.1) Area [m2] of Surface Lowering: " +
                          str(countNegArea) + "\n")
            analyse.write(
                "Thresholded (0.1) Area [km2] of Surface Lowering: " +
                str(countNegArea / 1000000) + "\n")
            analyse.write("Thresholded (0.1) Area [m2] of Surface Raising: " +
                          str(countPosArea) + "\n")
            analyse.write("Thresholded (0.1) Area [km2] of Surface Raising: " +
                          str(countPosArea / 1000000) + "\n")
            analyse.write(
                "Thresholded (0.1) Volume [m3] of Surface Lowering: " +
                str(countNeg) + "\n")
            analyse.write(
                "Thresholded (0.1) Volume [m3] of Surface Raising: " +
                str(countPos) + "\n")
            analyse.write("Thresholded (0.1) Volume [m3] of Difference: " +
                          str(countPos + countNeg) + "\n")
            analyse.write("Thresholded (0.1) Net Volume [m3] of Difference: " +
                          str(countPos - countNeg) + "\n")
            analyse.write("\n")
            analyse.write("\n")
            analyse.write(
                "Volume [m3] of Error within Threshold of -0.1 and 0.1: " +
                str(countAcc) + "\n")
            analyse.write("Count of Cells within -0.1 and 0.1: " +
                          str(countCell) + "\n")
            analyse.write("Volume [m3] of Cells between -0.1 and 0.1: " +
                          str(countCellVol) + "\n")
            analyse.write(
                "Percent [%] of Error of Cells between -0.1 and 0.1: " +
                str((countCellVol / (countPosGes + countNegGes)) * 100) + "\n")
            analyse.write("\n")
            analyse.write("\n")

            analyse_csv.write("0.1; " + str(countAOI) + "; " +
                              str(countPosArea + countNegArea) + "; " +
                              str(((countPosArea + countNegArea) / countAOI) *
                                  100) + "; " + str(countNegArea) + "; " +
                              str(countPosArea) + "; " + str(countNeg) + "; " +
                              str(countPos) + "; " + str(countPos + countNeg) +
                              "; " + str(countPos - countNeg) + "\n")
            net_v_1 = countPos - countNeg
            sr_1 = countPos
            sl_1 = countNeg

            del countPos
            del countNeg
            del countPosArea
            del countNegArea
            del countAcc
            del countCell
            del countCellVol

            ## Classification2 - 0.3
            countPos = 0
            countNeg = 0
            countPosArea = 0
            countNegArea = 0
            countAcc = 0
            countCell = 0
            countCellVol = 0

            for row in range(0, width):
                for col in range(0, height):
                    diff = pix_diff[row, col]
                    ES = pix_uc[row, col]
                    ES2 = abs(ES)
                    if diff < -0.3 and diff > -100:  # 0.1 ist der Standardfehler zwischen den 2 Modellen
                        volNeg = cs * cs * (abs(diff) - 0.3)
                        countNeg = countNeg + volNeg
                        countNegArea = countNegArea + (cs * cs)
                        countAcc = countAcc + (cs * cs * 0.3)
                    if diff > 0.3 and diff < 100:
                        volPos = cs * cs * (diff - 0.3)
                        countPos = countPos + (volPos)
                        countPosArea = countPosArea + (cs * cs)
                        countAcc = countAcc + (cs * cs * 0.3)
                    if diff < 0 and diff > -0.3:
                        countCell = countCell + 1
                        countCellVol = countCellVol + (cs * cs * abs(diff))
                    if diff > 0 and diff < 0.3:
                        countCell = countCell + 1
                        countCellVol = countCellVol + (cs * cs * diff)

            analyse.write("Analysis with Threshold of +/- 0.3" + "\n")
            analyse.write(
                "Thresholded (0.3) Area [m2] of Detectable Change: " +
                str(countPosArea + countNegArea) + "\n")
            analyse.write(
                "Thresholded (0.3) Area [km2] of Detectable Change: " +
                str((countPosArea + countNegArea) / 1000000) + "\n")
            analyse.write(
                "Thresholded (0.3) of Interest [%] with Detectable Change: " +
                str(((countPosArea + countNegArea) / countAOI) * 100) + "\n")
            analyse.write("Thresholded (0.3) Area [m2] of Surface Lowering: " +
                          str(countNegArea) + "\n")
            analyse.write(
                "Thresholded (0.3) Area [km2] of Surface Lowering: " +
                str(countNegArea / 1000000) + "\n")
            analyse.write("Thresholded (0.3) Area [m2] of Surface Raising: " +
                          str(countPosArea) + "\n")
            analyse.write("Thresholded (0.3) Area [km2] of Surface Raising: " +
                          str(countPosArea / 1000000) + "\n")
            analyse.write(
                "Thresholded (0.3) Volume [m3] of Surface Lowering: " +
                str(countNeg) + "\n")
            analyse.write(
                "Thresholded (0.3) Volume [m3] of Surface Raising: " +
                str(countPos) + "\n")
            analyse.write("Thresholded (0.3) Volume [m3] of Difference: " +
                          str(countPos + countNeg) + "\n")
            analyse.write("Thresholded (0.3) Net Volume [m3] of Difference: " +
                          str(countPos - countNeg) + "\n")
            analyse.write("\n")
            analyse.write(
                "Volume [m3] of Error within Threshold of -0.3 and 0.3: " +
                str(countAcc) + "\n")
            analyse.write("Count of Cells within -0.3 and 0.3: " +
                          str(countCell) + "\n")
            analyse.write("Volume [m3] of Cells between -0.3 and 0.3: " +
                          str(countCellVol) + "\n")
            analyse.write(
                "Percent [%] of Error of Cells between -0.3 and 0.3: " +
                str((countCellVol / (countPosGes + countNegGes)) * 100) + "\n")
            analyse.write("\n")
            analyse.write("\n")

            analyse_csv.write("0.3; " + str(countAOI) + "; " +
                              str(countPosArea + countNegArea) + "; " +
                              str(((countPosArea + countNegArea) / countAOI) *
                                  100) + "; " + str(countNegArea) + "; " +
                              str(countPosArea) + "; " + str(countNeg) + "; " +
                              str(countPos) + "; " + str(countPos + countNeg) +
                              "; " + str(countPos - countNeg) + "\n")
            net_v_2 = countPos - countNeg
            sr_2 = countPos
            sl_2 = countNeg

            del countPos
            del countNeg
            del countPosArea
            del countNegArea
            del countAcc
            del countCell
            del countCellVol

            ## Classification3 - UC
            countAOI = 0
            countPosGes = 0
            countNegGes = 0
            countPos = 0
            countNeg = 0
            countPosArea = 0
            countNegArea = 0
            countES = 0
            countESneg = 0
            countESpos = 0
            countAcc = 0
            countCell = 0
            countCellVol = 0
            for row in range(0, width):
                for col in range(0, height):
                    diff = pix_diff[row, col]
                    ES = pix_uc[row, col]
                    ES2 = abs(ES)
                    if diff > -9999.0 and diff < 100:
                        countAOI = countAOI + (cs * cs)
                    if diff < -ES2 and diff > -100.0:
                        grid_diff_uc[row, col] = diff + ES2
                        volESneg = cs * cs * (abs(diff) - ES2)
                        countESneg = countESneg + volESneg
                        countNegArea = countNegArea + (cs * cs)
                        countAcc = countAcc + (cs * cs * ES2)
                    if diff > ES2 and diff < 100:
                        grid_diff_uc[row, col] = diff - ES2
                        volESpos = cs * cs * (diff - ES2)
                        countESpos = countESpos + volESpos
                        countPosArea = countPosArea + (cs * cs)
                        countAcc = countAcc + (cs * cs * 0.1)
                    if diff < 0 and diff > -ES2:
                        grid_diff_uc[row, col] = 0.0
                        countCell = countCell + 1
                        countCellVol = countCellVol + (cs * cs * abs(diff))
                        #print countCell
                    if diff > 0 and diff < ES2:
                        grid_diff_uc[row, col] = 0.0
                        countCell = countCell + 1
                        countCellVol = countCellVol + (cs * cs * abs(diff))

            analyse.write("Analysis including Uncertainty Analysis" + "\n")
            analyse.write("Thresholded Area [m2] of Detectable Change: " +
                          str(countPosArea + countNegArea) + "\n")
            analyse.write(
                "Thresholded Area of Interest [%] with Detectable Change: " +
                str(((countPosArea + countNegArea) / countAOI) * 100) + "\n")
            analyse.write("Thresholded Volume [m3] of Surface Lowering: " +
                          str(countESneg) + "\n")
            analyse.write("Thresholded Volume [m3] of Surface Raising: " +
                          str(countESpos) + "\n")
            analyse.write("Total Volume [m3] of Difference: " +
                          str(countESpos + countESneg) + "\n")
            analyse.write("Total Net Volume [m3] of Difference: " +
                          str(countESpos - countESneg) + "\n")
            analyse.write("\n")
            analyse.write("\n")
            analyse.write("Volume [m3] of Error within Threshold of UC: " +
                          str(countAcc) + "\n")
            analyse.write("Count of Cells within UC: " + str(countCell) + "\n")
            analyse.write("Volume [m3] of Cells between UC: " +
                          str(countCellVol) + "\n")
            analyse.write("Percent [%] of Error of Cells between UC: " +
                          str((countCellVol /
                               (countESpos + countESneg)) * 100) + "\n")
            analyse.write("\n")
            analyse.write("\n")

            analyse_csv.write("UC; " + str(countAOI) + "; " +
                              str(countPosArea + countNegArea) + "; " +
                              str(((countPosArea + countNegArea) / countAOI) *
                                  100) + "; ; ; " + str(countESneg) + "; " +
                              str(countESpos) + "; " +
                              str(countESpos + countESneg) + "; " +
                              str(countESpos - countESneg) + "\n")
            net_v_3 = countESpos - countESneg
            sr_3 = countESpos
            sl_3 = countESneg

            ## BarChart
            plotdata = pd.DataFrame(
                {
                    'surface raising': [sr_0, sr_1, sr_2, sr_3],
                    'surface lowering': [-sl_0, -sl_1, -sl_2, -sl_3]
                },
                index=['raw', '0.1 m', '0.3 m', 'UC model'])
            New_Colors = ['silver', 'dimgrey']
            rcParams['font.family'] = 'sans-serif'
            rcParams['font.sans-serif'] = ['Verdana']
            plotdata.plot(kind="bar",
                          stacked=True,
                          width=0.5,
                          color=New_Colors,
                          align='center',
                          widtH=0.5)
            #plt.xticks(np.arange(0, 4, step=1))
            plt.xticks(rotation=5, horizontalalignment="center")
            #plt.yticks(rotation=0, horizontalalignment="center")
            plt.title('volume changes [m3]', fontsize=10)
            plt.xlabel('threshold', fontsize=10)
            #plt.ylabel('volume changes [m3]', fontsize=10)
            #plt.ylabel('net volume [m3]', fontsize=10)
            plt.grid(True)

            plt.savefig(final_path + '/' + 'change_detection_plot.png')

            ## Grid UC
            out3 = temp_path + '/' + 'diff_uc_old.tif'
            out4 = final_path + '/' + 'diff_uc.tif'
            grid_diff_uc = np.flip(grid_diff_uc, 1)
            grid_diff_uc = np.rot90(grid_diff_uc)
            imsave = Image.fromarray(grid_diff_uc, mode='F')
            imsave.save(out3, "TIFF")

            ## Raster georeferenzieren
            src_ds = gdal.Open(out3)
            format = "GTiff"
            driver = gdal.GetDriverByName(format)

            dst_ds = driver.CreateCopy(out4, src_ds, 0)
            dst_ds.SetGeoTransform(gt)
            srs = osr.SpatialReference()
            srs.ImportFromEPSG(int(epsg))
            dest_wkt = srs.ExportToWkt()
            dst_ds.SetProjection(dest_wkt)

            # Close files
            dst_ds = None
            src_ds = None

        ## ----------------------------------------------------------------------------------------------------------##
        ## ChangeDetection (Threshold)
        sel = self.SELECTIONS[self.parameterAsEnum(parameters, self.SELECTION,
                                                   context)]
        if str(sel) == str('Threshold'):
            feedback.pushInfo(str(sel))

            val = (parameters[self.INPUT_threshold])

            analyse = open(
                final_path + '/' + 'change_detection_' + str(val) + '.txt',
                "w")
            analyse_csv = open(
                final_path + '/' + 'change_detection_' + str(val) + '.csv',
                "w")
            analyse_csv.write(
                " ; AOI [m2]; Detectable Change [m2]; Detectable Change [%]; Surface Lowering [m2]; Surface Raising [m2]; Surface Lowering [m3]; Surface Raising [m3]; Volume of Difference [m3]; Net Volume of Difference [m3]"
                + "\n")

            ##Rasters to Arrays
            #out_uc = temp_path + '/' + 'dhm_uc.tif'

            diff_rds = gdal.Open(out2)
            format = "GTiff"
            driver3 = gdal.GetDriverByName(format)
            band_diff = diff_rds.GetRasterBand(1)
            im_diff = Image.open(out2)
            pix_diff = im_diff.load()

            ## Classification1 - Threshold
            countAOI = 0
            countPosGes = 0
            countNegGes = 0
            countPos = 0
            countNeg = 0
            countPosArea = 0
            countNegArea = 0
            countPosAreaGes = 0
            countNegAreaGes = 0
            countAcc = 0
            countCell = 0
            countCellVol = 0

            for row in range(0, width):
                for col in range(0, height):
                    diff = pix_diff[row, col]
                    if diff > -9999.0 and diff < 100:
                        countAOI = countAOI + (cs * cs)
                    if diff < 0 and diff > -100:
                        volNegGes = cs * cs * (abs(diff))
                        countNegGes = countNegGes + volNegGes
                        countNegAreaGes = countNegAreaGes + (cs * cs)
                    if diff > 0 and diff < 100:
                        volPosGes = cs * cs * (abs(diff))
                        countPosGes = countPosGes + volPosGes
                        countPosAreaGes = countPosAreaGes + (cs * cs)
                    if diff < -val and diff > -100:
                        grid_diff_uc[row, col] = diff + val
                        volNeg = cs * cs * (abs(diff) - val)
                        countNeg = countNeg + volNeg
                        countNegArea = countNegArea + (cs * cs)
                        countAcc = countAcc + (cs * cs * val)
                    if diff > val and diff < 100:
                        grid_diff_uc[row, col] = diff - val
                        volPos = cs * cs * (diff - val)
                        countPos = countPos + (volPos)
                        countPosArea = countPosArea + (cs * cs)
                        countAcc = countAcc + (cs * cs * val)
                    if diff < 0 and diff > -val:
                        grid_diff_uc[row, col] = 0.0
                        countCell = countCell + 1
                        countCellVol = countCellVol + (cs * cs * abs(diff))
                        #print countCell
                    if diff > 0 and diff < val:
                        grid_diff_uc[row, col] = 0.0
                        countCell = countCell + 1
                        countCellVol = countCellVol + (cs * cs * abs(diff))

            analyse.write("Total Area [m2] of Interest: " + str(countAOI) +
                          "\n")
            analyse.write("Total Area [km2] of Interest: " +
                          str(countAOI / 1000000) + "\n")
            analyse.write("\n")
            analyse.write("Total Area [m2] of Detectable Change: " +
                          str(countPosAreaGes + countNegAreaGes) + "\n")
            analyse.write(
                "Total Area of Interest [%] with Detectable Change: " +
                str(((countPosAreaGes + countNegAreaGes) / countAOI) * 100) +
                "\n")
            analyse.write("Total Area [m2] of Surface Lowering: " +
                          str(countNegAreaGes) + "\n")
            analyse.write("Total Area [m2] of Surface Raising: " +
                          str(countPosAreaGes) + "\n")
            analyse.write("Total Volume [m3] of Surface Lowering: " +
                          str(countNegGes) + "\n")
            analyse.write("Total Volume [m3] of Surface Raising: " +
                          str(countPosGes) + "\n")
            analyse.write("Total Volume [m3] of Difference: " +
                          str(countPosGes + countNegGes) + "\n")
            analyse.write("Total Net Volume [m3] of Difference: " +
                          str(countPosGes - countNegGes) + "\n")
            analyse.write("\n")
            analyse.write("\n")

            analyse_csv.write(
                "0.0; " + str(countAOI) + "; " +
                str(countPosAreaGes + countNegAreaGes) + "; " +
                str(((countPosAreaGes + countNegAreaGes) / countAOI) * 100) +
                "; " + str(countNegAreaGes) + "; " + str(countPosAreaGes) +
                "; " + str(countNegGes) + "; " + str(countPosGes) + "; " +
                str(countPosGes + countNegGes) + "; " +
                str(countPosGes - countNegGes) + "\n")
            net_v_0 = countPosGes - countNegGes
            sr_0 = countPosGes
            sl_0 = countNegGes

            analyse.write("Analysis with Threshold of +/- 0.1" + "\n")
            analyse.write(
                "Thresholded (0.1) Area [m2] of Detectable Change: " +
                str(countPosArea + countNegArea) + "\n")
            analyse.write(
                "Thresholded (0.1) Area [km2] of Detectable Change: " +
                str((countPosArea + countNegArea) / 1000000) + "\n")
            analyse.write(
                "Thresholded (0.1) Area of Interest [%] with Detectable Change: "
                + str(((countPosArea + countNegArea) / countAOI) * 100) + "\n")
            analyse.write("Thresholded (0.1) Area [m2] of Surface Lowering: " +
                          str(countNegArea) + "\n")
            analyse.write(
                "Thresholded (0.1) Area [km2] of Surface Lowering: " +
                str(countNegArea / 1000000) + "\n")
            analyse.write("Thresholded (0.1) Area [m2] of Surface Raising: " +
                          str(countPosArea) + "\n")
            analyse.write("Thresholded (0.1) Area [km2] of Surface Raising: " +
                          str(countPosArea / 1000000) + "\n")
            analyse.write(
                "Thresholded (0.1) Volume [m3] of Surface Lowering: " +
                str(countNeg) + "\n")
            analyse.write(
                "Thresholded (0.1) Volume [m3] of Surface Raising: " +
                str(countPos) + "\n")
            analyse.write("Thresholded (0.1) Volume [m3] of Difference: " +
                          str(countPos + countNeg) + "\n")
            analyse.write("Thresholded (0.1) Net Volume [m3] of Difference: " +
                          str(countPos - countNeg) + "\n")
            analyse.write("\n")
            analyse.write("\n")
            analyse.write(
                "Volume [m3] of Error within Threshold of -0.1 and 0.1: " +
                str(countAcc) + "\n")
            analyse.write("Count of Cells within -0.1 and 0.1: " +
                          str(countCell) + "\n")
            analyse.write("Volume [m3] of Cells between -0.1 and 0.1: " +
                          str(countCellVol) + "\n")
            analyse.write(
                "Percent [%] of Error of Cells between -0.1 and 0.1: " +
                str((countCellVol / (countPosGes + countNegGes)) * 100) + "\n")
            analyse.write("\n")
            analyse.write("\n")

            analyse_csv.write("0.1; " + str(countAOI) + "; " +
                              str(countPosArea + countNegArea) + "; " +
                              str(((countPosArea + countNegArea) / countAOI) *
                                  100) + "; " + str(countNegArea) + "; " +
                              str(countPosArea) + "; " + str(countNeg) + "; " +
                              str(countPos) + "; " + str(countPos + countNeg) +
                              "; " + str(countPos - countNeg) + "\n")
            net_v_1 = countPos - countNeg
            sr_1 = countPos
            sl_1 = countNeg

            del countPos
            del countNeg
            del countPosArea
            del countNegArea
            del countAcc
            del countCell
            del countCellVol

            ## BarChart
            plotdata = pd.DataFrame(
                {
                    'surface raising': [sr_0, sr_1],
                    'surface lowering': [-sl_0, -sl_1]
                },
                index=['raw', str(val) + ' m'])
            New_Colors = ['silver', 'dimgrey']
            rcParams['font.family'] = 'sans-serif'
            rcParams['font.sans-serif'] = ['Verdana']
            plotdata.plot(kind="bar",
                          stacked=True,
                          width=0.5,
                          color=New_Colors,
                          align='center',
                          widtH=0.5)
            #plt.xticks(np.arange(0, 4, step=1))
            plt.xticks(rotation=5, horizontalalignment="center")
            #plt.yticks(rotation=0, horizontalalignment="center")
            plt.title('volume changes [m3]', fontsize=10)
            plt.xlabel('threshold', fontsize=10)
            #plt.ylabel('volume changes [m3]', fontsize=10)
            #plt.ylabel('net volume [m3]', fontsize=10)
            plt.grid(True)

            plt.savefig(final_path + '/' + 'change_detection_plot.png')

            ## Grid UC
            out3 = temp_path + '/' + 'diff_thresholded_old.tif'
            out4 = final_path + '/' + 'diff_thresholded.tif'
            grid_diff_uc = np.flip(grid_diff_uc, 1)
            grid_diff_uc = np.rot90(grid_diff_uc)
            imsave = Image.fromarray(grid_diff_uc, mode='F')
            imsave.save(out3, "TIFF")

            ## Raster georeferenzieren
            src_ds = gdal.Open(out3)
            format = "GTiff"
            driver = gdal.GetDriverByName(format)

            dst_ds = driver.CreateCopy(out4, src_ds, 0)
            dst_ds.SetGeoTransform(gt)
            #srs = osr.SpatialReference()
            #srs.ImportFromEPSG(epsg)
            #dest_wkt = srs.ExportToWkt()
            dst_ds.SetProjection(dest_wkt)

            # Close files
            dst_ds = None
            src_ds = None

            feedback.pushInfo(str("OK"))

        ## ----------------------------------------------------------------------------------------------------------##
        ## Add Layer
        root = QgsProject.instance().layerTreeRoot()
        mygroup = root.insertGroup(1, "QCD_Tool")
        rlayer = QgsRasterLayer(out4, 'ChangeDetection')
        rprovider = rlayer.dataProvider()
        colDic = {
            'f': '#d7191c',
            'f1': '#eb6640',
            'f2': '#feb165',
            'f3': '#ffdc96',
            'f4': '#ffffff',
            'f5': '#ffffff',
            'f6': '#9cd3a7',
            'f7': '#5ea7b1',
            'f8': '#2b83ba',
            'f9': '#1e5c83'
        }
        valueList = [-3, -2, -1, -0.5, -0.05, 0.05, 0.5, 1, 2, 3]
        lst = [
            QgsColorRampShader.ColorRampItem(valueList[0],
                                             QColor(colDic['f'])),
            QgsColorRampShader.ColorRampItem(valueList[1],
                                             QColor(colDic['f1'])),
            QgsColorRampShader.ColorRampItem(valueList[2],
                                             QColor(colDic['f2'])),
            QgsColorRampShader.ColorRampItem(valueList[3],
                                             QColor(colDic['f3'])),
            QgsColorRampShader.ColorRampItem(valueList[4],
                                             QColor(colDic['f4'])),
            QgsColorRampShader.ColorRampItem(valueList[5],
                                             QColor(colDic['f5'])),
            QgsColorRampShader.ColorRampItem(valueList[6],
                                             QColor(colDic['f6'])),
            QgsColorRampShader.ColorRampItem(valueList[7],
                                             QColor(colDic['f7'])),
            QgsColorRampShader.ColorRampItem(valueList[8],
                                             QColor(colDic['f8'])),
            QgsColorRampShader.ColorRampItem(valueList[9],
                                             QColor(colDic['f9']))
        ]
        my_shader = QgsRasterShader()
        my_colorramp = QgsColorRampShader()
        #fcn = QgsColorRampShader()
        #fcn.setColorRampType(QgsColorRampShader.Interpolated)
        #lst = [ QgsColorRampShader.ColorRampItem(0, QColor(0,255,0)),QgsColorRampShader.ColorRampItem(255, QColor(255,255,0)) ]
        my_colorramp.setColorRampItemList(lst)
        my_colorramp.setColorRampType(QgsColorRampShader.Interpolated)
        my_shader.setRasterShaderFunction(my_colorramp)
        renderer = QgsSingleBandPseudoColorRenderer(rlayer.dataProvider(), 1,
                                                    my_shader)
        rasterTransparency = QgsRasterTransparency()
        myTransparentSingleValuePixelList = []
        myTransparentPixel1 = QgsRasterTransparency.TransparentSingleValuePixel(
        )
        myTransparentPixel1.min = -0.05
        myTransparentPixel1.max = 0.05
        myTransparentPixel1.percentTransparent = 100
        myTransparentSingleValuePixelList.append(myTransparentPixel1)
        rasterTransparency.setTransparentSingleValuePixelList(
            myTransparentSingleValuePixelList)
        renderer.setRasterTransparency(rasterTransparency)
        rlayer.setRenderer(renderer)
        rlayer.triggerRepaint()
        QgsProject.instance().addMapLayer(rlayer)
        mygroup.addLayer(rlayer)

        outputs['LastStep'] = out4
        results['Tool abgeschlossen'] = outputs['LastStep']
        return results