def javaPath(): # load previous value folder = ProcessingConfig.getSetting(qsdm_settings.JAVA_EXEC) if folder is None: # Try to automatically detect JAVA path # Can Java be executed from the shell? try: from subprocess import DEVNULL # python 3k except ImportError: DEVNULL = open(os.devnull, 'wb') try: proc = subprocess.call(['java', '-version'],stdin=subprocess.PIPE, stdout=DEVNULL, stderr=subprocess.STDOUT) except Exception, err: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, "There has been an Error detecting JAVA for QSDM. Please set correct the path manually.") folder = '' proc = 1 if proc == 0: # java detected, look for executable env = os.environ #a = env.get("PATH") bin also in here if env.has_key("JAVA_HOME"): folder = os.path.join(env.get("JAVA_HOME"), 'bin') else: # Otherwise User has to set path manually folder = ''
def processAlgorithm(self, feedback): ns = {} ns['feedback'] = feedback ns['scriptDescriptionFile'] = self.descriptionFile for param in self.parameters: ns[param.name] = param.value for out in self.outputs: ns[out.name] = out.value variables = re.findall('@[a-zA-Z0-9_]*', self.script) script = 'import processing\n' script += self.script context = QgsExpressionContext() context.appendScope(QgsExpressionContextUtils.globalScope()) context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance())) for var in variables: varname = var[1:] if context.hasVariable(varname): script = script.replace(var, context.variable(varname)) else: ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, 'Cannot find variable: %s' % varname) exec((script), ns) for out in self.outputs: out.setValue(ns[out.name])
def executeOtb(commands, progress, addToLog=True): loglines = [] loglines.append(tr("OTB execution console output")) os.putenv("ITK_AUTOLOAD_PATH", otbLibPath()) fused_command = "".join(['"%s" ' % re.sub(r'^"|"$', "", c) for c in commands]) with subprocess.Popen( fused_command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.DEVNULL, stderr=subprocess.STDOUT, universal_newlines=True, ) as proc: if isMac(): # This trick avoids having an uninterrupted system call exception if OTB is not installed time.sleep(1) for line in iter(proc.stdout.readline, ""): if "[*" in line: idx = line.find("[*") perc = int(line[idx - 4 : idx - 2].strip(" ")) if perc != 0: progress.setPercentage(perc) else: loglines.append(line) progress.setConsoleInfo(line) if addToLog: ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines) return loglines
def runFusion(commands, progress): loglines = [] loglines.append("Fusion execution console output") proc = subprocess.Popen(commands, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,stderr=subprocess.STDOUT, universal_newlines=False).stdout for line in iter(proc.readline, ""): loglines.append(line) ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines)
def openModel(self): filename = unicode(QFileDialog.getOpenFileName(self, self.tr('Open Model'), ModelerUtils.modelsFolder(), self.tr('Processing models (*.model *.MODEL)'))) if filename: try: alg = ModelerAlgorithm.fromFile(filename) self.alg = alg self.alg.setModelerView(self) self.textGroup.setText(alg.group) self.textName.setText(alg.name) self.repaintModel() self.view.centerOn(0, 0) self.hasChanged = False except WrongModelException as e: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, self.tr('Could not load model %s\n%s') % (filename, e.msg)) QMessageBox.critical(self, self.tr('Could not open model'), self.tr('The selected model could not be loaded.\n' 'See the log for more information.')) except Exception as e: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, self.tr('Could not load model %s\n%s') % (filename, e.args[0])) QMessageBox.critical(self, self.tr('Could not open model'), self.tr('The selected model could not be loaded.\n' 'See the log for more information.'))
def defineCharacteristicsFromFile(self): with codecs.open(self.descriptionFile, encoding='utf-8') as f: line = f.readline().strip('\n').strip() self.name = line self.i18n_name = self.tr(line) line = f.readline().strip('\n').strip() self.cmdName = line line = f.readline().strip('\n').strip() self.group = line self.i18n_group = self.tr(line) line = f.readline().strip('\n').strip() while line != '': try: line = line.strip('\n').strip() if line.startswith('Parameter'): param = getParameterFromString(line) self.addParameter(param) else: self.addOutput(getOutputFromString(line)) line = f.readline().strip('\n').strip() except Exception as e: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, self.tr('Could not load TauDEM algorithm: {}\n{}'.format(self.descriptionFile, line))) raise e
def __init__(self, alg): super(HelpEditionDialog, self).__init__(None) self.setupUi(self) self.alg = alg self.descriptions = {} if isinstance(self.alg, ModelerAlgorithm): self.descriptions = self.alg.helpContent else: if self.alg.descriptionFile is not None: helpfile = alg.descriptionFile + '.help' if os.path.exists(helpfile): try: with open(helpfile) as f: self.descriptions = json.load(f) except Exception: ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, self.tr('Cannot open help file: %s') % helpfile) self.currentName = self.ALG_DESC if self.ALG_DESC in self.descriptions: self.text.setText(self.descriptions[self.ALG_DESC]) self.tree.itemClicked.connect(self.changeItem) self.fillTree() self.updateHtmlView()
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT)) tolerance = self.getParameterValue(self.TOLERANCE) pointsBefore = 0 pointsAfter = 0 writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( layer.pendingFields().toList(), layer.wkbType(), layer.crs()) features = vector.features(layer) total = 100.0 / len(features) for current, f in enumerate(features): featGeometry = QgsGeometry(f.geometry()) attrs = f.attributes() pointsBefore += self.geomVertexCount(featGeometry) newGeometry = featGeometry.simplify(tolerance) pointsAfter += self.geomVertexCount(newGeometry) feature = QgsFeature() feature.setGeometry(newGeometry) feature.setAttributes(attrs) writer.addFeature(feature) progress.setPercentage(int(current * total)) del writer ProcessingLog.addToLog(ProcessingLog.LOG_INFO, self.tr('Simplify: Input geometries have been simplified from %s to %s points' % (pointsBefore, pointsAfter)))
def executeSaga(progress): if ProcessingUtils.isWindows(): command = ["cmd.exe", "/C ", SagaUtils.sagaBatchJobFilename()] else: os.chmod(SagaUtils.sagaBatchJobFilename(), stat.S_IEXEC | stat.S_IREAD | stat.S_IWRITE) command = [SagaUtils.sagaBatchJobFilename()] loglines = [] loglines.append("SAGA execution console output") proc = subprocess.Popen( command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, ).stdout for line in iter(proc.readline, ""): if "%" in line: s = "".join([x for x in line if x.isdigit()]) try: progress.setPercentage(int(s)) except: pass else: line = line.strip() if line != "/" and line != "-" and line != "\\" and line != "|": loglines.append(line) progress.setConsoleInfo(line) if ProcessingConfig.getSetting(SagaUtils.SAGA_LOG_CONSOLE): ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines)
def execute(self, progress=SilentProgress(), model=None): """The method to use to call a processing algorithm. Although the body of the algorithm is in processAlgorithm(), it should be called using this method, since it performs some additional operations. Raises a GeoAlgorithmExecutionException in case anything goes wrong. """ self.model = model try: self.setOutputCRS() self.resolveOutputs() self.evaluateParameterValues() self.runPreExecutionScript(progress) self.processAlgorithm(progress) progress.setPercentage(100) self.convertUnsupportedFormats(progress) self.runPostExecutionScript(progress) except GeoAlgorithmExecutionException as gaee: lines = [self.tr('Error while executing algorithm')] lines.append(traceback.format_exc()) ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, gaee.msg) raise GeoAlgorithmExecutionException(gaee.msg, lines, gaee) except Exception as e: # If something goes wrong and is not caught in the # algorithm, we catch it here and wrap it lines = [self.tr('Uncaught error while executing algorithm')] lines.append(traceback.format_exc()) ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, lines) raise GeoAlgorithmExecutionException(str(e) + self.tr('\nSee log for more details'), lines, e)
def processAlgorithm(self, progress): layer = QGisLayers.getObjectFromUri(self.getParameterValue(self.INPUT)) tolerance =self.getParameterValue(self.TOLERANCE) pointsBefore = 0 pointsAfter = 0 writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(layer.pendingFields().toList(), layer.wkbType(), layer.crs()) current = 0 selection = QGisLayers.features(layer) total = 100.0 / float(len(selection)) for f in selection: featGeometry = QgsGeometry(f.geometry()) attrs = f.attributes() pointsBefore += self.geomVertexCount(featGeometry) newGeometry = featGeometry.simplify(tolerance) pointsAfter += self.geomVertexCount(newGeometry) feature = QgsFeature() feature.setGeometry(newGeometry) feature.setAttributes(attrs) writer.addFeature(feature) current += 1 progress.setPercentage(int(current * total)) del writer ProcessingLog.addToLog(ProcessingLog.LOG_INFO, "Simplify: Input geometries have been simplified from" + str(pointsBefore) + " to " + str(pointsAfter) + " points.")
def executeSaga(progress): if isWindows(): command = ['cmd.exe', '/C ', SagaUtils.sagaBatchJobFilename()] else: os.chmod(SagaUtils.sagaBatchJobFilename(), stat.S_IEXEC | stat.S_IREAD | stat.S_IWRITE) command = [SagaUtils.sagaBatchJobFilename()] loglines = [] loglines.append('SAGA execution console output') proc = subprocess.Popen( command, shell=True, stdout=subprocess.PIPE, stdin=open(os.devnull), stderr=subprocess.STDOUT, universal_newlines=True, ).stdout for line in iter(proc.readline, ''): if '%' in line: s = ''.join([x for x in line if x.isdigit()]) try: progress.setPercentage(int(s)) except: pass else: line = line.strip() if line != '/' and line != '-' and line != '\\' and line \ != '|': loglines.append(line) progress.setConsoleInfo(line) if ProcessingConfig.getSetting(SagaUtils.SAGA_LOG_CONSOLE): ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines)
def _loadAlgorithms(self): self.algs = [] version = SagaUtils.getSagaInstalledVersion(True) if version is None: ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr("Problem with SAGA installation: SAGA was not found or is not correctly installed"), ) return if version not in self.supportedVersions: lastVersion = sorted(self.supportedVersions.keys())[-1] if version > lastVersion: version = lastVersion else: ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr("Problem with SAGA installation: installed SAGA version (%s) is not supported" % version), ) return folder = SagaUtils.sagaDescriptionPath() folder = os.path.join(folder, self.supportedVersions[version][0]) for descriptionFile in os.listdir(folder): if descriptionFile.endswith("txt"): f = os.path.join(folder, descriptionFile) self._loadAlgorithm(f, version) self.algs.append(SplitRGBBands())
def accept(self): keepOpen = ProcessingConfig.getSetting( ProcessingConfig.KEEP_DIALOG_OPEN) try: if self.setParamValues(): QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) ProcessingLog.addToLog(ProcessingLog.LOG_ALGORITHM, self.alg.getAsCommand()) ret = runalg(self.alg, self) QApplication.restoreOverrideCursor() if ret: handleAlgorithmResults(self.alg, self, not keepOpen) self.executed = True QDialog.reject(self) else: QMessageBox.critical(self, self.tr('Unable to execute algorithm'), self.tr('Wrong or missing parameter ' 'values')) return except GeoAlgorithmExecutionException, e: QApplication.restoreOverrideCursor() QMessageBox.critical(self, "Error",e.msg) ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, e.msg) self.executed = False QDialog.reject(self)
def processAlgorithm(self, progress): if not ogrAvailable: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, "OGR bindings not installed" ) return input = self.getParameterValue(self.INPUT_LAYER) sql = self.getParameterValue(self.SQL) ogrLayer = self.ogrConnectionString(input) output = self.getOutputValue(self.OUTPUT) qDebug("Opening data source '%s'" % ogrLayer) poDS = ogr.Open( ogrLayer, False ) if poDS is None: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, self.failure(ogrLayer)) return result = self.select_values(poDS, sql) f = open(output, "w") f.write("<table>") for row in result: f.write("<tr>") for col in row: f.write("<td>"+col+"</td>") f.write("</tr>") f.write("</table>") f.close()
def bounds(self): """ Function for recalculating the bounded extents of the layers as they are processed. Under construction :return: """ # Requires refinement for raster manipulation of bounds selected_extent = unicode(self.getParameterValue(self.MAP_EXTENT)).split(',') xMin = float(selected_extent[0]) xMax = float(selected_extent[1]) yMin = float(selected_extent[2]) yMax = float(selected_extent[3]) extent = QgsRectangle(xMin, yMin, xMax, yMax) mapCRS = iface.mapCanvas().mapSettings().destinationCrs() transform = QgsCoordinateTransform( mapCRS, QgsCoordinateReferenceSystem('EPSG:4326') # WGS84 # QgsCoordinateReferenceSystem('EPSG:3785') # Popular vis mercator ) try: layer_extent = transform.transform(extent) except QgsCsException: ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, "exception in transform layer srs") layer_extent = QgsRectangle(-180, -90, 180, 90) ProcessingLog.addToLog(ProcessingLog.LOG_INFO, layer_extent.toString()) return layer_extent
def processAlgorithm(self, progress): commands = [] commands.append(os.path.join(TauDEMUtils.mpiexecPath(), 'mpiexec')) processNum = ProcessingConfig.getSetting(TauDEMUtils.MPI_PROCESSES) if processNum <= 0: raise GeoAlgorithmExecutionException('Wrong number of MPI \ processes used.\nPlease set correct number before running \ TauDEM algorithms.') commands.append('-n') commands.append(str(processNum)) commands.append(os.path.join(TauDEMUtils.taudemPath(), self.cmdName)) commands.append('-slp') commands.append(self.getParameterValue(self.SLOPE_GRID)) commands.append('-sca') commands.append(self.getParameterValue(self.AREA_GRID)) commands.append('-par') commands.append(str(self.getParameterValue(self.SLOPE_EXPONENT))) commands.append(str(self.getParameterValue(self.AREA_EXPONENT))) commands.append('-sa') commands.append(self.getOutputValue(self.SLOPE_AREA_GRID)) loglines = [] loglines.append('TauDEM execution command') for line in commands: loglines.append(line) ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines) TauDEMUtils.executeTauDEM(commands, progress)
def processAlgorithm(self, progress): commands.append(os.path.join(TauDEMUtils.mpiexecPath(), "mpiexec")) processNum = ProcessingConfig.getSetting(TauDEMUtils.MPI_PROCESSES) if processNum <= 0: raise GeoAlgorithmExecutionException("Wrong number of MPI processes used.\nPlease set correct number before running TauDEM algorithms.") commands.append("-n") commands.append(str(processNum)) commands.append(os.path.join(TauDEMUtils.taudemPath(), self.cmdName)) commands.append("-ad8") commands.append(self.getParameterValue(self.D8_CONTRIB_AREA_GRID)) commands.append("-p") commands.append(self.getParameterValue(self.D8_FLOW_DIR_GRID)) commands.append("-fel") commands.append(self.getParameterValue(self.PIT_FILLED_GRID)) commands.append("-ssa") commands.append(self.getParameterValue(self.ACCUM_STREAM_SOURCE_GRID)) commands.append("-o") commands.append(self.getParameterValue(self.OUTLETS_SHAPE)) commands.append("-par") commands.append(str(self.getParameterValue(self.MIN_TRESHOLD))) commands.append(str(self.getParameterValue(self.MAX_THRESHOLD))) commands.append(str(self.getParameterValue(self.TRESHOLD_NUM))) commands.append(str(self.getParameterValue(self.STEPS))) commands.append("-drp") commands.append(self.getOutputValue(self.DROP_ANALYSIS_FILE)) loglines = [] loglines.append("TauDEM execution command") for line in commands: loglines.append(line) ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines) TauDEMUtils.executeTauDEM(commands, progress)
def check_extension(self, path, progress): """ Due to the wider range of the accepted file types by QGIS the file extensions are checked and given a boolean value for further processing if they are accepted by GIS Cloud :param path: Path to check if valid dataset :type path: str :param progress: Interface to the processing window :type progress: processing.gui.AlgorithmDialog.AlgorithmDialog :rtype: bool """ filename, file_extension = os.path.splitext(path) if file_extension in (".shp", ".mif", ".mid", ".tab", ".kml", ".gpx", ".tif", ".tiff", ".ecw", ".img", ".jp2", ".jpg", ".png", ".pdf", ".json", ".geojson"): return True else: # progress.error(path + " is not compatible with GISCloud.") # provides feedback on the rejection of a filetype if path: # i.e. not an empty string progress.error(path + " is not compatible with GISCloud.") ProcessingLog.addToLog( ProcessingLog.LOG_WARNING, "{} is not an accepted filetype".format(path) ) return False
def executeGrass(commands, progress, outputCommands = None): loglines = [] loglines.append("GRASS execution console output") grassOutDone = False command = GrassUtils.prepareGrassExecution(commands) proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,stderr=subprocess.STDOUT, universal_newlines=True).stdout for line in iter(proc.readline, ""): if "GRASS_INFO_PERCENT" in line: try: progress.setPercentage(int(line[len("GRASS_INFO_PERCENT")+ 2:])) except: pass else: if "r.out" in line or "v.out" in line: grassOutDone = True loglines.append(line) progress.setConsoleInfo(line) # Some GRASS scripts, like r.mapcalculator or r.fillnulls, call other GRASS scripts during execution. This may override any commands that are # still to be executed by the subprocess, which are usually the output ones. If that is the case runs the output commands again. if not grassOutDone and outputCommands: command = GrassUtils.prepareGrassExecution(outputCommands) proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,stderr=subprocess.STDOUT, universal_newlines=True).stdout for line in iter(proc.readline, ""): if "GRASS_INFO_PERCENT" in line: try: progress.setPercentage(int(line[len("GRASS_INFO_PERCENT")+ 2:])) except: pass else: loglines.append(line) progress.setConsoleInfo(line) if ProcessingConfig.getSetting(GrassUtils.GRASS_LOG_CONSOLE): ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines) return loglines;
def processAlgorithm(self, progress): commands = [] commands.append(os.path.join(TauDEMUtils.mpiexecPath(), "mpiexec")) processNum = ProcessingConfig.getSetting(TauDEMUtils.MPI_PROCESSES) if processNum <= 0: raise GeoAlgorithmExecutionException("Wrong number of MPI processes used.\nPlease set correct number before running TauDEM algorithms.") commands.append("-n") commands.append(str(processNum)) commands.append(os.path.join(TauDEMUtils.taudemPath(), self.cmdName)) commands.append("-plen") commands.append(self.getParameterValue(self.LENGTH_GRID)) commands.append("-ad8") commands.append(self.getParameterValue(self.CONTRIB_AREA_GRID)) commands.append("-par") commands.append(str(self.getParameterValue(self.THRESHOLD))) commands.append(str(self.getParameterValue(self.EXPONENT))) commands.append("-ss") commands.append(self.getOutputValue(self.STREAM_SOURCE_GRID)) loglines = [] loglines.append("TauDEM execution command") for line in commands: loglines.append(line) ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines) TauDEMUtils.executeTauDEM(commands, progress)
def processAlgorithm(self, progress): ns = {} ns["progress"] = progress ns["scriptDescriptionFile"] = self.descriptionFile for param in self.parameters: ns[param.name] = param.value for out in self.outputs: ns[out.name] = out.value variables = re.findall("@[a-zA-Z0-9_]*", self.script) script = "import processing\n" script += self.script context = QgsExpressionContext() context.appendScope(QgsExpressionContextUtils.globalScope()) context.appendScope(QgsExpressionContextUtils.projectScope()) for var in variables: varname = var[1:] if context.hasVariable(varname): script = script.replace(var, context.variable(varname)) else: ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, "Cannot find variable: %s" % varname) exec((script), ns) for out in self.outputs: out.setValue(ns[out.name])
def processAlgorithm(self, progress): # Do the thing, Julie inputFilename = self.getParameterValue(self.RASTER) what = self.tsel[self.getParameterValue(self.TRANSFORM)] polyn = self.getParameterValue(self.POLYNOM) output = self.getOutputValue(self.OUT) # Starting transformation progress.setConsoleInfo("Transforming input raster layer with %s " % (str( what ))) func.updateProcessing(progress,1,3) raster = gdal.Open(str(inputFilename)) columns = raster.RasterXSize rows = raster.RasterYSize driver = raster.GetDriver() if(raster.RasterCount==1): band = raster.GetRasterBand(1) data_type = band.DataType nodata = band.GetNoDataValue() # Raise Notice that no no-data value has been selected progress.setConsoleInfo("!!! - Found no nodata-value for band %s . Transforming all values - !!!" % (str(1)) ) try: array = band.ReadAsArray() except Exception, e: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,"Could not transform the raster to an array.") work = array[array!=nodata] res = self.transformArray(work,what,polyn) # Transformation result = numpy.copy(array) result[result!=nodata] = res # Replace new values with the one sampled func.updateProcessing(progress,2,3)
def createAlgsList(self): # First we populate the list of algorithms with those created # extending GeoAlgorithm directly (those that execute GDAL # using the console) self.preloadedAlgs = [nearblack(), information(), warp(), translate(), rgb2pct(), pct2rgb(), merge(), buildvrt(), polygonize(), gdaladdo(), ClipByExtent(), ClipByMask(), contour(), rasterize(), proximity(), sieve(), fillnodata(), ExtractProjection(), gdal2xyz(), hillshade(), slope(), aspect(), tri(), tpi(), roughness(), ColorRelief(), GridInvDist(), GridAverage(), GridNearest(), GridDataMetrics(), gdaltindex(), gdalcalc(), rasterize_over(), # ----- OGR tools ----- OgrInfo(), Ogr2Ogr(), Ogr2OgrClip(), Ogr2OgrClipExtent(), Ogr2OgrToPostGis(), Ogr2OgrToPostGisList(), Ogr2OgrPointsOnLines(), Ogr2OgrBuffer(), Ogr2OgrDissolve(), Ogr2OgrOneSideBuffer(), Ogr2OgrTableToPostGisList(), OgrSql(), ] # And then we add those that are created as python scripts folder = self.scriptsFolder() if os.path.exists(folder): for descriptionFile in os.listdir(folder): if descriptionFile.endswith('py'): try: fullpath = os.path.join(self.scriptsFolder(), descriptionFile) alg = GdalScriptAlgorithm(fullpath) self.preloadedAlgs.append(alg) except WrongScriptException as e: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, e.msg)
def error(self, msg): QApplication.restoreOverrideCursor() QMessageBox.critical(self, "Error", msg) ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, msg) if self.algEx: self.algEx.terminate() self.table.setEnabled(True)
def defineCharacteristicsFromFile(self): lines = open(self.descriptionFile) line = lines.readline().strip('\n').strip() self.name = line self.i18n_name = QCoreApplication.translate("TAUDEMAlgorithm", line) line = lines.readline().strip('\n').strip() self.cmdName = line line = lines.readline().strip('\n').strip() self.group = line self.i18n_group = QCoreApplication.translate("TAUDEMAlgorithm", line) line = lines.readline().strip('\n').strip() while line != '': try: line = line.strip('\n').strip() if line.startswith('Parameter'): param = getParameterFromString(line) self.addParameter(param) else: self.addOutput(getOutputFromString(line)) line = lines.readline().strip('\n').strip() except Exception as e: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, self.tr('Could not load TauDEM algorithm: %s\n%s' % (self.descriptionFile, line))) raise e lines.close()
def processAlgorithm(self, progress): commands = [] commands.append(os.path.join(TauDEMUtils.mpiexecPath(), "mpiexec")) processNum = ProcessingConfig.getSetting(TauDEMUtils.MPI_PROCESSES) if processNum <= 0: raise GeoAlgorithmExecutionException("Wrong number of MPI processes used.\nPlease set correct number before running TauDEM algorithms.") commands.append("-n") commands.append(str(processNum)) commands.append(os.path.join(TauDEMUtils.taudemPath(), self.cmdName)) commands.append("-ang") commands.append(self.getParameterValue(self.DINF_FLOW_DIR_GRID)) commands.append("-fel") commands.append(self.getParameterValue(self.PIT_FILLED_GRID)) commands.append("-m") commands.append(str(self.STAT_DICT[self.getParameterValue(self.STAT_METHOD)])) commands.append(str(self.DIST_DICT[self.getParameterValue(self.DIST_METHOD)])) commands.append("-thresh") commands.append(str(self.getParameterValue(self.THRESHOLD))) if str(self.getParameterValue(self.EDGE_CONTAM)).lower() == "false": commands.append("-nc") commands.append("-du") commands.append(self.getOutputValue(self.DIST_UP_GRID)) loglines = [] loglines.append("TauDEM execution command") for line in commands: loglines.append(line) ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines) TauDEMUtils.executeTauDEM(commands, progress)
def executeSaga(feedback): if isWindows(): command = ['cmd.exe', '/C ', sagaBatchJobFilename()] else: os.chmod(sagaBatchJobFilename(), stat.S_IEXEC | stat.S_IREAD | stat.S_IWRITE) command = [sagaBatchJobFilename()] loglines = [] loglines.append(QCoreApplication.translate('SagaUtils', 'SAGA execution console output')) with subprocess.Popen( command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.DEVNULL, stderr=subprocess.STDOUT, universal_newlines=True, ) as proc: try: for line in iter(proc.stdout.readline, ''): if '%' in line: s = ''.join([x for x in line if x.isdigit()]) try: feedback.setProgress(int(s)) except: pass else: line = line.strip() if line != '/' and line != '-' and line != '\\' and line != '|': loglines.append(line) feedback.pushConsoleInfo(line) except: pass if ProcessingConfig.getSetting(SAGA_LOG_CONSOLE): ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines)
def defineCharacteristicsFromFile(self): lines = open(self.descriptionFile) line = lines.readline().strip("\n").strip() self.appkey = line line = lines.readline().strip("\n").strip() self.cliName = line line = lines.readline().strip("\n").strip() self.name = line line = lines.readline().strip("\n").strip() self.group = line while line != "": try: line = line.strip("\n").strip() if line.startswith("Parameter"): param = ParameterFactory.getFromString(line) # Hack for initializing the elevation parameters from Processing configuration if param.name == "-elev.dem.path" or param.name == "-elev.dem": param.default = OTBUtils.otbSRTMPath() elif param.name == "-elev.dem.geoid" or param.name == "-elev.geoid": param.default = OTBUtils.otbGeoidPath() self.addParameter(param) elif line.startswith("*Parameter"): param = ParameterFactory.getFromString(line[1:]) param.isAdvanced = True self.addParameter(param) elif line.startswith("Extent"): self.addParameter(ParameterExtent(self.REGION_OF_INTEREST, "Region of interest", "0,1,0,1")) self.hasROI = True else: self.addOutput(OutputFactory.getFromString(line)) line = lines.readline().strip("\n").strip() except Exception,e: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, "Could not open OTB algorithm: " + self.descriptionFile + "\n" + line) raise e
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_LAYER)) writer = self.getOutputFromName( self.OUTPUT_LAYER).getVectorWriter( layer.fields(), QgsWkbTypes.Point, layer.crs()) features = vector.features(layer) total = 100.0 / len(features) for current, input_feature in enumerate(features): output_feature = input_feature if input_feature.geometry(): output_geometry = input_feature.geometry().centroid() if not output_geometry: ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, 'Error calculating centroid for feature {}'.format(input_feature.id())) output_feature.setGeometry(output_geometry) writer.addFeature(output_feature) progress.setPercentage(int(current * total)) del writer
def processAlgorithm(self, feedback): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_VECTOR)) startPoints = dataobjects.getObjectFromUri( self.getParameterValue(self.START_POINTS)) endPoint = self.getParameterValue(self.END_POINT) strategy = self.getParameterValue(self.STRATEGY) directionFieldName = self.getParameterValue(self.DIRECTION_FIELD) forwardValue = self.getParameterValue(self.VALUE_FORWARD) backwardValue = self.getParameterValue(self.VALUE_BACKWARD) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) bothValue = self.getParameterValue(self.VALUE_BOTH) defaultDirection = self.getParameterValue(self.DEFAULT_DIRECTION) speedFieldName = self.getParameterValue(self.SPEED_FIELD) defaultSpeed = self.getParameterValue(self.DEFAULT_SPEED) tolerance = self.getParameterValue(self.TOLERANCE) fields = QgsFields() fields.append(QgsField('start', QVariant.String, '', 254, 0)) fields.append(QgsField('end', QVariant.String, '', 254, 0)) fields.append(QgsField('cost', QVariant.Double, '', 20, 7)) feat = QgsFeature() feat.setFields(fields) writer = self.getOutputFromName(self.OUTPUT_LAYER).getVectorWriter( fields.toList(), QgsWkbTypes.LineString, layer.crs()) tmp = endPoint.split(',') endPoint = QgsPoint(float(tmp[0]), float(tmp[1])) directionField = -1 if directionFieldName is not None: directionField = layer.fields().lookupField(directionFieldName) speedField = -1 if speedFieldName is not None: speedField = layer.fields().lookupField(speedFieldName) director = QgsVectorLayerDirector(layer, directionField, forwardValue, backwardValue, bothValue, defaultDirection) distUnit = iface.mapCanvas().mapSettings().destinationCrs().mapUnits() multiplier = QgsUnitTypes.fromUnitToUnitFactor( distUnit, QgsUnitTypes.DistanceMeters) if strategy == 0: strategy = QgsNetworkDistanceStrategy() else: strategy = QgsNetworkSpeedStrategy(speedField, defaultSpeed, multiplier * 1000.0 / 3600.0) multiplier = 3600 director.addStrategy(strategy) builder = QgsGraphBuilder( iface.mapCanvas().mapSettings().destinationCrs(), True, tolerance) feedback.pushInfo(self.tr('Loading start points...')) request = QgsFeatureRequest() request.setFlags(request.flags() ^ QgsFeatureRequest.SubsetOfAttributes) features = vector.features(startPoints, request) count = len(features) points = [endPoint] for f in features: points.append(f.geometry().asPoint()) feedback.pushInfo(self.tr('Building graph...')) snappedPoints = director.makeGraph(builder, points) feedback.pushInfo(self.tr('Calculating shortest paths...')) graph = builder.graph() idxEnd = graph.findVertex(snappedPoints[0]) route = [] total = 100.0 / count for i in range(1, count + 1): idxStart = graph.findVertex(snappedPoints[i]) tree, cost = QgsGraphAnalyzer.dijkstra(graph, idxStart, 0) if tree[idxEnd] == -1: msg = self.tr( 'There is no route from start point ({}) to end point ({}).' .format(points[i].toString(), endPoint.toString())) feedback.setProgressText(msg) ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, msg) continue cost = 0.0 current = idxEnd while current != idxStart: cost += graph.edge(tree[current]).cost(0) route.append( graph.vertex(graph.edge(tree[current]).inVertex()).point()) current = graph.edge(tree[current]).outVertex() route.append(snappedPoints[i]) route.reverse() geom = QgsGeometry.fromPolyline(route) feat.setGeometry(geom) feat['start'] = points[i].toString() feat['end'] = endPoint.toString() feat['cost'] = cost / multiplier writer.addFeature(feat) route[:] = [] feedback.setProgress(int(i * total)) del writer
def processAlgorithm(self, progress): layerA = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_A)) splitLayer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_B)) sameLayer = self.getParameterValue( self.INPUT_A) == self.getParameterValue(self.INPUT_B) fieldList = layerA.fields() writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fieldList, QgsWkbTypes.multiType(layerA.wkbType()), layerA.crs()) spatialIndex = QgsSpatialIndex() splitGeoms = {} request = QgsFeatureRequest() request.setSubsetOfAttributes([]) for aSplitFeature in vector.features(splitLayer, request): splitGeoms[aSplitFeature.id()] = aSplitFeature.geometry() spatialIndex.insertFeature(aSplitFeature) # honor the case that user has selection on split layer and has setting "use selection" outFeat = QgsFeature() features = vector.features(layerA) if len(features) == 0: total = 100 else: total = 100.0 / float(len(features)) for current, inFeatA in enumerate(features): inGeom = inFeatA.geometry() attrsA = inFeatA.attributes() outFeat.setAttributes(attrsA) if inGeom.isMultipart(): inGeoms = [] for g in inGeom.asGeometryCollection(): inGeoms.append(g) else: inGeoms = [inGeom] lines = spatialIndex.intersects(inGeom.boundingBox()) if len(lines) > 0: # has intersection of bounding boxes splittingLines = [] engine = QgsGeometry.createGeometryEngine(inGeom.geometry()) engine.prepareGeometry() for i in lines: try: splitGeom = splitGeoms[i] except: continue # check if trying to self-intersect if sameLayer: if inFeatA.id() == i: continue if engine.intersects(splitGeom.geometry()): splittingLines.append(splitGeom) if len(splittingLines) > 0: for splitGeom in splittingLines: splitterPList = None outGeoms = [] split_geom_engine = QgsGeometry.createGeometryEngine( splitGeom.geometry()) split_geom_engine.prepareGeometry() while len(inGeoms) > 0: inGeom = inGeoms.pop() if inGeom.isEmpty( ): # this has been encountered and created a run-time error continue if split_geom_engine.intersects(inGeom.geometry()): inPoints = vector.extractPoints(inGeom) if splitterPList == None: splitterPList = vector.extractPoints( splitGeom) try: result, newGeometries, topoTestPoints = inGeom.splitGeometry( splitterPList, False) except: ProcessingLog.addToLog( ProcessingLog.LOG_WARNING, self. tr('Geometry exception while splitting' )) result = 1 # splitGeometry: If there are several intersections # between geometry and splitLine, only the first one is considered. if result == 0: # split occurred if inPoints == vector.extractPoints( inGeom): # bug in splitGeometry: sometimes it returns 0 but # the geometry is unchanged outGeoms.append(inGeom) else: inGeoms.append(inGeom) for aNewGeom in newGeometries: inGeoms.append(aNewGeom) else: outGeoms.append(inGeom) else: outGeoms.append(inGeom) inGeoms = outGeoms parts = [] for aGeom in inGeoms: passed = True if QgsWkbTypes.geometryType( aGeom.wkbType()) == QgsWkbTypes.LineGeometry: numPoints = aGeom.geometry().numPoints() if numPoints <= 2: if numPoints == 2: passed = not aGeom.geometry().isClosed( ) # tests if vertex 0 = vertex 1 else: passed = False # sometimes splitting results in lines of zero length if passed: parts.append(aGeom) if len(parts) > 0: outFeat.setGeometry(QgsGeometry.collectGeometry(parts)) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer
def buffering(progress, writer, distance, field, useField, layer, dissolve, segments, endCapStyle=1, joinStyle=1, mitreLimit=2): if useField: field = layer.fields().lookupField(field) outFeat = QgsFeature() current = 0 features = vector.features(layer) total = 100.0 / float(len(features)) # With dissolve if dissolve: first = True buffered_geometries = [] for inFeat in features: attrs = inFeat.attributes() if useField: value = attrs[field] else: value = distance inGeom = inFeat.geometry() if not inGeom: ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, 'Feature {} has empty geometry. Skipping...'.format(inFeat.id())) continue if not inGeom.isGeosValid(): ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, 'Feature {} has invalid geometry. Skipping...'.format(inFeat.id())) continue buffered_geometries.append(inGeom.buffer(float(value), segments, endCapStyle, joinStyle, mitreLimit)) current += 1 progress.setPercentage(int(current * total)) final_geometry = QgsGeometry.unaryUnion(buffered_geometries) outFeat.setGeometry(final_geometry) outFeat.setAttributes(attrs) writer.addFeature(outFeat) else: # Without dissolve for inFeat in features: attrs = inFeat.attributes() if useField: value = attrs[field] else: value = distance inGeom = inFeat.geometry() outFeat = QgsFeature() if inGeom.isEmpty() or inGeom.isGeosEmpty(): pass elif not inGeom.isGeosValid(): ProcessingLog.addToLog(ProcessingLog.LOG_WARNING, 'Feature {} has invalid geometry. Skipping...'.format(inFeat.id())) continue else: outGeom = inGeom.buffer(float(value), segments, endCapStyle, joinStyle, mitreLimit) outFeat.setGeometry(outGeom) outFeat.setAttributes(attrs) writer.addFeature(outFeat) current += 1 progress.setPercentage(int(current * total)) del writer
def accept(self): feedback = self.createFeedback() context = dataobjects.createContext(feedback) checkCRS = ProcessingConfig.getSetting( ProcessingConfig.WARN_UNMATCHING_CRS) try: parameters = self.getParameterValues() if checkCRS and not self.algorithm().validateInputCrs( parameters, context): reply = QMessageBox.question( self, self.tr("Unmatching CRS's"), self.tr('Layers do not all use the same CRS. This can ' 'cause unexpected results.\nDo you want to ' 'continue?'), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: return checkExtentCRS = ProcessingConfig.getSetting( ProcessingConfig.WARN_UNMATCHING_EXTENT_CRS) # TODO if False and checkExtentCRS and self.checkExtentCRS(): reply = QMessageBox.question( self, self.tr("Extent CRS"), self. tr('Extent parameters must use the same CRS as the input layers.\n' 'Your input layers do not have the same extent as the project, ' 'so the extent might be in a wrong CRS if you have selected it from the canvas.\n' 'Do you want to continue?'), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: return ok, msg = self.algorithm().checkParameterValues( parameters, context) if msg: QMessageBox.warning(self, self.tr('Unable to execute algorithm'), msg) return self.runButton().setEnabled(False) self.cancelButton().setEnabled(False) buttons = self.mainWidget().iterateButtons self.iterateParam = None for i in range(len(list(buttons.values()))): button = list(buttons.values())[i] if button.isChecked(): self.iterateParam = list(buttons.keys())[i] break self.clearProgress() self.setProgressText( QCoreApplication.translate('AlgorithmDialog', 'Processing algorithm…')) self.setInfo(QCoreApplication.translate( 'AlgorithmDialog', '<b>Algorithm \'{0}\' starting…</b>').format( self.algorithm().displayName()), escapeHtml=False) feedback.pushInfo(self.tr('Input parameters:')) display_params = [] for k, v in parameters.items(): display_params.append("'" + k + "' : " + self.algorithm().parameterDefinition( k).valueAsPythonString(v, context)) feedback.pushCommandInfo('{ ' + ', '.join(display_params) + ' }') feedback.pushInfo('') start_time = time.time() if self.iterateParam: # Make sure the Log tab is visible before executing the algorithm try: self.showLog() self.repaint() except: pass self.cancelButton().setEnabled( self.algorithm().flags() & QgsProcessingAlgorithm.FlagCanCancel) if executeIterating(self.algorithm(), parameters, self.iterateParam, context, feedback): feedback.pushInfo( self.tr('Execution completed in {0:0.2f} seconds'). format(time.time() - start_time)) self.cancelButton().setEnabled(False) self.finish(True, parameters, context, feedback) else: self.cancelButton().setEnabled(False) self.resetGui() else: command = self.algorithm().asPythonCommand(parameters, context) if command: ProcessingLog.addToLog(command) self.cancelButton().setEnabled( self.algorithm().flags() & QgsProcessingAlgorithm.FlagCanCancel) def on_complete(ok, results): if ok: feedback.pushInfo( self.tr('Execution completed in {0:0.2f} seconds'). format(time.time() - start_time)) feedback.pushInfo(self.tr('Results:')) feedback.pushCommandInfo(pformat(results)) else: feedback.reportError( self.tr('Execution failed after {0:0.2f} seconds'). format(time.time() - start_time)) feedback.pushInfo('') if self.feedback_dialog is not None: self.feedback_dialog.close() self.feedback_dialog.deleteLater() self.feedback_dialog = None self.cancelButton().setEnabled(False) self.finish(ok, results, context, feedback) if not (self.algorithm().flags() & QgsProcessingAlgorithm.FlagNoThreading): # Make sure the Log tab is visible before executing the algorithm self.showLog() task = QgsProcessingAlgRunnerTask(self.algorithm(), parameters, context, feedback) task.executed.connect(on_complete) self.setCurrentTask(task) else: self.feedback_dialog = self.createProgressDialog() self.feedback_dialog.show() ok, results = execute(self.algorithm(), parameters, context, feedback) on_complete(ok, results) except AlgorithmDialogBase.InvalidParameterValue as e: try: self.buttonBox().accepted.connect( lambda e=e: e.widget.setPalette(QPalette())) palette = e.widget.palette() palette.setColor(QPalette.Base, QColor(255, 255, 0)) e.widget.setPalette(palette) except: pass self.messageBar().clearWidgets() self.messageBar().pushMessage( "", self.tr("Wrong or missing parameter value: {0}").format( e.parameter.description()), level=Qgis.Warning, duration=5)
def processAlgorithm(self, progress): layerA = dataobjects.getObjectFromUri( self.getParameterValue(Difference.INPUT)) layerB = dataobjects.getObjectFromUri( self.getParameterValue(Difference.OVERLAY)) ignoreInvalid = self.getParameterValue(Difference.IGNORE_INVALID) geomType = QgsWKBTypes.multiType(QGis.fromOldWkbType(layerA.wkbType())) writer = self.getOutputFromName(Difference.OUTPUT).getVectorWriter( layerA.pendingFields(), geomType, layerA.crs()) outFeat = QgsFeature() index = vector.spatialindex(layerB) selectionA = vector.features(layerA) total = 100.0 / len(selectionA) if len(selectionA) > 0 else 1 for current, inFeatA in enumerate(selectionA): add = True geom = QgsGeometry(inFeatA.geometry()) diff_geom = QgsGeometry(geom) attrs = inFeatA.attributes() intersections = index.intersects(geom.boundingBox()) for i in intersections: request = QgsFeatureRequest().setFilterFid(i) inFeatB = layerB.getFeatures(request).next() tmpGeom = QgsGeometry(inFeatB.geometry()) if diff_geom.intersects(tmpGeom): diff_geom = QgsGeometry(diff_geom.difference(tmpGeom)) if diff_geom.isGeosEmpty(): ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr('Feature with NULL geometry found.')) if not diff_geom.isGeosValid(): if ignoreInvalid: ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self. tr('GEOS geoprocessing error: One or more input features have invalid geometry.' )) add = False else: raise GeoAlgorithmExecutionException( self. tr('Features with invalid geometries found. Please fix these errors or specify the "Ignore invalid input features" flag' )) break if add: try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(attrs) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_WARNING, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) continue progress.setPercentage(int(current * total)) del writer
def processAlgorithm(self, progress): if system.isWindows(): path = Grass7Utils.grassPath() if path == '': raise GeoAlgorithmExecutionException( self.tr( 'GRASS GIS 7 folder is not configured. Please ' 'configure it before running GRASS GIS 7 algorithms.')) # Create brand new commands lists self.commands = [] self.outputCommands = [] self.exportedLayers = {} # If GRASS session has been created outside of this algorithm then # get the list of layers loaded in GRASS otherwise start a new # session existingSession = Grass7Utils.sessionRunning if existingSession: self.exportedLayers = Grass7Utils.getSessionLayers() else: Grass7Utils.startGrass7Session() # Handle ext functions for inputs/command/outputs if self.module: if hasattr(self.module, 'processInputs'): func = getattr(self.module, 'processInputs') func(self) else: self.processInputs() if hasattr(self.module, 'processCommand'): func = getattr(self.module, 'processCommand') func(self) else: self.processCommand() if hasattr(self.module, 'processOutputs'): func = getattr(self.module, 'processOutputs') func(self) else: self.processOutputs() else: self.processInputs() self.processCommand() self.processOutputs() # Run GRASS loglines = [] loglines.append(self.tr('GRASS GIS 7 execution commands')) for line in self.commands: progress.setCommand(line) loglines.append(line) if ProcessingConfig.getSetting(Grass7Utils.GRASS_LOG_COMMANDS): ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines) Grass7Utils.executeGrass7(self.commands, progress, self.outputCommands) for out in self.outputs: if isinstance(out, OutputHTML): with open(self.getOutputFromName("rawoutput").value) as f: rawOutput = "".join(f.readlines()) with open(out.value, "w") as f: f.write("<pre>%s</pre>" % rawOutput) # If the session has been created outside of this algorithm, add # the new GRASS GIS 7 layers to it otherwise finish the session if existingSession: Grass7Utils.addSessionLayers(self.exportedLayers) else: Grass7Utils.endGrass7Session()
def defineCharacteristicsFromFile(self): lines = open(self.descriptionFile) line = lines.readline().strip('\n').strip() self.grass7Name = line line = lines.readline().strip('\n').strip() self.name = line self.i18n_name = QCoreApplication.translate("GrassAlgorithm", line) if " - " not in self.name: self.name = self.grass7Name + " - " + self.name self.i18n_name = self.grass7Name + " - " + self.i18n_name line = lines.readline().strip('\n').strip() self.group = line self.i18n_group = QCoreApplication.translate("GrassAlgorithm", line) hasRasterOutput = False hasVectorInput = False vectorOutputs = 0 line = lines.readline().strip('\n').strip() while line != '': try: line = line.strip('\n').strip() if line.startswith('Hardcoded'): self.hardcodedStrings.append(line[len('Hardcoded|'):]) elif line.startswith('Parameter'): parameter = getParameterFromString(line) self.addParameter(parameter) if isinstance(parameter, ParameterVector): hasVectorInput = True if isinstance(parameter, ParameterMultipleInput) \ and parameter.datatype < 3: hasVectorInput = True elif line.startswith('*Parameter'): param = getParameterFromString(line[1:]) param.isAdvanced = True self.addParameter(param) else: output = getOutputFromString(line) self.addOutput(output) if isinstance(output, OutputRaster): hasRasterOutput = True elif isinstance(output, OutputVector): vectorOutputs += 1 if isinstance(output, OutputHTML): self.addOutput( OutputFile("rawoutput", output.description + " (raw output)", "txt")) line = lines.readline().strip('\n').strip() except Exception as e: ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr('Could not open GRASS GIS 7 algorithm: %s\n%s' % (self.descriptionFile, line))) raise e lines.close() self.addParameter( ParameterExtent(self.GRASS_REGION_EXTENT_PARAMETER, self.tr('GRASS GIS 7 region extent'))) if hasRasterOutput: self.addParameter( ParameterNumber( self.GRASS_REGION_CELLSIZE_PARAMETER, self.tr( 'GRASS GIS 7 region cellsize (leave 0 for default)'), 0, None, 0.0)) if hasVectorInput: param = ParameterNumber(self.GRASS_SNAP_TOLERANCE_PARAMETER, 'v.in.ogr snap tolerance (-1 = no snap)', -1, None, -1.0) param.isAdvanced = True self.addParameter(param) param = ParameterNumber(self.GRASS_MIN_AREA_PARAMETER, 'v.in.ogr min area', 0, None, 0.0001) param.isAdvanced = True self.addParameter(param) if vectorOutputs == 1: param = ParameterSelection(self.GRASS_OUTPUT_TYPE_PARAMETER, 'v.out.ogr output type', self.OUTPUT_TYPES) param.isAdvanced = True self.addParameter(param)
def processAlgorithm(self, progress): layerA = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT)) layerB = dataobjects.getObjectFromUri( self.getParameterValue(self.OVERLAY)) providerA = layerA.dataProvider() providerB = layerB.dataProvider() GEOS_EXCEPT = True FEATURE_EXCEPT = True fields = vector.combineVectorFields(layerA, layerB) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, providerA.geometryType(), providerA.crs()) featB = QgsFeature() outFeat = QgsFeature() indexA = vector.spatialindex(layerB) indexB = vector.spatialindex(layerA) featuresA = vector.features(layerA) featuresB = vector.features(layerB) total = 100.0 / (len(featuresA) * len(featuresB)) count = 0 for featA in featuresA: add = True geom = QgsGeometry(featA.geometry()) diffGeom = QgsGeometry(geom) attrs = featA.attributes() intersects = indexA.intersects(geom.boundingBox()) for i in intersects: providerB.getFeatures( QgsFeatureRequest().setFilterFid(i)).nextFeature(featB) tmpGeom = QgsGeometry(featB.geometry()) try: if diffGeom.intersects(tmpGeom): diffGeom = QgsGeometry(diffGeom.difference(tmpGeom)) except: add = False GEOS_EXCEPT = False break if add: try: outFeat.setGeometry(diffGeom) outFeat.setAttributes(attrs) writer.addFeature(outFeat) except: FEATURE_EXCEPT = False continue count += 1 progress.setPercentage(int(count * total)) length = len(providerA.fields()) for featA in featuresB: add = True geom = QgsGeometry(featA.geometry()) diffGeom = QgsGeometry(geom) attrs = featA.attributes() attrs = [NULL] * length + attrs intersects = indexB.intersects(geom.boundingBox()) for i in intersects: providerA.getFeatures( QgsFeatureRequest().setFilterFid(i)).nextFeature(featB) tmpGeom = QgsGeometry(featB.geometry()) try: if diffGeom.intersects(tmpGeom): diffGeom = QgsGeometry(diffGeom.difference(tmpGeom)) except: add = False GEOS_EXCEPT = False break if add: try: outFeat.setGeometry(diffGeom) outFeat.setAttributes(attrs) writer.addFeature(outFeat) except: FEATURE_EXCEPT = False continue count += 1 progress.setPercentage(int(count * total)) del writer if not GEOS_EXCEPT: ProcessingLog.addToLog( ProcessingLog.LOG_WARNING, self. tr('Geometry exception while computing symetrical difference')) if not FEATURE_EXCEPT: ProcessingLog.addToLog( ProcessingLog.LOG_WARNING, self.tr( 'Feature exception while computing symetrical difference'))
def runAlgorithm(algOrName, onFinish, *args): if isinstance(algOrName, GeoAlgorithm): alg = algOrName else: alg = Processing.getAlgorithm(algOrName) if alg is None: print 'Error: Algorithm not found\n' return alg = alg.getCopy() if len(args) == 1 and isinstance(args[0], dict): # Set params by name and try to run the alg even if not all parameter values are provided, # by using the default values instead. setParams = [] for (name, value) in args[0].items(): param = alg.getParameterFromName(name) if param and param.setValue(value): setParams.append(name) continue output = alg.getOutputFromName(name) if output and output.setValue(value): continue print 'Error: Wrong parameter value %s for parameter %s.' % ( value, name) ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, Processing. tr('Error in %s. Wrong parameter value %s for parameter %s.' ) % (alg.name, value, name)) return # fill any missing parameters with default values if allowed for param in alg.parameters: if param.name not in setParams: if not param.setValue(None): print( 'Error: Missing parameter value for parameter %s.' % (param.name)) ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, Processing. tr('Error in %s. Missing parameter value for parameter %s.' ) % (alg.name, param.name)) return else: if len(args) != alg.getVisibleParametersCount( ) + alg.getVisibleOutputsCount(): print 'Error: Wrong number of parameters' processing.alghelp(algOrName) return i = 0 for param in alg.parameters: if not param.hidden: if not param.setValue(args[i]): print 'Error: Wrong parameter value: ' \ + unicode(args[i]) return i = i + 1 for output in alg.outputs: if not output.hidden: if not output.setValue(args[i]): print 'Error: Wrong output value: ' + unicode(args[i]) return i = i + 1 msg = alg.checkParameterValuesBeforeExecuting() if msg: print 'Unable to execute algorithm\n' + msg return if not alg.checkInputCRS(): print 'Warning: Not all input layers use the same CRS.\n' \ + 'This can cause unexpected results.' if iface is not None: # Don't set the wait cursor twice, because then when you # restore it, it will still be a wait cursor. cursor = QApplication.overrideCursor() if cursor is None or cursor == 0: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) elif cursor.shape() != Qt.WaitCursor: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) progress = None if iface is not None: progress = MessageBarProgress() ret = runalg(alg, progress) if onFinish is not None and ret: onFinish(alg, progress) if iface is not None: QApplication.restoreOverrideCursor() progress.close() return alg
def processAlgorithm(self, progress): layerA = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_A)) layerB = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT_B)) sameLayer = self.getParameterValue( self.INPUT_A) == self.getParameterValue(self.INPUT_B) fieldList = layerA.fields() writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fieldList, QgsWkbTypes.LineString, layerA.crs()) spatialIndex = vector.spatialindex(layerB) outFeat = QgsFeature() features = vector.features(layerA) total = 100.0 / float(len(features)) for current, inFeatA in enumerate(features): inGeom = inFeatA.geometry() attrsA = inFeatA.attributes() outFeat.setAttributes(attrsA) inLines = [inGeom] lines = spatialIndex.intersects(inGeom.boundingBox()) if len(lines) > 0: # hasIntersections splittingLines = [] for i in lines: request = QgsFeatureRequest().setFilterFid(i) inFeatB = layerB.getFeatures(request).next() # check if trying to self-intersect if sameLayer: if inFeatA.id() == inFeatB.id(): continue splitGeom = inFeatB.geometry() if inGeom.intersects(splitGeom): splittingLines.append(splitGeom) if len(splittingLines) > 0: for splitGeom in splittingLines: splitterPList = vector.extractPoints(splitGeom) outLines = [] while len(inLines) > 0: inGeom = inLines.pop() inPoints = vector.extractPoints(inGeom) if inGeom.intersects(splitGeom): try: result, newGeometries, topoTestPoints = inGeom.splitGeometry( splitterPList, False) except: ProcessingLog.addToLog( ProcessingLog.LOG_WARNING, self. tr('Geometry exception while splitting' )) result = 1 # splitGeometry: If there are several intersections # between geometry and splitLine, only the first one is considered. if result == 0: # split occurred if inPoints == vector.extractPoints( inGeom): # bug in splitGeometry: sometimes it returns 0 but # the geometry is unchanged outLines.append(inGeom) else: inLines.append(inGeom) for aNewGeom in newGeometries: inLines.append(aNewGeom) else: outLines.append(inGeom) else: outLines.append(inGeom) inLines = outLines for aLine in inLines: if len(aLine.asPolyline()) > 2 or \ (len(aLine.asPolyline()) == 2 and aLine.asPolyline()[0] != aLine.asPolyline()[1]): # sometimes splitting results in lines of zero length outFeat.setGeometry(aLine) writer.addFeature(outFeat) progress.setPercentage(int(current * total)) del writer
def processAlgorithm(self, feedback): inLayer = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT)) boundary = self.getParameterValue(self.MODE) == self.MODE_BOUNDARY smallestArea = self.getParameterValue( self.MODE) == self.MODE_SMALLEST_AREA if inLayer.selectedFeatureCount() == 0: ProcessingLog.addToLog( ProcessingLog.LOG_WARNING, self.tr('%s: (No selection in input layer "%s")' % (self.commandLineName(), self.getParameterValue(self.INPUT)))) featToEliminate = [] selFeatIds = inLayer.selectedFeatureIds() output = self.getOutputFromName(self.OUTPUT) writer = output.getVectorWriter(inLayer.fields(), inLayer.wkbType(), inLayer.crs()) for aFeat in inLayer.getFeatures(): if aFeat.id() in selFeatIds: # Keep references to the features to eliminate featToEliminate.append(aFeat) else: # write the others to output writer.addFeature(aFeat) # Delete all features to eliminate in processLayer processLayer = output.layer processLayer.startEditing() # ANALYZE if len(featToEliminate) > 0: # Prevent zero division start = 20.00 add = 80.00 / len(featToEliminate) else: start = 100 feedback.setProgress(start) madeProgress = True # We go through the list and see if we find any polygons we can # merge the selected with. If we have no success with some we # merge and then restart the whole story. while madeProgress: # Check if we made any progress madeProgress = False featNotEliminated = [] # Iterate over the polygons to eliminate for i in range(len(featToEliminate)): feat = featToEliminate.pop() geom2Eliminate = feat.geometry() bbox = geom2Eliminate.boundingBox() fit = processLayer.getFeatures( QgsFeatureRequest().setFilterRect( bbox).setSubsetOfAttributes([])) mergeWithFid = None mergeWithGeom = None max = 0 min = -1 selFeat = QgsFeature() # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine( geom2Eliminate.geometry()) engine.prepareGeometry() while fit.nextFeature(selFeat): selGeom = selFeat.geometry() if engine.intersects(selGeom.geometry()): # We have a candidate iGeom = geom2Eliminate.intersection(selGeom) if not iGeom: continue if boundary: selValue = iGeom.length() else: # area. We need a common boundary in # order to merge if 0 < iGeom.length(): selValue = selGeom.area() else: selValue = -1 if -1 != selValue: useThis = True if smallestArea: if -1 == min: min = selValue else: if selValue < min: min = selValue else: useThis = False else: if selValue > max: max = selValue else: useThis = False if useThis: mergeWithFid = selFeat.id() mergeWithGeom = QgsGeometry(selGeom) # End while fit if mergeWithFid is not None: # A successful candidate newGeom = mergeWithGeom.combine(geom2Eliminate) if processLayer.changeGeometry(mergeWithFid, newGeom): madeProgress = True else: raise GeoAlgorithmExecutionException( self. tr('Could not replace geometry of feature with id %s' % mergeWithFid)) start = start + add feedback.setProgress(start) else: featNotEliminated.append(feat) # End for featToEliminate featToEliminate = featNotEliminated # End while if not processLayer.commitChanges(): raise GeoAlgorithmExecutionException( self.tr('Could not commit changes')) for feature in featNotEliminated: writer.addFeature(feature)
def error(self, text): QMessageBox.critical(self, "Error", text) ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, text)
def processAlgorithm(self, progress): vlayerA = dataobjects.getObjectFromUri( self.getParameterValue(Union.INPUT)) vlayerB = dataobjects.getObjectFromUri( self.getParameterValue(Union.INPUT2)) geomType = vlayerA.wkbType() fields = vector.combineVectorFields(vlayerA, vlayerB) writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter( fields, geomType, vlayerA.crs()) inFeatA = QgsFeature() inFeatB = QgsFeature() outFeat = QgsFeature() indexA = vector.spatialindex(vlayerB) indexB = vector.spatialindex(vlayerA) count = 0 nElement = 0 featuresA = vector.features(vlayerA) nFeat = len(featuresA) for inFeatA in featuresA: progress.setPercentage(nElement / float(nFeat) * 50) nElement += 1 lstIntersectingB = [] geom = inFeatA.geometry() atMapA = inFeatA.attributes() intersects = indexA.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat) except: # This really shouldn't happen, as we haven't # edited the input geom at all ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: request = QgsFeatureRequest().setFilterFids(intersects) engine = QgsGeometry.createGeometryEngine(geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerB.getFeatures(request): count += 1 atMapB = inFeatB.attributes() tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): int_geom = geom.intersection(tmpGeom) lstIntersectingB.append(tmpGeom) if not int_geom: # There was a problem creating the intersection ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('GEOS geoprocessing error: One or more input features have invalid geometry.' )) int_geom = QgsGeometry() else: int_geom = QgsGeometry(int_geom) if int_geom.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( int_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: # Intersection produced different geomety types temp_list = int_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): int_geom = QgsGeometry(i) try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: # Geometry list: prevents writing error # in geometries of different types # produced by the intersection # fix #3549 if int_geom.wkbType() in wkbTypeGroups[ wkbTypeGroups[int_geom.wkbType()]]: try: outFeat.setGeometry(int_geom) outFeat.setAttributes(atMapA + atMapB) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) # the remaining bit of inFeatA's geometry # if there is nothing left, this will just silently fail and we're good diff_geom = QgsGeometry(geom) if len(lstIntersectingB) != 0: intB = QgsGeometry.unaryUnion(lstIntersectingB) diff_geom = diff_geom.difference(intB) if diff_geom.isGeosEmpty() or not diff_geom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self. tr('GEOS geoprocessing error: One or more input features have invalid geometry.' )) if diff_geom.wkbType() == 0 or QgsWkbTypes.flatType( diff_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: temp_list = diff_geom.asGeometryCollection() for i in temp_list: if i.type() == geom.type(): diff_geom = QgsGeometry(i) try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMapA) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) length = len(vlayerA.fields()) atMapA = [None] * length featuresA = vector.features(vlayerB) nFeat = len(featuresA) for inFeatA in featuresA: progress.setPercentage(nElement / float(nFeat) * 100) add = False geom = inFeatA.geometry() diff_geom = QgsGeometry(geom) atMap = [None] * length atMap.extend(inFeatA.attributes()) intersects = indexB.intersects(geom.boundingBox()) if len(intersects) < 1: try: outFeat.setGeometry(geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) else: request = QgsFeatureRequest().setFilterFids(intersects) # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine(diff_geom.geometry()) engine.prepareGeometry() for inFeatB in vlayerA.getFeatures(request): atMapB = inFeatB.attributes() tmpGeom = inFeatB.geometry() if engine.intersects(tmpGeom.geometry()): add = True diff_geom = QgsGeometry(diff_geom.difference(tmpGeom)) if diff_geom.isGeosEmpty( ) or not diff_geom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self. tr('GEOS geoprocessing error: One or more input features have invalid geometry.' )) else: try: # Ihis only happends if the bounding box # intersects, but the geometry doesn't outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) if add: try: outFeat.setGeometry(diff_geom) outFeat.setAttributes(atMap) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) nElement += 1 del writer
def processAlgorithm(self, progress): source_layer = dataobjects.getObjectFromUri( self.getParameterValue(Clip.INPUT)) mask_layer = dataobjects.getObjectFromUri( self.getParameterValue(Clip.OVERLAY)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( source_layer.fields(), QgsWkbTypes.multiType(source_layer.wkbType()), source_layer.crs()) # first build up a list of clip geometries clip_geoms = [] for maskFeat in vector.features( mask_layer, QgsFeatureRequest().setSubsetOfAttributes([])): clip_geoms.append(maskFeat.geometry()) # are we clipping against a single feature? if so, we can show finer progress reports if len(clip_geoms) > 1: combined_clip_geom = QgsGeometry.unaryUnion(clip_geoms) single_clip_feature = False else: combined_clip_geom = clip_geoms[0] single_clip_feature = True # use prepared geometries for faster intersection tests engine = QgsGeometry.createGeometryEngine( combined_clip_geom.geometry()) engine.prepareGeometry() tested_feature_ids = set() for i, clip_geom in enumerate(clip_geoms): input_features = [ f for f in vector.features( source_layer, QgsFeatureRequest().setFilterRect(clip_geom.boundingBox())) ] if not input_features: continue if single_clip_feature: total = 100.0 / len(input_features) else: total = 0 for current, in_feat in enumerate(input_features): if not in_feat.geometry(): continue if in_feat.id() in tested_feature_ids: # don't retest a feature we have already checked continue tested_feature_ids.add(in_feat.id()) if not engine.intersects(in_feat.geometry().geometry()): continue if not engine.contains(in_feat.geometry().geometry()): cur_geom = in_feat.geometry() new_geom = combined_clip_geom.intersection(cur_geom) if new_geom.wkbType( ) == QgsWkbTypes.Unknown or QgsWkbTypes.flatType( new_geom.geometry().wkbType( )) == QgsWkbTypes.GeometryCollection: int_com = in_feat.geometry().combine(new_geom) int_sym = in_feat.geometry().symDifference(new_geom) if not int_com or not int_sym: ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr( 'GEOS geoprocessing error: One or more ' 'input features have invalid geometry.')) else: new_geom = int_com.difference(int_sym) if new_geom.isGeosEmpty( ) or not new_geom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self. tr('GEOS geoprocessing error: One or more ' 'input features have invalid geometry.' )) else: # clip geometry totally contains feature geometry, so no need to perform intersection new_geom = in_feat.geometry() try: out_feat = QgsFeature() out_feat.setGeometry(new_geom) out_feat.setAttributes(in_feat.attributes()) writer.addFeature(out_feat) except: ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr('Feature geometry error: One or more ' 'output features ignored due to ' 'invalid geometry.')) continue if single_clip_feature: progress.setPercentage(int(current * total)) if not single_clip_feature: # coarse progress report for multiple clip geometries progress.setPercentage(100.0 * i / len(clip_geoms)) del writer
def getLiteralResult(self, identifier, literalText): self.setOutputValue(identifier, literalText) ProcessingLog.addToLog(ProcessingLog.LOG_INFO, identifier + ": " + literalText)
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT)) hSpacing = self.getParameterValue(self.HSPACING) vSpacing = self.getParameterValue(self.VSPACING) if hSpacing <= 0 or vSpacing <= 0: raise GeoAlgorithmExecutionException( self.tr('Invalid grid spacing: %s/%s' % (hSpacing, vSpacing))) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( layer.pendingFields(), layer.wkbType(), layer.crs()) features = vector.features(layer) total = 100.0 / len(features) if len(features) > 0 else 1 for current, f in enumerate(features): geom = f.geometry() geomType = geom.wkbType() if geomType == QGis.WKBPoint: points = self._gridify([geom.asPoint()], hSpacing, vSpacing) newGeom = QgsGeometry.fromPoint(points[0]) elif geomType == QGis.WKBMultiPoint: points = self._gridify(geom.aMultiPoint(), hSpacing, vSpacing) newGeom = QgsGeometry.fromMultiPoint(points) elif geomType == QGis.WKBLineString: points = self._gridify(geom.asPolyline(), hSpacing, vSpacing) if len(points) < 2: ProcessingLog.addToLog(ProcessingLog.LOG_INFO, self.tr('Failed to gridify feature with FID %s' % f.id())) newGeom = None else: newGeom = QgsGeometry.fromPolyline(points) elif geomType == QGis.WKBMultiLineString: polyline = [] for line in geom.asMultiPolyline(): points = self._gridify(line, hSpacing, vSpacing) if len(points) > 1: polyline.append(points) if len(polyline) <= 0: ProcessingLog.addToLog(ProcessingLog.LOG_INFO, self.tr('Failed to gridify feature with FID %s' % f.id())) newGeom = None else: newGeom = QgsGeometry.fromMultiPolyline(polyline) elif geomType == QGis.WKBPolygon: polygon = [] for line in geom.asPolygon(): points = self._gridify(line, hSpacing, vSpacing) if len(points) > 1: polygon.append(points) if len(polygon) <= 0: ProcessingLog.addToLog(ProcessingLog.LOG_INFO, self.tr('Failed to gridify feature with FID %s' % f.id())) newGeom = None else: newGeom = QgsGeometry.fromPolygon(polygon) elif geomType == QGis.WKBMultiPolygon: multipolygon = [] for polygon in geom.asMultiPolygon(): newPolygon = [] for line in polygon: points = self._gridify(line, hSpacing, vSpacing) if len(points) > 2: newPolygon.append(points) if len(newPolygon) > 0: multipolygon.append(newPolygon) if len(multipolygon) <= 0: ProcessingLog.addToLog(ProcessingLog.LOG_INFO, self.tr('Failed to gridify feature with FID %s' % f.id())) newGeom = None else: newGeom = QgsGeometry.fromMultiPolygon(multipolygon) if newGeom is not None: feat = QgsFeature() feat.setGeometry(newGeom) feat.setAttributes(f.attributes()) writer.addFeature(feat) progress.setPercentage(int(current * total)) del writer
class OTBAlgorithm(GeoAlgorithm): REGION_OF_INTEREST = "ROI" def __init__(self, descriptionfile): GeoAlgorithm.__init__(self) self.roiFile = None self.descriptionFile = descriptionfile self.defineCharacteristicsFromFile() self.numExportedLayers = 0 self.hasROI = None def __str__(self): return ("Algo : " + self.name + " from app : " + self.cliName + " in : " + self.group) def getCopy(self): newone = OTBAlgorithm(self.descriptionFile) newone.provider = self.provider return newone def getIcon(self): return QIcon(os.path.join(pluginPath, 'images', 'otb.png')) def help(self): folder = os.path.join(OTBUtils.otbDescriptionPath(), 'doc') helpfile = os.path.join(str(folder), self.appkey + ".html") if os.path.exists(helpfile): return False, helpfile else: raise (False, None) def adapt_list_to_string(self, c_list): a_list = c_list[1:] if a_list[0] in ["ParameterVector", "ParameterMultipleInput"]: if c_list[0] == "ParameterType_InputImageList": a_list[3] = 3 elif c_list[0] == "ParameterType_InputFilenameList": a_list[3] = 4 else: a_list[3] = -1 a_list[1] = "-%s" % a_list[1] def mystr(par): if isinstance(par, list): return ";".join(par) return str(par) b_list = map(mystr, a_list) res = "|".join(b_list) return res def get_list_from_node(self, myet): all_params = [] for parameter in myet.iter('parameter'): rebuild = [] par_type = parameter.find('parameter_type').text key = parameter.find('key').text name = parameter.find('name').text source_par_type = parameter.find( 'parameter_type').attrib['source_parameter_type'] rebuild.append(source_par_type) rebuild.append(par_type) rebuild.append(key) rebuild.append(name) for each in parameter[4:]: if each.tag not in ["hidden"]: if len(list(each)) == 0: rebuild.append(each.text) else: rebuild.append( [item.text for item in each.iter('choice')]) all_params.append(rebuild) return all_params def defineCharacteristicsFromFile(self): content = open(self.descriptionFile).read() dom_model = ET.fromstring(content) self.appkey = dom_model.find('key').text self.cliName = dom_model.find('exec').text self.name = dom_model.find('longname').text self.group = dom_model.find('group').text rebu = None the_result = None try: rebu = self.get_list_from_node(dom_model) the_result = map(self.adapt_list_to_string, rebu) except Exception, e: ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr('Could not open OTB algorithm: %s\n%s' % (self.descriptionFile, traceback.format_exc()))) raise e for line in the_result: try: if line.startswith("Parameter") or line.startswith( "*Parameter"): if line.startswith("*Parameter"): param = getParameterFromString(line[1:]) param.isAdvanced = True else: param = getParameterFromString(line) # Hack for initializing the elevation parameters from Processing configuration if param.name == "-elev.dem.path" or param.name == "-elev.dem" or "elev.dem" in param.name: param.default = OTBUtils.otbSRTMPath() elif param.name == "-elev.dem.geoid" or param.name == "-elev.geoid" or "elev.geoid" in param.name: param.default = OTBUtils.otbGeoidPath() self.addParameter(param) elif line.startswith("Extent"): self.addParameter( ParameterExtent(self.REGION_OF_INTEREST, "Region of interest", "0,1,0,1")) self.hasROI = True else: self.addOutput(getOutputFromString(line)) except Exception, e: ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr('Could not open OTB algorithm: %s\n%s' % (self.descriptionFile, line))) raise e
def processAlgorithm(self, progress): layer = dataobjects.getObjectFromUri( self.getParameterValue(self.VECTOR)) pointCount = float(self.getParameterValue(self.POINT_NUMBER)) minDistance = float(self.getParameterValue(self.MIN_DISTANCE)) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QGis.WKBPoint, layer.dataProvider().crs()) nPoints = 0 nIterations = 0 maxIterations = pointCount * 200 featureCount = layer.featureCount() total = 100.0 / pointCount index = QgsSpatialIndex() points = dict() da = QgsDistanceArea() request = QgsFeatureRequest() random.seed() while nIterations < maxIterations and nPoints < pointCount: # pick random feature fid = random.randint(0, featureCount - 1) f = layer.getFeatures(request.setFilterFid(fid)).next() fGeom = QgsGeometry(f.geometry()) if fGeom.isMultipart(): lines = fGeom.asMultiPolyline() # pick random line lineId = random.randint(0, len(lines) - 1) vertices = lines[lineId] else: vertices = fGeom.asPolyline() # pick random segment if len(vertices) == 2: vid = 0 else: vid = random.randint(0, len(vertices) - 2) startPoint = vertices[vid] endPoint = vertices[vid + 1] length = da.measureLine(startPoint, endPoint) dist = length * random.random() if dist > minDistance: d = dist / (length - dist) rx = (startPoint.x() + d * endPoint.x()) / (1 + d) ry = (startPoint.y() + d * endPoint.y()) / (1 + d) # generate random point pnt = QgsPoint(rx, ry) geom = QgsGeometry.fromPoint(pnt) if vector.checkMinDistance(pnt, index, minDistance, points): f = QgsFeature(nPoints) f.initAttributes(1) f.setFields(fields) f.setAttribute('id', nPoints) f.setGeometry(geom) writer.addFeature(f) index.insertFeature(f) points[nPoints] = pnt nPoints += 1 progress.setPercentage(int(nPoints * total)) nIterations += 1 if nPoints < pointCount: ProcessingLog.addToLog(ProcessingLog.LOG_INFO, self.tr('Can not generate requested number of random points. ' 'Maximum number of attempts exceeded.')) del writer
def processAlgorithm(self, progress): layerA = dataobjects.getObjectFromUri( self.getParameterValue(self.INPUT)) layerB = dataobjects.getObjectFromUri( self.getParameterValue(self.OVERLAY)) geomType = QgsWkbTypes.multiType(layerA.wkbType()) fields = vector.combineVectorFields(layerA, layerB) writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, geomType, layerA.crs()) featB = QgsFeature() outFeat = QgsFeature() indexA = vector.spatialindex(layerB) indexB = vector.spatialindex(layerA) featuresA = vector.features(layerA) featuresB = vector.features(layerB) total = 100.0 / (len(featuresA) * len(featuresB)) count = 0 for featA in featuresA: add = True geom = featA.geometry() diffGeom = QgsGeometry(geom) attrs = featA.attributes() intersects = indexA.intersects(geom.boundingBox()) request = QgsFeatureRequest().setFilterFids( intersects).setSubsetOfAttributes([]) for featB in layerB.getFeatures(request): tmpGeom = featB.geometry() if diffGeom.intersects(tmpGeom): diffGeom = QgsGeometry(diffGeom.difference(tmpGeom)) if not diffGeom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) add = False break if add: try: outFeat.setGeometry(diffGeom) outFeat.setAttributes(attrs) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_WARNING, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) continue count += 1 progress.setPercentage(int(count * total)) length = len(layerA.fields()) for featA in featuresB: add = True geom = featA.geometry() diffGeom = QgsGeometry(geom) attrs = featA.attributes() attrs = [NULL] * length + attrs intersects = indexB.intersects(geom.boundingBox()) request = QgsFeatureRequest().setFilterFids( intersects).setSubsetOfAttributes([]) for featB in layerA.getFeatures(request): tmpGeom = featB.geometry() if diffGeom.intersects(tmpGeom): diffGeom = QgsGeometry(diffGeom.difference(tmpGeom)) if not diffGeom.isGeosValid(): ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, self.tr('GEOS geoprocessing error: One or ' 'more input features have invalid ' 'geometry.')) add = False break if add: try: outFeat.setGeometry(diffGeom) outFeat.setAttributes(attrs) writer.addFeature(outFeat) except: ProcessingLog.addToLog( ProcessingLog.LOG_WARNING, self. tr('Feature geometry error: One or more output features ignored due to invalid geometry.' )) continue count += 1 progress.setPercentage(int(count * total)) del writer
def processAlgorithm(self, feedback): commands = list() self.exportedLayers = {} self.preProcessInputs() # 1: Export rasters to sgrd and vectors to shp # Tables must be in dbf format. We check that. for param in self.parameters: if isinstance(param, ParameterRaster): if param.value is None: continue if param.value.endswith('sdat'): param.value = param.value[:-4] + "sgrd" elif not param.value.endswith('sgrd'): exportCommand = self.exportRasterLayer(param.value) if exportCommand is not None: commands.append(exportCommand) if isinstance(param, ParameterVector): if param.value is None: continue layer = dataobjects.getLayerFromString(param.value, False) if layer: filename = dataobjects.exportVectorLayer(layer) self.exportedLayers[param.value] = filename elif not param.value.endswith('shp'): raise GeoAlgorithmExecutionException( self.tr('Unsupported file format')) if isinstance(param, ParameterTable): if param.value is None: continue table = dataobjects.getLayerFromString(param.value, False) if table: filename = dataobjects.exportTable(table) self.exportedLayers[param.value] = filename elif not param.value.endswith('shp'): raise GeoAlgorithmExecutionException( self.tr('Unsupported file format')) if isinstance(param, ParameterMultipleInput): if param.value is None: continue layers = param.value.split(';') if layers is None or len(layers) == 0: continue if param.datatype == dataobjects.TYPE_RASTER: for i, layerfile in enumerate(layers): if layerfile.endswith('sdat'): layerfile = param.value[:-4] + "sgrd" layers[i] = layerfile elif not layerfile.endswith('sgrd'): exportCommand = self.exportRasterLayer(layerfile) if exportCommand is not None: commands.append(exportCommand) param.value = ";".join(layers) elif param.datatype in [ dataobjects.TYPE_VECTOR_ANY, dataobjects.TYPE_VECTOR_LINE, dataobjects.TYPE_VECTOR_POLYGON, dataobjects.TYPE_VECTOR_POINT ]: for layerfile in layers: layer = dataobjects.getLayerFromString( layerfile, False) if layer: filename = dataobjects.exportVectorLayer(layer) self.exportedLayers[layerfile] = filename elif not layerfile.endswith('shp'): raise GeoAlgorithmExecutionException( self.tr('Unsupported file format')) # 2: Set parameters and outputs command = self.undecoratedGroup + ' "' + self.cmdname + '"' command += ' ' + ' '.join(self.hardcodedStrings) for param in self.parameters: if param.value is None: continue if isinstance(param, (ParameterRaster, ParameterVector, ParameterTable)): value = param.value if value in list(self.exportedLayers.keys()): command += ' -' + param.name + ' "' \ + self.exportedLayers[value] + '"' else: command += ' -' + param.name + ' "' + value + '"' elif isinstance(param, ParameterMultipleInput): s = param.value for layer in list(self.exportedLayers.keys()): s = s.replace(layer, self.exportedLayers[layer]) command += ' -' + param.name + ' "' + s + '"' elif isinstance(param, ParameterBoolean): if param.value: command += ' -' + param.name.strip() + " true" else: command += ' -' + param.name.strip() + " false" elif isinstance(param, ParameterFixedTable): tempTableFile = getTempFilename('txt') with open(tempTableFile, 'w') as f: f.write('\t'.join([col for col in param.cols]) + '\n') values = param.value.split(',') for i in range(0, len(values), 3): s = values[i] + '\t' + values[i + 1] + '\t' + values[ i + 2] + '\n' f.write(s) command += ' -' + param.name + ' "' + tempTableFile + '"' elif isinstance(param, ParameterExtent): # 'We have to substract/add half cell size, since SAGA is # center based, not corner based halfcell = self.getOutputCellsize() / 2 offset = [halfcell, -halfcell, halfcell, -halfcell] values = param.value.split(',') for i in range(4): command += ' -' + self.extentParamNames[i] + ' ' \ + str(float(values[i]) + offset[i]) elif isinstance(param, (ParameterNumber, ParameterSelection)): command += ' -' + param.name + ' ' + str(param.value) else: command += ' -' + param.name + ' "' + str(param.value) + '"' for out in self.outputs: command += ' -' + out.name + ' "' + out.getCompatibleFileName( self) + '"' commands.append(command) # special treatment for RGB algorithm # TODO: improve this and put this code somewhere else for out in self.outputs: if isinstance(out, OutputRaster): filename = out.getCompatibleFileName(self) filename2 = filename + '.sgrd' if self.cmdname == 'RGB Composite': commands.append('io_grid_image 0 -IS_RGB -GRID:"' + filename2 + '" -FILE:"' + filename + '"') # 3: Run SAGA commands = self.editCommands(commands) SagaUtils.createSagaBatchJobFileFromSagaCommands(commands) loglines = [] loglines.append(self.tr('SAGA execution commands')) for line in commands: feedback.pushCommandInfo(line) loglines.append(line) if ProcessingConfig.getSetting(SagaUtils.SAGA_LOG_COMMANDS): ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines) SagaUtils.executeSaga(feedback) if self.crs is not None: for out in self.outputs: if isinstance(out, (OutputVector, OutputRaster)): prjFile = os.path.splitext( out.getCompatibleFileName(self))[0] + ".prj" with open(prjFile, "w") as f: f.write(self.crs.toWkt())
class GeoAlgorithm: def __init__(self): # Parameters needed by the algorithm self.parameters = list() # Outputs generated by the algorithm self.outputs = list() # Name and group for normal toolbox display self.name = '' self.group = '' # The crs taken from input layers (if possible), and used when # loading output layers self.crs = None # Change any of the following if your algorithm should not # appear in the toolbox or modeler self.showInToolbox = True self.showInModeler = True #if true, will show only loaded layers in parameters dialog. #Also, if True, the algorithm does not run on the modeler #or batch ptocessing interface self.allowOnlyOpenedLayers = False # False if it should not be run a a batch process self.canRunInBatchMode = True # To be set by the provider when it loads the algorithm self.provider = None # If the algorithm is run as part of a model, the parent model # can be set in this variable, to allow for customized # behaviour, in case some operations should be run differently # when running as part of a model self.model = None self.defineCharacteristics() def getCopy(self): """Returns a new instance of this algorithm, ready to be used for being executed. """ newone = copy.copy(self) newone.parameters = copy.deepcopy(self.parameters) newone.outputs = copy.deepcopy(self.outputs) return newone # methods to overwrite when creating a custom geoalgorithm def getIcon(self): return QtGui.QIcon(os.path.dirname(__file__) + '/../images/alg.png') @staticmethod def getDefaultIcon(): return QtGui.QIcon(os.path.dirname(__file__) + '/../images/alg.png') def help(self): """Returns the help with the description of this algorithm. It returns a tuple boolean, string. IF the boolean value is true, it means that the string contains the actual description. If false, it is an url or path to a file where the description is stored. Returns None if there is no help file available. The default implementation looks for an rst file in a help folder under the folder where the algorithm is located. The name of the file is the name console name of the algorithm, without the namespace part """ name = self.commandLineName().split(':')[1].lower() filename = os.path.join( os.path.dirname(inspect.getfile(self.__class__)), 'help', name + '.rst') print filename try: html = getHtmlFromRstFile(filename) return True, html except: return False, None def processAlgorithm(self): """Here goes the algorithm itself. There is no return value from this method. A GeoAlgorithmExecutionException should be raised in case something goes wrong. """ pass def defineCharacteristics(self): """Here is where the parameters and outputs should be defined. """ pass def getCustomParametersDialog(self): """If the algorithm has a custom parameters dialog, it should be returned here, ready to be executed. """ return None def getCustomModelerParametersDialog(self, modelAlg, algIndex=None): """If the algorithm has a custom parameters dialog when called from the modeler, it should be returned here, ready to be executed. """ return None def getParameterDescriptions(self): """Returns a dict with param names as keys and detailed descriptions of each param as value. These descriptions are used as tool tips in the parameters dialog. If a description does not exist, the parameter's human-readable name is used. """ descs = {} return descs def checkBeforeOpeningParametersDialog(self): """If there is any check to perform before the parameters dialog is opened, it should be done here. This method returns an error message string if there is any problem (for instance, an external app not configured yet), or None if the parameters dialog can be opened. Note that this check should also be done in the processAlgorithm method, since algorithms can be called without opening the parameters dialog. """ return None def checkParameterValuesBeforeExecuting(self): """If there is any check to do before launching the execution of the algorithm, it should be done here. If values are not correct, a message should be returned explaining the problem. This check is called from the parameters dialog, and also when calling from the console. """ return None # ========================================================= def execute(self, progress, model=None): """The method to use to call a processing algorithm. Although the body of the algorithm is in processAlgorithm(), it should be called using this method, since it performs some additional operations. Raises a GeoAlgorithmExecutionException in case anything goe wrong. """ self.model = model try: self.setOutputCRS() self.resolveTemporaryOutputs() self.checkOutputFileExtensions() self.runPreExecutionScript(progress) self.processAlgorithm(progress) self.convertUnsupportedFormats(progress) self.runPostExecutionScript(progress) except GeoAlgorithmExecutionException, gaee: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, gaee.msg) raise gaee except Exception, e: # If something goes wrong and is not caught in the # algorithm, we catch it here and wrap it lines = ['Uncaught error while executing algorithm'] errstring = traceback.format_exc() newline = errstring.find('\n') if newline != -1: lines.append(errstring[:newline]) else: lines.append(errstring) lines.append(errstring.replace('\n', '|')) ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, lines) raise GeoAlgorithmExecutionException( str(e) + '\nSee log for more details')
def processAlgorithm(self, progress): currentOs = os.name path = OTBUtils.otbPath() libpath = OTBUtils.otbLibPath() if path == "" or libpath == "": raise GeoAlgorithmExecutionException( self.tr('OTB folder is not configured. Please configure it ' 'before running OTB algorithms.')) commands = [] commands.append(path + os.sep + self.cliName) self.roiVectors = {} self.roiRasters = {} for param in self.parameters: # get the given input(s) if param.name in ["-il", "-in"]: newparams = "" listeParameters = param.value.split(";") for inputParameter in listeParameters: # if HDF5 file if "HDF5" in inputParameter: if currentOs == "posix": data = inputParameter[6:] else: data = inputParameter[5:] dataset = data #on windows, there isn't " #if data[-1] == '"': if currentOs == "posix": data = data[:data.index('"')] else: data = data[:data.index('://')] #try : if currentOs == "posix": dataset.index('"') dataset = os.path.basename( data) + dataset[dataset.index('"'):] #except ValueError : else: #dataset = os.path.basename( data ) + '"' + dataset[dataset.index('://'):] dataset = dataset[dataset.index('://'):] #get index of the subdataset with gdal if currentOs == "posix": commandgdal = "gdalinfo " + data + " | grep '" + dataset + "$'" else: commandgdal = "gdalinfo " + data + " | findstr \"" + dataset + "$\"" resultGDAL = os.popen(commandgdal).readlines() indexSubdataset = -1 if resultGDAL: indexSubdatasetString = re.search( "SUBDATASET_(\d+)_", resultGDAL[0]) if indexSubdatasetString: #match between () indexSubdataset = indexSubdatasetString.group( 1) else: indexSubdataset = -1 else: #print "Error : no match of ", dataset, "$ in gdalinfo " + data indexSubdataset = -1 if not indexSubdataset == -1: indexSubdataset = int(indexSubdataset) - 1 newParam = "\'" + data + "?&sdataidx=" + str( indexSubdataset) + "\'" else: newParam = inputParameter newparams += newParam # no hdf5 else: newparams += inputParameter newparams += ";" if newparams[-1] == ";": newparams = newparams[:-1] param.value = newparams if param.value is None or param.value == "": continue if isinstance(param, ParameterVector): commands.append(param.name) if self.hasROI: roiFile = getTempFilename('shp') commands.append(roiFile) self.roiVectors[param.value] = roiFile else: commands.append("\"" + param.value + "\"") elif isinstance(param, ParameterRaster): commands.append(param.name) if self.hasROI: roiFile = getTempFilename('tif') commands.append(roiFile) self.roiRasters[param.value] = roiFile else: commands.append("\"" + param.value + "\"") elif isinstance(param, ParameterMultipleInput): commands.append(param.name) files = str(param.value).split(";") paramvalue = " ".join(["\"" + f + " \"" for f in files]) commands.append(paramvalue) elif isinstance(param, ParameterSelection): commands.append(param.name) idx = int(param.value) commands.append(str(param.options[idx])) elif isinstance(param, ParameterBoolean): if param.value: commands.append(param.name) commands.append(str(param.value).lower()) elif isinstance(param, ParameterExtent): self.roiValues = param.value.split(",") else: commands.append(param.name) commands.append(str(param.value)) for out in self.outputs: commands.append(out.name) commands.append('"' + out.value + '"') for roiInput, roiFile in self.roiRasters.items(): startX, startY = float(self.roiValues[0]), float(self.roiValues[1]) sizeX = float(self.roiValues[2]) - startX sizeY = float(self.roiValues[3]) - startY helperCommands = [ "otbcli_ExtractROI", "-in", roiInput, "-out", roiFile, "-startx", str(startX), "-starty", str(startY), "-sizex", str(sizeX), "-sizey", str(sizeY) ] ProcessingLog.addToLog(ProcessingLog.LOG_INFO, helperCommands) progress.setCommand(helperCommands) OTBUtils.executeOtb(helperCommands, progress) if self.roiRasters: supportRaster = self.roiRasters.itervalues().next() for roiInput, roiFile in self.roiVectors.items(): helperCommands = [ "otbcli_VectorDataExtractROIApplication", "-vd.in", roiInput, "-io.in", supportRaster, "-io.out", roiFile, "-elev.dem.path", OTBUtils.otbSRTMPath() ] ProcessingLog.addToLog(ProcessingLog.LOG_INFO, helperCommands) progress.setCommand(helperCommands) OTBUtils.executeOtb(helperCommands, progress) loglines = [] loglines.append(self.tr('OTB execution command')) for line in commands: loglines.append(line) progress.setCommand(line) ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines) import processing.algs.otb.OTBSpecific_XMLLoading module = processing.algs.otb.OTBSpecific_XMLLoading found = False if 'adapt%s' % self.appkey in dir(module): found = True commands = getattr(module, 'adapt%s' % self.appkey)(commands) else: the_key = 'adapt%s' % self.appkey if '-' in the_key: base_key = the_key.split("-")[0] if base_key in dir(module): found = True commands = getattr(module, base_key)(commands) if not found: ProcessingLog.addToLog( ProcessingLog.LOG_INFO, self.tr("Adapter for %s not found" % the_key)) #frames = inspect.getouterframes(inspect.currentframe())[1:] #for a_frame in frames: # frame,filename,line_number,function_name,lines,index = a_frame # ProcessingLog.addToLog(ProcessingLog.LOG_INFO, "%s %s %s %s %s %s" % (frame,filename,line_number,function_name,lines,index)) OTBUtils.executeOtb(commands, progress)
def accept(self): super(AlgorithmDialog, self)._saveGeometry() feedback = self.createFeedback() context = dataobjects.createContext(feedback) checkCRS = ProcessingConfig.getSetting( ProcessingConfig.WARN_UNMATCHING_CRS) try: parameters = self.getParamValues() if checkCRS and not self.alg.validateInputCrs(parameters, context): reply = QMessageBox.question( self, self.tr("Unmatching CRS's"), self.tr('Layers do not all use the same CRS. This can ' 'cause unexpected results.\nDo you want to ' 'continue?'), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: return checkExtentCRS = ProcessingConfig.getSetting( ProcessingConfig.WARN_UNMATCHING_EXTENT_CRS) #TODO if False and checkExtentCRS and self.checkExtentCRS(): reply = QMessageBox.question( self, self.tr("Extent CRS"), self. tr('Extent parameters must use the same CRS as the input layers.\n' 'Your input layers do not have the same extent as the project, ' 'so the extent might be in a wrong CRS if you have selected it from the canvas.\n' 'Do you want to continue?'), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: return ok, msg = self.alg.checkParameterValues(parameters, context) if msg: QMessageBox.warning(self, self.tr('Unable to execute algorithm'), msg) return self.btnRun.setEnabled(False) self.btnClose.setEnabled(False) buttons = self.mainWidget.iterateButtons self.iterateParam = None for i in range(len(list(buttons.values()))): button = list(buttons.values())[i] if button.isChecked(): self.iterateParam = list(buttons.keys())[i] break self.progressBar.setMaximum(0) self.lblProgress.setText(self.tr('Processing algorithm...')) # Make sure the Log tab is visible before executing the algorithm try: self.tabWidget.setCurrentIndex(1) self.repaint() except: pass self.setInfo( self.tr('<b>Algorithm \'{0}\' starting...</b>').format( self.alg.displayName()), escape_html=False) feedback.pushInfo(self.tr('Input parameters:')) feedback.pushCommandInfo(pformat(parameters)) feedback.pushInfo('') start_time = time.time() if self.iterateParam: self.buttonCancel.setEnabled( self.alg.flags() & QgsProcessingAlgorithm.FlagCanCancel) if executeIterating(self.alg, parameters, self.iterateParam, context, feedback): feedback.pushInfo( self.tr( 'Execution completed in {0:0.2f} seconds'.format( time.time() - start_time))) self.buttonCancel.setEnabled(False) self.finish(parameters, context, feedback) else: self.buttonCancel.setEnabled(False) self.resetGUI() else: command = self.alg.asPythonCommand(parameters, context) if command: ProcessingLog.addToLog(command) self.buttonCancel.setEnabled( self.alg.flags() & QgsProcessingAlgorithm.FlagCanCancel) def on_complete(ok, results): if ok: feedback.pushInfo( self.tr('Execution completed in {0:0.2f} seconds'. format(time.time() - start_time))) feedback.pushInfo(self.tr('Results:')) feedback.pushCommandInfo(pformat(results)) else: feedback.reportError( self.tr('Execution failed after {0:0.2f} seconds'. format(time.time() - start_time))) feedback.pushInfo('') self.buttonCancel.setEnabled(False) self.finish(results, context, feedback) task = QgsProcessingAlgRunnerTask(self.alg, parameters, context, feedback) task.executed.connect(on_complete) QgsApplication.taskManager().addTask(task) except AlgorithmDialogBase.InvalidParameterValue as e: try: self.buttonBox.accepted.connect( lambda e=e: e.widget.setPalette(QPalette())) palette = e.widget.palette() palette.setColor(QPalette.Base, QColor(255, 255, 0)) e.widget.setPalette(palette) except: pass self.bar.clearWidgets() self.bar.pushMessage( "", self.tr("Wrong or missing parameter value: {0}").format( e.parameter.description()), level=QgsMessageBar.WARNING, duration=5)
def accept(self): self.settings.setValue("/Processing/dialogBase", self.saveGeometry()) checkCRS = ProcessingConfig.getSetting(ProcessingConfig.WARN_UNMATCHING_CRS) try: self.setParamValues() if checkCRS and not self.alg.checkInputCRS(): reply = QMessageBox.question(self, self.tr("Unmatching CRS's"), self.tr('Layers do not all use the same CRS. This can ' 'cause unexpected results.\nDo you want to ' 'continue?'), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: return msg = self.alg._checkParameterValuesBeforeExecuting() if msg: QMessageBox.warning( self, self.tr('Unable to execute algorithm'), msg) return self.btnRun.setEnabled(False) self.btnClose.setEnabled(False) buttons = self.mainWidget.iterateButtons self.iterateParam = None for i in range(len(buttons.values())): button = buttons.values()[i] if button.isChecked(): self.iterateParam = buttons.keys()[i] break self.progressBar.setMaximum(0) self.lblProgress.setText(self.tr('Processing algorithm...')) # Make sure the Log tab is visible before executing the algorithm try: self.tabWidget.setCurrentIndex(1) self.repaint() except: pass QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) self.setInfo( self.tr('<b>Algorithm %s starting...</b>') % self.alg.name) if self.iterateParam: if runalgIterating(self.alg, self.iterateParam, self): self.finish() else: QApplication.restoreOverrideCursor() self.resetGUI() else: command = self.alg.getAsCommand() if command: ProcessingLog.addToLog( ProcessingLog.LOG_ALGORITHM, command) if runalg(self.alg, self): self.finish() else: QApplication.restoreOverrideCursor() self.resetGUI() except AlgorithmDialogBase.InvalidParameterValue as e: try: self.buttonBox.accepted.connect(lambda: e.widget.setPalette(QPalette())) palette = e.widget.palette() palette.setColor(QPalette.Base, QColor(255, 255, 0)) e.widget.setPalette(palette) self.lblProgress.setText( self.tr('<b>Missing parameter value: %s</b>') % e.parameter.description) return except: QMessageBox.critical(self, self.tr('Unable to execute algorithm'), self.tr('Wrong or missing parameter values'))
def processAlgorithm(self, progress): # get variables from dialog layer = dataobjects.getObjectFromUri(self.getParameterValue( self.INPUT)) SELECTED_ONLY = self.getParameterValue(self.SELECTED_ONLY) kneighbors = int(self.getParameterValue(self.KNEIGHBORS)) use_field = self.getParameterValue(self.METHOD) == 1 field_name = self.getParameterValue(self.FIELD) # temporarily alter the processing environment old_setting = ProcessingConfig.getSetting( ProcessingConfig.USE_SELECTED) ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, SELECTED_ONLY) # get properties of the field the grouping is based on if use_field: field = QgsField(field_name) field.setType(QVariant.String) field.setLength(255) index = layer.fieldNameIndex(field_name) field_type = layer.pendingFields()[index].type() if field_type == QVariant.Int: field.setType(QVariant.Int) field.setLength(20) elif field_type == QVariant.Double: field.setType(QVariant.Double) field.setLength(20) field.setPrecision(6) else: field.setType(QVariant.String) field.setLength(255) fields = [ QgsField('id', QVariant.Int, '', 20), QgsField('count', QVariant.Int, '', 20), field ] else: # setup the fields of the output layer fields = [ QgsField('id', QVariant.Int, '', 20), QgsField('count', QVariant.Int, '', 20) ] # initialize writer writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( fields, QGis.WKBPolygon, layer.crs()) current = 0 fid = 0 if use_field: # get unique values of field denoted by index as filter conditions unique_values = layer.uniqueValues(index) total = 100.0 / float(layer.featureCount() * len(unique_values)) for unique in unique_values: points = [] first = True features = vector.features(layer) for in_feature in features: value = in_feature[field_name] if value == unique: if first: val = unique first = False points.extend( vector.extractPoints( QgsGeometry(in_feature.geometry()))) current += 1 progress.setPercentage(int(current * total)) # A minimum of 3 points is necessary to proceed if len(points) >= 3: out_feature = QgsFeature() try: the_hull = concave_hull(points, kneighbors) if the_hull: vertex = [ QgsPoint(point[0], point[1]) for point in the_hull ] poly = QgsGeometry.fromPolygon([vertex]) out_feature.setGeometry(poly) out_feature.setAttributes([fid, len(points), val]) writer.addFeature(out_feature) except: ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, 'Exception while computing concave hull.') raise GeoAlgorithmExecutionException( 'Exception while computing concave hull.') finally: ProcessingConfig.setSettingValue( ProcessingConfig.USE_SELECTED, old_setting) fid += 1 else: points = [] features = vector.features(layer) total = 100.0 / float(len(features)) for in_feature in features: points.extend( vector.extractPoints(QgsGeometry(in_feature.geometry()))) current += 1 progress.setPercentage(int(current * total)) out_feature = QgsFeature() try: the_hull = concave_hull(points, kneighbors) if the_hull: vertex = [ QgsPoint(point[0], point[1]) for point in the_hull ] poly = QgsGeometry.fromPolygon([vertex]) out_feature.setGeometry(poly) out_feature.setAttributes([0, len(points)]) writer.addFeature(out_feature) except: ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, 'Exception while computing concave hull.') raise GeoAlgorithmExecutionException( 'Exception while computing concave hull.') finally: ProcessingConfig.setSettingValue(ProcessingConfig.USE_SELECTED, old_setting) del writer
def runAlgorithm(algOrName, onFinish, *args, **kwargs): if isinstance(algOrName, GeoAlgorithm): alg = algOrName else: alg = QgsApplication.processingRegistry().algorithmById(algOrName) if alg is None: # fix_print_with_import print('Error: Algorithm not found\n') QgsMessageLog.logMessage( Processing.tr('Error: Algorithm {0} not found\n').format( algOrName), Processing.tr("Processing")) return alg = alg.getCopy() if len(args) == 1 and isinstance(args[0], dict): # Set params by name and try to run the alg even if not all parameter values are provided, # by using the default values instead. setParams = [] for (name, value) in list(args[0].items()): param = alg.getParameterFromName(name) if param and param.setValue(value): setParams.append(name) continue output = alg.getOutputFromName(name) if output and output.setValue(value): continue # fix_print_with_import print('Error: Wrong parameter value %s for parameter %s.' % (value, name)) QgsMessageLog.logMessage( Processing.tr( 'Error: Wrong parameter value {0} for parameter {1}.'). format(value, name), Processing.tr("Processing")) ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, Processing. tr('Error in {0}. Wrong parameter value {1} for parameter {2}.' ).format(alg.name(), value, name)) return # fill any missing parameters with default values if allowed for param in alg.parameters: if param.name not in setParams: if not param.setDefaultValue(): # fix_print_with_import print( 'Error: Missing parameter value for parameter %s.' % param.name) QgsMessageLog.logMessage( Processing. tr('Error: Missing parameter value for parameter {0}.' ).format(param.name), Processing.tr("Processing")) ProcessingLog.addToLog( ProcessingLog.LOG_ERROR, Processing. tr('Error in {0}. Missing parameter value for parameter {1}.' ).format(alg.name(), param.name)) return else: if len(args) != alg.getVisibleParametersCount( ) + alg.getVisibleOutputsCount(): # fix_print_with_import print('Error: Wrong number of parameters') QgsMessageLog.logMessage( Processing.tr('Error: Wrong number of parameters'), Processing.tr("Processing")) processing.algorithmHelp(algOrName) return i = 0 for param in alg.parameters: if not param.hidden: if not param.setValue(args[i]): # fix_print_with_import print('Error: Wrong parameter value: ' + str(args[i])) QgsMessageLog.logMessage( Processing.tr('Error: Wrong parameter value: ') + str(args[i]), Processing.tr("Processing")) return i = i + 1 for output in alg.outputs: if not output.hidden: if not output.setValue(args[i]): # fix_print_with_import print('Error: Wrong output value: ' + str(args[i])) QgsMessageLog.logMessage( Processing.tr('Error: Wrong output value: ') + str(args[i]), Processing.tr("Processing")) return i = i + 1 msg = alg._checkParameterValuesBeforeExecuting() if msg: # fix_print_with_import print('Unable to execute algorithm\n' + str(msg)) QgsMessageLog.logMessage( Processing.tr('Unable to execute algorithm\n{0}').format(msg), Processing.tr("Processing")) return if not alg.checkInputCRS(): print('Warning: Not all input layers use the same CRS.\n' + 'This can cause unexpected results.') QgsMessageLog.logMessage( Processing. tr('Warning: Not all input layers use the same CRS.\nThis can cause unexpected results.' ), Processing.tr("Processing")) # Don't set the wait cursor twice, because then when you # restore it, it will still be a wait cursor. overrideCursor = False if iface is not None: cursor = QApplication.overrideCursor() if cursor is None or cursor == 0: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) overrideCursor = True elif cursor.shape() != Qt.WaitCursor: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) overrideCursor = True feedback = None if kwargs is not None and "feedback" in list(kwargs.keys()): feedback = kwargs["feedback"] elif iface is not None: feedback = MessageBarProgress(alg.displayName()) ret = execute(alg, feedback) if ret: if onFinish is not None: onFinish(alg, feedback) else: QgsMessageLog.logMessage( Processing.tr("There were errors executing the algorithm."), Processing.tr("Processing")) if overrideCursor: QApplication.restoreOverrideCursor() if isinstance(feedback, MessageBarProgress): feedback.close() return alg
def accept(self): checkCRS = ProcessingConfig.getSetting( ProcessingConfig.WARN_UNMATCHING_CRS) try: self.setParamValues() if checkCRS and not self.alg.checkInputCRS(): reply = QMessageBox.question(self, "Unmatching CRS's", 'Layers do not all use the same CRS.\n' + 'This can cause unexpected results.\n' + 'Do you want to continue?', QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.No: return msg = self.alg.checkParameterValuesBeforeExecuting() if msg: QMessageBox.warning(self, 'Unable to execute algorithm', msg) return self.runButton.setEnabled(False) self.buttonBox.button( QtGui.QDialogButtonBox.Close).setEnabled(False) buttons = self.paramTable.iterateButtons self.iterateParam = None for i in range(len(buttons.values())): button = buttons.values()[i] if button.isChecked(): self.iterateParam = buttons.keys()[i] break self.tabWidget.setCurrentIndex(1) # Log tab self.progress.setMaximum(0) self.progressLabel.setText('Processing algorithm...') QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) self.setInfo('<b>Algorithm %s starting...</b>' % self.alg.name) # make sure the log tab is visible before executing the algorithm try: self.repaint() except: pass if self.iterateParam: if runalgIterating(self.alg, self.iterateParam, self): self.finish() else: QApplication.restoreOverrideCursor() self.resetGUI() else: command = self.alg.getAsCommand() if command: ProcessingLog.addToLog(ProcessingLog.LOG_ALGORITHM, command) if runalg(self.alg, self): self.finish() else: QApplication.restoreOverrideCursor() self.resetGUI() except AlgorithmExecutionDialog.InvalidParameterValue, ex: try: self.buttonBox.accepted.connect(lambda : ex.widget.setPalette(QPalette())) palette = ex.widget.palette() palette.setColor(QPalette.Base, QColor(255, 255, 0)) ex.widget.setPalette(palette) self.progressLabel.setText('<b>Missing parameter value: ' + ex.parameter.description + '</b>') return except: QMessageBox.critical(self, 'Unable to execute algorithm', 'Wrong or missing parameter values')
def ovals(self, writer, features, width, height, rotation, segments): ft = QgsFeature() if rotation is not None: for current, feat in enumerate(features): w = feat[width] h = feat[height] angle = feat[rotation] if not w or not h or not angle: ProcessingLog.addToLog( ProcessingLog.LOG_WARNING, self.tr('Feature {} has empty ' 'width, height or angle. ' 'Skipping...'.format(feat.id()))) continue xOffset = w / 2.0 yOffset = h / 2.0 phi = angle * math.pi / 180 point = feat.geometry().asPoint() x = point.x() y = point.y() points = [] for t in [(2 * math.pi) / segments * i for i in range(segments)]: points.append( (xOffset * math.cos(t), yOffset * math.sin(t))) polygon = [[ QgsPoint(i[0] * math.cos(phi) + i[1] * math.sin(phi) + x, -i[0] * math.sin(phi) + i[1] * math.cos(phi) + y) for i in points ]] ft.setGeometry(QgsGeometry.fromPolygon(polygon)) ft.setAttributes(feat.attributes()) writer.addFeature(ft) else: for current, feat in enumerate(features): w = feat[width] h = feat[height] if not w or not h: ProcessingLog.addToLog( ProcessingLog.LOG_WARNING, self.tr('Feature {} has empty ' 'width or height. ' 'Skipping...'.format(feat.id()))) continue xOffset = w / 2.0 yOffset = h / 2.0 point = feat.geometry().asPoint() x = point.x() y = point.y() points = [] for t in [(2 * math.pi) / segments * i for i in range(segments)]: points.append( (xOffset * math.cos(t), yOffset * math.sin(t))) polygon = [[QgsPoint(i[0] + x, i[1] + y) for i in points]] ft.setGeometry(QgsGeometry.fromPolygon(polygon)) ft.setAttributes(feat.attributes()) writer.addFeature(ft)
def processAlgorithm(self, progress): if system.isWindows(): path = GrassUtils.grassPath() if path == '': raise GeoAlgorithmExecutionException( self.tr('GRASS folder is not configured.\nPlease ' 'configure it before running GRASS algorithms.')) commands = [] self.exportedLayers = {} outputCommands = [] # If GRASS session has been created outside of this algorithm then # get the list of layers loaded in GRASS otherwise start a new # session existingSession = GrassUtils.sessionRunning if existingSession: self.exportedLayers = GrassUtils.getSessionLayers() else: GrassUtils.startGrassSession() # 1: Export layer to grass mapset for param in self.parameters: if isinstance(param, ParameterRaster): if param.value is None: continue value = param.value # Check if the layer hasn't already been exported in, for # example, previous GRASS calls in this session if value in self.exportedLayers.keys(): continue else: self.setSessionProjectionFromLayer(value, commands) commands.append(self.exportRasterLayer(value)) if isinstance(param, ParameterVector): if param.value is None: continue value = param.value if value in self.exportedLayers.keys(): continue else: self.setSessionProjectionFromLayer(value, commands) commands.append(self.exportVectorLayer(value)) if isinstance(param, ParameterTable): pass if isinstance(param, ParameterMultipleInput): if param.value is None: continue layers = param.value.split(';') if layers is None or len(layers) == 0: continue if param.datatype == ParameterMultipleInput.TYPE_RASTER: for layer in layers: if layer in self.exportedLayers.keys(): continue else: self.setSessionProjectionFromLayer(layer, commands) commands.append(self.exportRasterLayer(layer)) elif param.datatype == ParameterMultipleInput.TYPE_VECTOR_ANY: for layer in layers: if layer in self.exportedLayers.keys(): continue else: self.setSessionProjectionFromLayer(layer, commands) commands.append(self.exportVectorLayer(layer)) self.setSessionProjectionFromProject(commands) region = \ unicode(self.getParameterValue(self.GRASS_REGION_EXTENT_PARAMETER)) regionCoords = region.split(',') command = 'g.region' command += ' n=' + unicode(regionCoords[3]) command += ' s=' + unicode(regionCoords[2]) command += ' e=' + unicode(regionCoords[1]) command += ' w=' + unicode(regionCoords[0]) cellsize = self.getParameterValue(self.GRASS_REGION_CELLSIZE_PARAMETER) if cellsize: command += ' res=' + unicode(cellsize) else: command += ' res=' + unicode(self.getDefaultCellsize()) alignToResolution = \ self.getParameterValue(self.GRASS_REGION_ALIGN_TO_RESOLUTION) if alignToResolution: command += ' -a' commands.append(command) # 2: Set parameters and outputs command = self.grassName command += ' ' + ' '.join(self.hardcodedStrings) for param in self.parameters: if param.value is None or param.value == '': continue if param.name in [ self.GRASS_REGION_CELLSIZE_PARAMETER, self.GRASS_REGION_EXTENT_PARAMETER, self.GRASS_MIN_AREA_PARAMETER, self.GRASS_SNAP_TOLERANCE_PARAMETER, self.GRASS_OUTPUT_TYPE_PARAMETER, self.GRASS_REGION_ALIGN_TO_RESOLUTION ]: continue if isinstance(param, (ParameterRaster, ParameterVector)): value = param.value if value in self.exportedLayers.keys(): command += ' %s="%s"' % (param.name, self.exportedLayers[value]) else: command += ' %s="%s"' % (param.name, value) elif isinstance(param, ParameterMultipleInput): s = param.value for layer in self.exportedLayers.keys(): s = s.replace(layer, self.exportedLayers[layer]) s = s.replace(';', ',') command += ' %s="%s"' % (param.name, s) elif isinstance(param, ParameterBoolean): if param.value: command += ' ' + param.name elif isinstance(param, ParameterSelection): idx = int(param.value) command += ' ' + param.name + '=' + unicode(param.options[idx]) elif isinstance(param, ParameterString): command += ' ' + param.name + '="' + unicode(param.value) + '"' else: command += ' ' + param.name + '="' + unicode(param.value) + '"' uniqueSufix = unicode(uuid.uuid4()).replace('-', '') for out in self.outputs: if isinstance(out, OutputFile): command += ' > ' + out.value elif not isinstance(out, OutputHTML): # We add an output name to make sure it is unique if the session # uses this algorithm several times. uniqueOutputName = out.name + uniqueSufix command += ' ' + out.name + '=' + uniqueOutputName # Add output file to exported layers, to indicate that # they are present in GRASS self.exportedLayers[out.value] = uniqueOutputName command += ' --overwrite' commands.append(command) # 3: Export resulting layers to a format that qgis can read for out in self.outputs: if isinstance(out, OutputRaster): filename = out.getCompatibleFileName(self) # Raster layer output: adjust region to layer before # exporting commands.append('g.region rast=' + out.name + uniqueSufix) outputCommands.append('g.region rast=' + out.name + uniqueSufix) if self.grassName == 'r.composite': command = 'r.out.tiff -t --verbose' command += ' input=' command += out.name + uniqueSufix command += ' output="' + filename + '"' commands.append(command) outputCommands.append(command) else: command = 'r.out.gdal -c createopt="TFW=YES,COMPRESS=LZW"' command += ' input=' if self.grassName == 'r.horizon': command += out.name + uniqueSufix + '_0' else: command += out.name + uniqueSufix command += ' output="' + filename + '"' commands.append(command) outputCommands.append(command) if isinstance(out, OutputVector): filename = out.getCompatibleFileName(self) command = 'v.out.ogr -s -c -e -z input=' + out.name + uniqueSufix command += ' dsn="' + os.path.dirname(filename) + '"' command += ' format=ESRI_Shapefile' command += ' olayer="%s"' % os.path.splitext( os.path.basename(filename))[0] typeidx = \ self.getParameterValue(self.GRASS_OUTPUT_TYPE_PARAMETER) outtype = ('auto' if typeidx is None else self.OUTPUT_TYPES[typeidx]) command += ' type=' + outtype commands.append(command) outputCommands.append(command) # 4: Run GRASS loglines = [] loglines.append(self.tr('GRASS execution commands')) for line in commands: progress.setCommand(line) loglines.append(line) if ProcessingConfig.getSetting(GrassUtils.GRASS_LOG_COMMANDS): ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines) GrassUtils.executeGrass(commands, progress, outputCommands) for out in self.outputs: if isinstance(out, OutputHTML): with open(self.getOutputFromName("rawoutput").value) as f: rawOutput = "".join(f.readlines()) with open(out.value, "w") as f: f.write("<pre>%s</pre>" % rawOutput) # If the session has been created outside of this algorithm, add # the new GRASS layers to it otherwise finish the session if existingSession: GrassUtils.addSessionLayers(self.exportedLayers) else: GrassUtils.endGrassSession()
Return true if everything went OK, false if the algorithm could not be completed. """ if progress is None: progress = SilentProgress() try: alg.execute(progress) return True except GeoAlgorithmExecutionException, e: ProcessingLog.addToLog(sys.exc_info()[0], ProcessingLog.LOG_ERROR) progress.error(e.msg) return False except Exception: msg = 'Uncaught error executing ' + str( alg.name) + '\nSee log for more information' ProcessingLog.addToLog(sys.exc_info()[0], ProcessingLog.LOG_ERROR) progress.error(msg) return False def runalgIterating(alg, paramToIter, progress): # Generate all single-feature layers settings = QSettings() systemEncoding = settings.value('/UI/encoding', 'System') layerfile = alg.getParameterValue(paramToIter) layer = dataobjects.getObjectFromUri(layerfile, False) feat = QgsFeature() filelist = [] outputs = {} provider = layer.dataProvider() features = vector.features(layer)