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}
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 }
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
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}
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}
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)
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
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)
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}
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}
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 {}
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}
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}
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}
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}
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}
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
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
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'] }
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
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