Exemple #1
1
    def execute(self, feedback=None, 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.
        """

        if feedback is None:
            feedback = QgsProcessingFeedback()

        self.model = model
        try:
            self.setOutputCRS()
            self.resolveOutputs()
            self.evaluateParameterValues()
            self.runPreExecutionScript(feedback)
            self.processAlgorithm(feedback)
            feedback.setProgress(100)
            self.convertUnsupportedFormats(feedback)
            self.runPostExecutionScript(feedback)
        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)
Exemple #2
0
def executeAlgorithm(alg, parameters, context=None, feedback=None, 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 QgsProcessingException in case anything goes
    wrong.
    :param parameters:
    """

    if feedback is None:
        feedback = QgsProcessingFeedback()
    if context is None:
        context = dataobjects.createContext(feedback)

    #self.model = model

    #self.setOutputCRS()
    #self.resolveOutputs()
    #self.evaluateParameterValues()
    #self.runPreExecutionScript(feedback)
    result, ok = alg.run(parameters, context, feedback)
    #self.processAlgorithm(parameters, context, feedback)
    feedback.setProgress(100)
    return result, ok
Exemple #3
0
def handleAlgorithmResults(alg, context, feedback=None, showResults=True):
    wrongLayers = []
    if feedback is None:
        feedback = QgsProcessingFeedback()
    feedback.setProgressText(QCoreApplication.translate('Postprocessing', 'Loading resulting layers'))
    i = 0

    for l, details in context.layersToLoadOnCompletion().items():
        if feedback.isCanceled():
            return False

        if len(context.layersToLoadOnCompletion()) > 2:
            # only show progress feedback if we're loading a bunch of layers
            feedback.setProgress(100 * i / float(len(context.layersToLoadOnCompletion())))

        try:
            layer = QgsProcessingUtils.mapLayerFromString(l, context, typeHint=details.layerTypeHint)
            if layer is not None:
                set_layer_name(layer, details)

                style = None
                if details.outputName:
                    style = RenderingStyles.getStyle(alg.id(), details.outputName)
                if style is None:
                    if layer.type() == QgsMapLayer.RasterLayer:
                        style = ProcessingConfig.getSetting(ProcessingConfig.RASTER_STYLE)
                    else:
                        if layer.geometryType() == QgsWkbTypes.PointGeometry:
                            style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_POINT_STYLE)
                        elif layer.geometryType() == QgsWkbTypes.LineGeometry:
                            style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_LINE_STYLE)
                        else:
                            style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_POLYGON_STYLE)
                if style:
                    layer.loadNamedStyle(style)

                details.project.addMapLayer(context.temporaryLayerStore().takeMapLayer(layer))

                if details.postProcessor():
                    details.postProcessor().postProcessLayer(layer, context, feedback)

            else:
                wrongLayers.append(str(l))
        except Exception:
            QgsMessageLog.logMessage(QCoreApplication.translate('Postprocessing', "Error loading result layer:") + "\n" + traceback.format_exc(), 'Processing', Qgis.Critical)
            wrongLayers.append(str(l))
        i += 1

    feedback.setProgress(100)

    if wrongLayers:
        msg = QCoreApplication.translate('Postprocessing', "The following layers were not correctly generated.")
        msg += "<ul>" + "".join(["<li>%s</li>" % lay for lay in wrongLayers]) + "</ul>"
        msg += QCoreApplication.translate('Postprocessing', "You can check the 'Log Messages Panel' in QGIS main window to find more information about the execution of the algorithm.")
        feedback.reportError(msg)

    return len(wrongLayers) == 0
    def __init__(self, algname=None):
        QgsProcessingFeedback.__init__(self)

        self.msg = []
        self.progressMessageBar = \
            iface.messageBar().createMessage(self.tr('Executing algorithm <i>{0}</i>'.format(algname if algname else '')))
        self.progress = QProgressBar()
        self.progressChanged.connect(self.progress.setValue)
        self.progress.setMaximum(100)
        self.progress.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        self.progressMessageBar.layout().addWidget(self.progress)
        self.message_bar_item = iface.messageBar().pushWidget(self.progressMessageBar,
                                                              Qgis.Info)
Exemple #5
0
    def runGdal(commands, feedback=None):
        if feedback is None:
            feedback = QgsProcessingFeedback()
        envval = os.getenv('PATH')
        # We need to give some extra hints to get things picked up on OS X
        isDarwin = False
        try:
            isDarwin = platform.system() == 'Darwin'
        except IOError:  # https://travis-ci.org/m-kuhn/QGIS#L1493-L1526
            pass
        if isDarwin and os.path.isfile(os.path.join(QgsApplication.prefixPath(), "bin", "gdalinfo")):
            # Looks like there's a bundled gdal. Let's use it.
            os.environ['PATH'] = "{}{}{}".format(os.path.join(QgsApplication.prefixPath(), "bin"), os.pathsep, envval)
            os.environ['DYLD_LIBRARY_PATH'] = os.path.join(QgsApplication.prefixPath(), "lib")
        else:
            # Other platforms should use default gdal finder codepath
            settings = QgsSettings()
            path = settings.value('/GdalTools/gdalPath', '')
            if not path.lower() in envval.lower().split(os.pathsep):
                envval += '{}{}'.format(os.pathsep, path)
                os.putenv('PATH', envval)

        fused_command = ' '.join([str(c) for c in commands])
        QgsMessageLog.logMessage(fused_command, 'Processing', Qgis.Info)
        feedback.pushInfo('GDAL command:')
        feedback.pushCommandInfo(fused_command)
        feedback.pushInfo('GDAL command output:')
        success = False
        retry_count = 0
        while not success:
            loglines = []
            loglines.append('GDAL execution console output')
            try:
                with subprocess.Popen(
                    fused_command,
                    shell=True,
                    stdout=subprocess.PIPE,
                    stdin=subprocess.DEVNULL,
                    stderr=subprocess.STDOUT,
                    universal_newlines=True,
                ) as proc:
                    for line in proc.stdout:
                        feedback.pushConsoleInfo(line)
                        loglines.append(line)
                    success = True
            except IOError as e:
                if retry_count < 5:
                    retry_count += 1
                else:
                    raise IOError(
                        str(e) + u'\nTried 5 times without success. Last iteration stopped after reading {} line(s).\nLast line(s):\n{}'.format(
                            len(loglines), u'\n'.join(loglines[-10:])))

            QgsMessageLog.logMessage('\n'.join(loglines), 'Processing', Qgis.Info)
            GdalUtils.consoleOutput = loglines
Exemple #6
0
def executeAlgorithm(alg, parameters, context=None, feedback=None, 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.
    :param parameters:
    """

    if feedback is None:
        feedback = QgsProcessingFeedback()
    if context is None:
        context = dataobjects.createContext()

    #self.model = model
    try:
        #self.setOutputCRS()
        #self.resolveOutputs()
        #self.evaluateParameterValues()
        #self.runPreExecutionScript(feedback)
        result = alg.run(parameters, context, feedback)
        #self.processAlgorithm(parameters, context, feedback)
        feedback.setProgress(100)
        return result
        #self.convertUnsupportedFormats(context, feedback)
        #self.runPostExecutionScript(feedback)
    except GeoAlgorithmExecutionException as gaee:
        lines = [self.tr('Error while executing algorithm')]
        lines = []
        lines.append(traceback.format_exc())
        feedback.reportError(gaee.msg)
        QgsMessageLog.logMessage(gaee.msg, self.tr('Processing'), QgsMessageLog.CRITICAL)
        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 = []
      #  lines.append(traceback.format_exc())
        #QgsMessageLog.logMessage('\n'.join(lines), self.tr('Processing'), QgsMessageLog.CRITICAL)
        #raise GeoAlgorithmExecutionException(str(e) + self.tr('\nSee log for more details'), lines, e)

    def helpUrl(self):
        return QgsHelp.helpUrl("processing_algs/{}/{}".format(
            self.provider().id(), self.id())).toString()
Exemple #7
0
def runalg(alg, feedback=None):
    """Executes a given algorithm, showing its progress in the
    progress object passed along.

    Return true if everything went OK, false if the algorithm
    could not be completed.
    """

    if feedback is None:
        feedback = QgsProcessingFeedback()

    try:
        alg.execute(feedback)
        return True
    except GeoAlgorithmExecutionException as e:
        ProcessingLog.addToLog(sys.exc_info()[0], ProcessingLog.LOG_ERROR)
        if feedback is not None:
            feedback.reportError(e.msg)
        return False
def execute(alg, parameters, context=None, feedback=None):
    """Executes a given algorithm, showing its progress in the
    progress object passed along.

    Return true if everything went OK, false if the algorithm
    could not be completed.
    """

    if feedback is None:
        feedback = QgsProcessingFeedback()
    if context is None:
        context = dataobjects.createContext(feedback)

    try:
        results, ok = alg.run(parameters, context, feedback)
        return ok, results
    except QgsProcessingException as e:
        QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.Critical)
        if feedback is not None:
            feedback.reportError(e.msg)
        return False, {}
Exemple #9
0
    def execute(self, parameters, context=None, feedback=None, 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 QgsProcessingException in case anything goes
        wrong.
        :param parameters:
        """

        if feedback is None:
            feedback = QgsProcessingFeedback()
        if context is None:
            context = dataobjects.createContext(feedback)

        self.model = model
        try:
            self.setOutputCRS()
            self.resolveOutputs()
            self.runPreExecutionScript(feedback)
            self.processAlgorithm(parameters, context, feedback)
            feedback.setProgress(100)
            self.convertUnsupportedFormats(context, feedback)
            self.runPostExecutionScript(feedback)
        except QgsProcessingException as gaee:
            lines = [self.tr('Error while executing algorithm')]
            lines.append(traceback.format_exc())
            QgsMessageLog.logMessage(gaee.msg, self.tr('Processing'), QgsMessageLog.CRITICAL)
            raise QgsProcessingException(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())
            QgsMessageLog.logMessage('\n'.join(lines), self.tr('Processing'), QgsMessageLog.CRITICAL)
            raise QgsProcessingException(str(e) + self.tr('\nSee log for more details'), lines, e)
def execute(commands, feedback=None):
    cmds = []
    cmds.append(os.path.join(mpichDirectory(), "mpiexec"))

    processes = ProcessingConfig.getSetting(TAUDEM_PROCESSES)
    if int(processes) <= 0:
      processes = 1

    cmds.append("-n")
    cmds.append(processes)
    cmds.extend(commands)

    if feedback is None:
        feedback = QgsProcessingFeedback()

    fused_command = " ".join([str(c) for c in cmds])
    QgsMessageLog.logMessage(fused_command, "Processing", QgsMessageLog.INFO)
    feedback.pushInfo("TauDEM command:")
    feedback.pushCommandInfo(fused_command)
    feedback.pushInfo("TauDEM command output:")

    loglines = []
    with subprocess.Popen(fused_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, ""):
                feedback.pushConsoleInfo(line)
                loglines.append(line)
        except:
            pass

    if ProcessingConfig.getSetting(TAUDEM_VERBOSE):
        QgsMessageLog.logMessage("\n".join(loglines), "Processing", QgsMessageLog.INFO)
Exemple #11
0
def handleAlgorithmResults(alg, feedback=None, showResults=True):
    wrongLayers = []
    htmlResults = False
    if feedback is None:
        feedback = QgsProcessingFeedback()
    feedback.setProgressText(QCoreApplication.translate('Postprocessing', 'Loading resulting layers'))
    i = 0
    for out in alg.outputs:
        feedback.setProgress(100 * i / float(len(alg.outputs)))
        if out.hidden or not out.open:
            continue
        if isinstance(out, (OutputRaster, OutputVector, OutputTable)):
            try:
                if hasattr(out, "layer") and out.layer is not None:
                    out.layer.setName(out.description)
                    QgsProject.instance().addMapLayers([out.layer])
                else:
                    if ProcessingConfig.getSetting(
                            ProcessingConfig.USE_FILENAME_AS_LAYER_NAME):
                        name = os.path.basename(out.value)
                    else:
                        name = out.description
                    dataobjects.load(out.value, name, alg.crs,
                                     RenderingStyles.getStyle(alg.commandLineName(),
                                                              out.name))
            except Exception:
                ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                       "Error loading result layer:\n" + traceback.format_exc())
                wrongLayers.append(out.description)
        elif isinstance(out, OutputHTML):
            ProcessingResults.addResult(out.description, out.value)
            htmlResults = True
        i += 1

    QApplication.restoreOverrideCursor()
    if wrongLayers:
        msg = "The following layers were not correctly generated.<ul>"
        msg += "".join(["<li>%s</li>" % lay for lay in wrongLayers]) + "</ul>"
        msg += "You can check the log messages to find more information about the execution of the algorithm"
        feedback.reportError(msg)

    if showResults and htmlResults and not wrongLayers:
        dlg = ResultsDialog()
        dlg.exec_()

    return len(wrongLayers) == 0
Exemple #12
0
 def refreshFeedback():
     # refresh feedback track to not carry "bias" to next execution
     workflow.feedback.progressChanged.disconnect(self.setProgress)
     del workflow.feedback
     workflow.feedback = QgsProcessingFeedback()
     workflow.feedback.progressChanged.connect(self.setProgress)
Exemple #13
0
def handleAlgorithmResults(alg, context, feedback=None, showResults=True, parameters={}):
    wrongLayers = []
    if feedback is None:
        feedback = QgsProcessingFeedback()
    feedback.setProgressText(QCoreApplication.translate('Postprocessing', 'Loading resulting layers'))
    i = 0

    for l, details in context.layersToLoadOnCompletion().items():
        if feedback.isCanceled():
            return False

        if len(context.layersToLoadOnCompletion()) > 2:
            # only show progress feedback if we're loading a bunch of layers
            feedback.setProgress(100 * i / float(len(context.layersToLoadOnCompletion())))
        try:
            layer = QgsProcessingUtils.mapLayerFromString(l, context, typeHint=details.layerTypeHint)
            if layer is not None:
                set_layer_name(layer, details)

                '''If running a model, the execution will arrive here when an algorithm that is part of
                that model is executed. We check if its output is a final otuput of the model, and
                adapt the output name accordingly'''
                outputName = details.outputName
                expcontext = QgsExpressionContext()
                scope = QgsExpressionContextScope()
                expcontext.appendScope(scope)
                for out in alg.outputDefinitions():
                    outValue = parameters[out.name()]
                    if hasattr(outValue, "sink"):
                        outValue = outValue.sink.valueAsString(expcontext)[0]
                    else:
                        outValue = str(outValue)
                    if outValue == l:
                        outputName = out.name()
                        break
                style = None
                if outputName:
                    style = RenderingStyles.getStyle(alg.id(), outputName)
                if style is None:
                    if layer.type() == QgsMapLayer.RasterLayer:
                        style = ProcessingConfig.getSetting(ProcessingConfig.RASTER_STYLE)
                    else:
                        if layer.geometryType() == QgsWkbTypes.PointGeometry:
                            style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_POINT_STYLE)
                        elif layer.geometryType() == QgsWkbTypes.LineGeometry:
                            style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_LINE_STYLE)
                        else:
                            style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_POLYGON_STYLE)
                if style:
                    layer.loadNamedStyle(style)

                details.project.addMapLayer(context.temporaryLayerStore().takeMapLayer(layer))

                if details.postProcessor():
                    details.postProcessor().postProcessLayer(layer, context, feedback)

            else:
                wrongLayers.append(str(l))
        except Exception:
            QgsMessageLog.logMessage(QCoreApplication.translate('Postprocessing', "Error loading result layer:") + "\n" + traceback.format_exc(), 'Processing', Qgis.Critical)
            wrongLayers.append(str(l))
        i += 1

    feedback.setProgress(100)

    if wrongLayers:
        msg = QCoreApplication.translate('Postprocessing', "The following layers were not correctly generated.")
        msg += "<ul>" + "".join(["<li>%s</li>" % lay for lay in wrongLayers]) + "</ul>"
        msg += QCoreApplication.translate('Postprocessing', "You can check the 'Log Messages Panel' in QGIS main window to find more information about the execution of the algorithm.")
        feedback.reportError(msg)

    return len(wrongLayers) == 0
Exemple #14
0
def handleAlgorithmResults(alg, context, feedback=None, showResults=True):
    wrongLayers = []
    if feedback is None:
        feedback = QgsProcessingFeedback()
    feedback.setProgressText(QCoreApplication.translate('Postprocessing', 'Loading resulting layers'))
    i = 0
    for l, details in context.layersToLoadOnCompletion().items():
        if feedback.isCanceled():
            return False

        if len(context.layersToLoadOnCompletion()) > 2:
            # only show progress feedback if we're loading a bunch of layers
            feedback.setProgress(100 * i / float(len(context.layersToLoadOnCompletion())))

        try:
            layer = QgsProcessingUtils.mapLayerFromString(l, context)
            if layer is not None:
                layer.setName(details.name)
                details.project.addMapLayer(context.temporaryLayerStore().takeMapLayer(layer))
            else:
                name = details.name
                if ProcessingConfig.getSetting(
                        ProcessingConfig.USE_FILENAME_AS_LAYER_NAME):
                    name = os.path.basename(l)
                dataobjects.load(l, name, alg.crs,
                                 RenderingStyles.getStyle(alg.id(), l))
        except Exception:
            QgsMessageLog.logMessage("Error loading result layer:\n" + traceback.format_exc(), 'Processing', QgsMessageLog.CRITICAL)
            #wrongLayers.append(out.description())
            wrongLayers.append(l)
    # for out in alg.outputs:
    #     feedback.setProgress(100 * i / float(len(alg.outputs)))
    #     if out.flags() & QgsProcessingParameterDefinition.FlagHidden or not out.open:
    #         continue
    #     if isinstance(out, (OutputRaster, OutputVector, OutputTable)):
    #         try:
    #             layer = QgsProcessingUtils.mapLayerFromString(out.value, context)
    #             if layer:
    #                 layer.setName(out.description)
    #                 QgsProject.instance().addMapLayer(context.temporaryLayerStore().takeMapLayer(layer))
    #             else:
    #                 if ProcessingConfig.getSetting(
    #                         ProcessingConfig.USE_FILENAME_AS_LAYER_NAME):
    #                     name = os.path.basename(out.value)
    #                 else:
    #                     name = out.description
    #
    #                 isRaster = True if isinstance(out, OutputRaster) else False
    #                 dataobjects.load(out.value, name, alg.crs,
    #                                  RenderingStyles.getStyle(alg.id(), out.name),
    #                                  isRaster)
    #         except Exception:
    #             QgsMessageLog.logMessage("Error loading result layer:\n" + traceback.format_exc(), 'Processing', QgsMessageLog.CRITICAL)
    #             wrongLayers.append(out.description)
    #     elif isinstance(out, OutputHTML):
    #         resultsList.addResult(alg.icon(), out.description, out.value)
        i += 1

    QApplication.restoreOverrideCursor()
    if wrongLayers:
        msg = "The following layers were not correctly generated.<ul>"
        msg += "".join(["<li>%s</li>" % lay for lay in wrongLayers]) + "</ul>"
        msg += "You can check the log messages to find more information about the execution of the algorithm"
        feedback.reportError(msg)

    return len(wrongLayers) == 0
Exemple #15
0
    def check_for_unsupported_property(name,  # pylint:disable=too-many-branches
                                       symbol,
                                       feedback: QgsProcessingFeedback,
                                       sink):
        """
        Checks for properties of ESRI symbols which have no equivalent in QGIS,
        and warns
        """
        for c in symbol.children():
            StyleToQgisXml.check_for_unsupported_property(name, c, feedback, sink)

        try:
            if symbol.random:
                feedback.reportError(
                    'Warning: random marker fills are not supported by QGIS (considering sponsoring this feature!)')
                if sink:
                    f = QgsFeature()
                    f.setAttributes([name, 'Random marker fills not supported by QGIS'])
                    sink.addFeature(f)
        except AttributeError:
            pass

        if isinstance(symbol, (MarkerFillSymbolLayer, PictureFillSymbolLayer)):
            if symbol.offset_x or symbol.offset_y:
                feedback.reportError(
                    'Warning: marker fill offset X or Y is not supported by QGIS (considering sponsoring this feature!)')

                if sink:
                    f = QgsFeature()
                    f.setAttributes([name, 'Marker fill offset X or Y not supported by QGIS'])
                    sink.addFeature(f)

        if isinstance(symbol, PictureFillSymbolLayer):
            if symbol.separation_x or symbol.separation_y:
                feedback.reportError(
                    'Warning: picture fill separation X or Y is not supported by QGIS (considering sponsoring this feature!)')

                if sink:
                    f = QgsFeature()
                    f.setAttributes([name, 'Picture fill separation X or Y not supported by QGIS'])
                    sink.addFeature(f)

        if isinstance(symbol, HashLineSymbolLayer):
            feedback.reportError(
                'QGIS does not have a hash line symbol type (considering sponsoring this feature!)')

            if sink:
                f = QgsFeature()
                f.setAttributes([name, 'Hash line symbols are not supported by QGIS'])
                sink.addFeature(f)

        try:
            if symbol.halo:
                feedback.reportError(
                    'Halos are not supported by QGIS (considering sponsoring this feature!)')
                if sink:
                    f = QgsFeature()
                    f.setAttributes([name, 'Marker halos not supported by QGIS'])
                    sink.addFeature(f)

        except AttributeError:
            pass
Exemple #16
0
    def runGdal(commands, feedback=None):
        if feedback is None:
            feedback = QgsProcessingFeedback()
        envval = os.getenv('PATH')
        # We need to give some extra hints to get things picked up on OS X
        isDarwin = False
        try:
            isDarwin = platform.system() == 'Darwin'
        except IOError:  # https://travis-ci.org/m-kuhn/QGIS#L1493-L1526
            pass
        if isDarwin and os.path.isfile(
                os.path.join(QgsApplication.prefixPath(), "bin", "gdalinfo")):
            # Looks like there's a bundled gdal. Let's use it.
            os.environ['PATH'] = "{}{}{}".format(
                os.path.join(QgsApplication.prefixPath(), "bin"), os.pathsep,
                envval)
            os.environ['DYLD_LIBRARY_PATH'] = os.path.join(
                QgsApplication.prefixPath(), "lib")
        else:
            # Other platforms should use default gdal finder codepath
            settings = QgsSettings()
            path = settings.value('/GdalTools/gdalPath', '')
            if not path.lower() in envval.lower().split(os.pathsep):
                envval += '{}{}'.format(os.pathsep, path)
                os.putenv('PATH', envval)

        fused_command = ' '.join([str(c) for c in commands])
        QgsMessageLog.logMessage(fused_command, 'Processing',
                                 QgsMessageLog.INFO)
        feedback.pushInfo('GDAL command:')
        feedback.pushCommandInfo(fused_command)
        feedback.pushInfo('GDAL command output:')
        success = False
        retry_count = 0
        while not success:
            loglines = []
            loglines.append('GDAL execution console output')
            try:
                with subprocess.Popen(
                        fused_command,
                        shell=True,
                        stdout=subprocess.PIPE,
                        stdin=subprocess.DEVNULL,
                        stderr=subprocess.STDOUT,
                        universal_newlines=True,
                ) as proc:
                    for line in proc.stdout:
                        feedback.pushConsoleInfo(line)
                        loglines.append(line)
                    success = True
            except IOError as e:
                if retry_count < 5:
                    retry_count += 1
                else:
                    raise IOError(
                        e.message +
                        u'\nTried 5 times without success. Last iteration stopped after reading {} line(s).\nLast line(s):\n{}'
                        .format(len(loglines), u'\n'.join(loglines[-10:])))

            QgsMessageLog.logMessage('\n'.join(loglines), 'Processing',
                                     QgsMessageLog.INFO)
            GdalUtils.consoleOutput = loglines
Exemple #17
0
    def processAlgorithm(self, parameters, context,
                         feedback: QgsProcessingFeedback):
        # Input / Output
        source = self.parameterAsSource(parameters, self.INPUT, context)
        (sink, dest_id) = self.create_output_sink(parameters, context,
                                                  source.sourceCrs())

        # Filter parameters
        observation_type_indices = self.parameterAsEnums(
            parameters, self.OBSERVATION_TYPE, context)
        observation_types = list(
            map(lambda i: self.OBSERVATION_TYPES[i][0],
                observation_type_indices))

        from_date = None
        from_date_string = self.parameterAsString(parameters, self.FROM_DATE,
                                                  context)
        if from_date_string:
            from_date = datetime.fromisoformat(from_date_string)

        to_date = None
        to_date_string = self.parameterAsString(parameters, self.TO_DATE,
                                                context)
        if to_date_string:
            to_date = datetime.fromisoformat(to_date_string)

        fire_connection_string = self.settings.value("fire_connection_string")
        fireDb = FireDb(fire_connection_string, debug=True)

        features = list(source.getFeatures())
        total_num_features = len(features)
        total_num_features_processed = 0
        # for current, feature in enumerate(features):
        for feature in features:
            if feedback.isCanceled():
                return {}
            wkt = feature.geometry().asWkt().upper()
            geometry = Geometry(wkt)
            observations = fireDb.hent_observationer_naer_geometri(
                geometri=geometry,
                afstand=0,
                tid_fra=from_date,
                tid_til=to_date)

            pid_list = self.get_pids_from_observations(observations)
            geometriobjekter = self.get_geometriobjekter_from_pids(
                fireDb, pid_list)
            idents = self.get_idents_from_pids(fireDb, pid_list)

            feedback.setProgressText(
                "Fandt {antal} observationer".format(antal=len(observations)))
            feedback.setProgressText("Fandt {antal} geometriobjekter".format(
                antal=len(geometriobjekter)))
            feedback.setProgressText(
                "Fandt {antal} idents".format(antal=len(idents)))
            for current, observation in enumerate(observations):
                observation_type_id = observation.observationstypeid
                if observation_type_id in observation_types:
                    feature = self.create_feature_from_observation(
                        observation, geometriobjekter, idents, feedback)
                    if feature:
                        sink.addFeature(feature, QgsFeatureSink.FastInsert)
            total_num_features_processed = total_num_features_processed + 1
            feedback.setProgress(total_num_features_processed /
                                 total_num_features)
            if feedback.isCanceled():
                return {}

        apply_theme = self.parameterAsBool(parameters, self.APPLY_THEME,
                                           context)
        if apply_theme:
            style_file = os.path.join(os.path.dirname(__file__), "..",
                                      "styles", "observation.qml")
            alg_params = {"INPUT": dest_id, "STYLE": style_file}
            processing.run(
                "qgis:setstyleforvectorlayer",
                alg_params,
                context=context,
                feedback=feedback,
                is_child_algorithm=True,
            )

        return {self.OUTPUT: dest_id}
Exemple #18
0
    def testReadOgr(self):
        """
        Test reading vector inputs
        """
        alg = RAlgorithm(
            description_file=os.path.join(test_data_path, 'test_vectorin.rsx'))
        alg.initAlgorithm()

        context = QgsProcessingContext()
        feedback = QgsProcessingFeedback()
        script = alg.build_import_commands(
            {'Layer': os.path.join(test_data_path, 'lines.shp')}, context,
            feedback)

        USE_NEW_API = Qgis.QGIS_VERSION_INT >= 30900 and hasattr(
            QgsProcessingAlgorithm,
            'parameterAsCompatibleSourceLayerPathAndLayerName')
        if USE_NEW_API:
            self.assertEqual(
                script[0], 'Layer <- readOGR("{}")'.format(
                    os.path.join(test_data_path, 'lines.shp')))
        else:
            self.assertEqual(
                script[0], 'Layer <- readOGR("{}")'.format(
                    os.path.join(test_data_path, 'lines.shp')))
        script = alg.build_import_commands(
            {
                'Layer':
                os.path.join(test_data_path, 'lines.shp').replace('/', '\\')
            }, context, feedback)
        if USE_NEW_API:
            self.assertEqual(
                script[0], 'Layer <- readOGR("{}")'.format(
                    os.path.join(test_data_path, 'lines.shp')))
        else:
            self.assertEqual(
                script[0], 'Layer <- readOGR("{}")'.format(
                    os.path.join(test_data_path, 'lines.shp')))
        vl = QgsVectorLayer(
            os.path.join(test_data_path, 'test_gpkg.gpkg') +
            '|layername=points')
        self.assertTrue(vl.isValid())
        vl2 = QgsVectorLayer(
            os.path.join(test_data_path, 'test_gpkg.gpkg') +
            '|layername=lines')
        self.assertTrue(vl2.isValid())
        script = alg.build_import_commands({
            'Layer': vl,
            'Layer2': vl2
        }, context, feedback)

        if USE_NEW_API:
            # use the newer api and avoid unnecessary layer translation
            self.assertEqual(script, [
                'Layer <- readOGR("{}", layer="points")'.format(
                    os.path.join(test_data_path, 'test_gpkg.gpkg')),
                'Layer2 <- readOGR("{}", layer="lines")'.format(
                    os.path.join(test_data_path, 'test_gpkg.gpkg'))
            ])
        else:
            # older version, forced to use inefficient api
            self.assertIn('Layer <- readOGR("/tmp', script[0])
            self.assertIn('Layer2 <- readOGR("/tmp', script[1])
Exemple #19
0
def handleAlgorithmResults(alg, context, feedback=None, showResults=True):
    wrongLayers = []
    if feedback is None:
        feedback = QgsProcessingFeedback()
    feedback.setProgressText(
        QCoreApplication.translate('Postprocessing',
                                   'Loading resulting layers'))
    i = 0
    for l, details in context.layersToLoadOnCompletion().items():
        if feedback.isCanceled():
            return False

        if len(context.layersToLoadOnCompletion()) > 2:
            # only show progress feedback if we're loading a bunch of layers
            feedback.setProgress(
                100 * i / float(len(context.layersToLoadOnCompletion())))

        try:
            layer = QgsProcessingUtils.mapLayerFromString(l, context)
            if layer is not None:
                if not ProcessingConfig.getSetting(
                        ProcessingConfig.USE_FILENAME_AS_LAYER_NAME):
                    layer.setName(details.name)

                style = None
                if details.outputName:
                    style = RenderingStyles.getStyle(alg.id(),
                                                     details.outputName)
                if style is None:
                    if layer.type() == QgsMapLayer.RasterLayer:
                        style = ProcessingConfig.getSetting(
                            ProcessingConfig.RASTER_STYLE)
                    else:
                        if layer.geometryType() == QgsWkbTypes.PointGeometry:
                            style = ProcessingConfig.getSetting(
                                ProcessingConfig.VECTOR_POINT_STYLE)
                        elif layer.geometryType() == QgsWkbTypes.LineGeometry:
                            style = ProcessingConfig.getSetting(
                                ProcessingConfig.VECTOR_LINE_STYLE)
                        else:
                            style = ProcessingConfig.getSetting(
                                ProcessingConfig.VECTOR_POLYGON_STYLE)
                if style:
                    layer.loadNamedStyle(style)
                details.project.addMapLayer(
                    context.temporaryLayerStore().takeMapLayer(layer))
            else:
                wrongLayers.append(str(l))
        except Exception:
            QgsMessageLog.logMessage(
                QCoreApplication.translate(
                    'Postprocessing', "Error loading result layer:") + "\n" +
                traceback.format_exc(), 'Processing', Qgis.Critical)
            wrongLayers.append(str(l))
        i += 1

    feedback.setProgress(100)

    if wrongLayers:
        msg = QCoreApplication.translate(
            'Postprocessing',
            "The following layers were not correctly generated.")
        msg += "<ul>" + "".join(["<li>%s</li>" % lay
                                 for lay in wrongLayers]) + "</ul>"
        msg += QCoreApplication.translate(
            'Postprocessing',
            "You can check the 'Log Messages Panel' in QGIS main window to find more information about the execution of the algorithm."
        )
        feedback.reportError(msg)

    return len(wrongLayers) == 0
Exemple #20
0
# Initialize processing
Processing.initialize()

# Add Processing providers
reg = app.processingRegistry()
# lizsync provider
from lizsync.processing.provider import LizsyncProvider

reg.addProvider(LizsyncProvider())
# Native QGIS provider
# reg.addProvider(QgsNativeAlgorithms())

# Get parameters
input_alg = sys.argv[1]
parameters = sys.argv[2]
print(input_alg)
print(parameters)
input_params = json.loads(parameters)

# Run Alg
from qgis.core import QgsProcessingFeedback

feedback = QgsProcessingFeedback()
from processing import run as processing_run

res = processing_run(input_alg, input_params, feedback=feedback)
print("RESULT = %s" % json.dumps(res))

# Exit
app.exitQgis()
Exemple #21
0
    def testInputs(self):
        """
        Test creation of script with algorithm inputs
        """
        alg = RAlgorithm(description_file=os.path.join(test_data_path,
                                                       'test_algorithm_2.rsx'))
        alg.initAlgorithm()

        context = QgsProcessingContext()
        feedback = QgsProcessingFeedback()

        # enum evaluation
        script = alg.build_import_commands({'in_enum': 0}, context, feedback)
        self.assertIn('in_enum <- 0', script)

        # boolean evaluation
        script = alg.build_import_commands({'in_bool': True}, context,
                                           feedback)
        self.assertIn('in_bool <- TRUE', script)
        script = alg.build_import_commands({'in_bool': False}, context,
                                           feedback)
        self.assertIn('in_bool <- FALSE', script)

        # number evaluation
        script = alg.build_import_commands({'in_number': None}, context,
                                           feedback)
        self.assertIn('in_number <- NULL', script)
        script = alg.build_import_commands({'in_number': 5}, context, feedback)
        self.assertIn('in_number <- 5.0', script)
        script = alg.build_import_commands({'in_number': 5.5}, context,
                                           feedback)
        self.assertIn('in_number <- 5.5', script)

        # folder destination
        script = alg.build_import_commands(
            {'param_folder_dest': '/tmp/processing/test_algorithm_2_r/'},
            context, feedback)

        # file destination
        script = alg.build_import_commands(
            {
                'param_html_dest':
                '/tmp/processing/test_algorithm_2_r/dest.html'
            }, context, feedback)
        self.assertIn(
            'param_html_dest <- "/tmp/processing/test_algorithm_2_r/dest.html"',
            script)
        script = alg.build_import_commands(
            {
                'param_file_dest':
                '/tmp/processing/test_algorithm_2_r/dest.file'
            }, context, feedback)
        self.assertIn(
            'param_file_dest <- "/tmp/processing/test_algorithm_2_r/dest.file"',
            script)
        script = alg.build_import_commands(
            {'param_csv_dest': '/tmp/processing/test_algorithm_2_r/dest.csv'},
            context, feedback)
        self.assertIn(
            'param_csv_dest <- "/tmp/processing/test_algorithm_2_r/dest.csv"',
            script)
Exemple #22
0
def handleAlgorithmResults(alg, context, feedback=None, showResults=True):
    wrongLayers = []
    if feedback is None:
        feedback = QgsProcessingFeedback()
    feedback.setProgressText(
        QCoreApplication.translate('Postprocessing',
                                   'Loading resulting layers'))
    i = 0
    for l, details in context.layersToLoadOnCompletion().items():
        feedback.setProgress(100 * i /
                             float(len(context.layersToLoadOnCompletion())))
        try:
            layer = QgsProcessingUtils.mapLayerFromString(l, context)
            if layer is not None:
                layer.setName(details.name)
                details.project.addMapLayer(
                    context.temporaryLayerStore().takeMapLayer(layer))
            else:
                name = details.name
                if ProcessingConfig.getSetting(
                        ProcessingConfig.USE_FILENAME_AS_LAYER_NAME):
                    name = os.path.basename(l)
                dataobjects.load(l, name, alg.crs,
                                 RenderingStyles.getStyle(alg.id(), l))
        except Exception:
            QgsMessageLog.logMessage(
                "Error loading result layer:\n" + traceback.format_exc(),
                'Processing', QgsMessageLog.CRITICAL)
            #wrongLayers.append(out.description())
            wrongLayers.append(l)
    # for out in alg.outputs:
    #     feedback.setProgress(100 * i / float(len(alg.outputs)))
    #     if out.flags() & QgsProcessingParameterDefinition.FlagHidden or not out.open:
    #         continue
    #     if isinstance(out, (OutputRaster, OutputVector, OutputTable)):
    #         try:
    #             layer = QgsProcessingUtils.mapLayerFromString(out.value, context)
    #             if layer:
    #                 layer.setName(out.description)
    #                 QgsProject.instance().addMapLayer(context.temporaryLayerStore().takeMapLayer(layer))
    #             else:
    #                 if ProcessingConfig.getSetting(
    #                         ProcessingConfig.USE_FILENAME_AS_LAYER_NAME):
    #                     name = os.path.basename(out.value)
    #                 else:
    #                     name = out.description
    #
    #                 isRaster = True if isinstance(out, OutputRaster) else False
    #                 dataobjects.load(out.value, name, alg.crs,
    #                                  RenderingStyles.getStyle(alg.id(), out.name),
    #                                  isRaster)
    #         except Exception:
    #             QgsMessageLog.logMessage("Error loading result layer:\n" + traceback.format_exc(), 'Processing', QgsMessageLog.CRITICAL)
    #             wrongLayers.append(out.description)
    #     elif isinstance(out, OutputHTML):
    #         resultsList.addResult(alg.icon(), out.description, out.value)
    #     i += 1

    QApplication.restoreOverrideCursor()
    if wrongLayers:
        msg = "The following layers were not correctly generated.<ul>"
        msg += "".join(["<li>%s</li>" % lay for lay in wrongLayers]) + "</ul>"
        msg += "You can check the log messages to find more information about the execution of the algorithm"
        feedback.reportError(msg)

    return len(wrongLayers) == 0
Exemple #23
0
    def testOgr2PostGis(self):
        context = QgsProcessingContext()
        feedback = QgsProcessingFeedback()
        source = os.path.join(testDataPath, 'polys.gml')
        source_with_space = os.path.join(testDataPath, 'filename with spaces.gml')
        alg = OgrToPostGis()
        alg.initAlgorithm()

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source_with_space}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 "' + source_with_space + '" filename_with_spaces '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.filename_with_spaces -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'HOST': 'google.com'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=google.com port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'PORT': 3333}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=3333 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'USER': '******'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public user=kevin_bacon" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'DBNAME': 'secret_stuff'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 dbname=secret_stuff active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'PASSWORD': '******'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 password=passw0rd active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'SCHEMA': 'desktop'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=desktop" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln desktop.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'TABLE': 'out_table'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.out_table -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'PK': ''}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'PK': 'new_fid'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=new_fid -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'PK': '',
                                    'PRIMARY_KEY': 'objectid'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=objectid -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'PK': 'new_id',
                                    'PRIMARY_KEY': 'objectid'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=new_id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'GEOCOLUMN': 'my_geom'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=my_geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'DIM': 1}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=3 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'SIMPLIFY': 5}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -simplify 5 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'SEGMENTIZE': 4}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -segmentize 4 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'SPAT': QgsRectangle(1, 2, 3, 4)}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -spat 1.0 2.0 3.0 4.0 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'FIELDS': ['f1', 'f2']}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 -select "f1,f2" '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'WHERE': '0=1'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -where "0=1" -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'GT': 2}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -gt 2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'OVERWRITE': False}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'APPEND': True}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-append -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'ADDFIELDS': True}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-addfields -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'LAUNDER': True}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-lco LAUNDER=NO -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'INDEX': True}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-lco SPATIAL_INDEX=OFF -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'SKIPFAILURES': True}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -skipfailures -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'PROMOTETOMULTI': False}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'PRECISION': False}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI -lco PRECISION=NO'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'OPTIONS': 'blah'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI blah'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'SHAPE_ENCODING': 'blah'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES --config SHAPE_ENCODING "blah" -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'GTYPE': 4}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -nlt LINESTRING -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'A_SRS': 'EPSG:3111'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'A_SRS': QgsCoordinateReferenceSystem('EPSG:3111')}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI'])

        custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs'
        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'A_SRS': custom_crs}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:20936 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'T_SRS': 'EPSG:3111'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:3111 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'T_SRS': QgsCoordinateReferenceSystem('EPSG:3111')}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:3111 -nlt PROMOTE_TO_MULTI'])

        custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs'
        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'T_SRS': custom_crs}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:20936 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'S_SRS': 'EPSG:3111'}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:3111 -nlt PROMOTE_TO_MULTI'])

        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'S_SRS': QgsCoordinateReferenceSystem('EPSG:3111')}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:3111 -nlt PROMOTE_TO_MULTI'])

        custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs'
        self.assertEqual(
            alg.getConsoleCommands({'INPUT': source,
                                    'S_SRS': custom_crs}, context, feedback),
            ['ogr2ogr',
             '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" '
             '-lco DIM=2 ' + source + ' polys2 '
             '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:20936 -nlt PROMOTE_TO_MULTI'])
Exemple #24
0
    def testDissolve(self):
        context = QgsProcessingContext()
        feedback = QgsProcessingFeedback()
        source = os.path.join(testDataPath, 'polys.gml')
        source_with_space = os.path.join(testDataPath, 'filename with spaces.gml')
        alg = Dissolve()
        alg.initAlgorithm()

        with tempfile.TemporaryDirectory() as outdir:
            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source,
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 source + ' ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry FROM \'polys2\'" ' +
                 '-f "ESRI Shapefile"'])

            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source,
                                        'FIELD': 'my_field',
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 source + ' ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, my_field FROM \'polys2\' ' +
                 'GROUP BY my_field" -f "ESRI Shapefile"'])

            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source_with_space,
                                        'FIELD': 'my_field',
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 '"' + source_with_space + '" ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, my_field FROM \'filename_with_spaces\' ' +
                 'GROUP BY my_field" -f "ESRI Shapefile"'])

            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source,
                                        'FIELD': 'my_field',
                                        'GEOMETRY': 'the_geom',
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 source + ' ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, my_field FROM \'polys2\' ' +
                 'GROUP BY my_field" -f "ESRI Shapefile"'])

            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source,
                                        'FIELD': 'my_field',
                                        'KEEP_ATTRIBUTES': False,
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 source + ' ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, my_field FROM \'polys2\' ' +
                 'GROUP BY my_field" -f "ESRI Shapefile"'])

            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source,
                                        'KEEP_ATTRIBUTES': False,
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 source + ' ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry FROM \'polys2\'" ' +
                 '-f "ESRI Shapefile"'])

            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source,
                                        'FIELD': 'my_field',
                                        'EXPLODE_COLLECTIONS': True,
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 source + ' ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, my_field FROM \'polys2\' ' +
                 'GROUP BY my_field" -explodecollections -f "ESRI Shapefile"'])

            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source,
                                        'FIELD': 'my_field',
                                        'COUNT_FEATURES': True,
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 source + ' ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, my_field, COUNT(geometry) AS count FROM \'polys2\' ' +
                 'GROUP BY my_field" -f "ESRI Shapefile"'])

            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source,
                                        'FIELD': 'my_field',
                                        'COUNT_FEATURES': True,
                                        'GEOMETRY': 'the_geom',
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 source + ' ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, my_field, COUNT(the_geom) AS count FROM \'polys2\' ' +
                 'GROUP BY my_field" -f "ESRI Shapefile"'])

            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source,
                                        'FIELD': 'my_field',
                                        'COMPUTE_AREA': True,
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 source + ' ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, my_field, SUM(ST_Area(geometry)) AS area, ' +
                 'ST_Perimeter(ST_Union(geometry)) AS perimeter FROM \'polys2\' ' +
                 'GROUP BY my_field" -f "ESRI Shapefile"'])

            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source,
                                        'FIELD': 'my_field',
                                        'COMPUTE_AREA': True,
                                        'GEOMETRY': 'the_geom',
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 source + ' ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(the_geom) AS the_geom, my_field, SUM(ST_Area(the_geom)) AS area, ' +
                 'ST_Perimeter(ST_Union(the_geom)) AS perimeter FROM \'polys2\' ' +
                 'GROUP BY my_field" -f "ESRI Shapefile"'])

            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source,
                                        'FIELD': 'my_field',
                                        'COMPUTE_STATISTICS': True,
                                        'STATISTICS_ATTRIBUTE': 'my_val',
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 source + ' ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, my_field, ' +
                 'SUM(my_val) AS sum, MIN(my_val) AS min, MAX(my_val) AS max, AVG(my_val) AS avg FROM \'polys2\' ' +
                 'GROUP BY my_field" -f "ESRI Shapefile"'])

            # compute stats without stats attribute, and vice versa (should be ignored)
            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source,
                                        'FIELD': 'my_field',
                                        'COMPUTE_STATISTICS': True,
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 source + ' ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, my_field FROM \'polys2\' ' +
                 'GROUP BY my_field" -f "ESRI Shapefile"'])
            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source,
                                        'FIELD': 'my_field',
                                        'STATISTICS_ATTRIBUTE': 'my_val',
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 source + ' ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, my_field FROM \'polys2\' ' +
                 'GROUP BY my_field" -f "ESRI Shapefile"'])

            self.assertEqual(
                alg.getConsoleCommands({'INPUT': source,
                                        'FIELD': 'my_field',
                                        'OPTIONS': 'my opts',
                                        'OUTPUT': outdir + '/check.shp'}, context, feedback),
                ['ogr2ogr',
                 outdir + '/check.shp ' +
                 source + ' ' +
                 '-nlt PROMOTE_TO_MULTI -dialect sqlite -sql "SELECT ST_Union(geometry) AS geometry, my_field FROM \'polys2\' ' +
                 'GROUP BY my_field" "my opts" -f "ESRI Shapefile"'])
Exemple #25
0
 def initialize_feedback(self):
     self.progress.setValue(0)
     self.progress.setVisible(False)
     self.feedback = QgsProcessingFeedback()
     self.feedback.progressChanged.connect(self.progress_changed)
     self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True)
Exemple #26
0
def generate_od_routes(
    network_layer: QgsVectorLayer,
    origin_layer: QgsVectorLayer,
    poi_layer: QgsVectorLayer,
    size_field: str,
    class_field: str,
    work_layer: QgsVectorLayer = None,
    work_size_field: str = None,
    school_layer: QgsVectorLayer = None,
    school_size_field: str = None,
    origin_weight_field: str = None,
    socio_data=None,
    health_data=None,
    diversity_data=None,
    join_on: str = None,
    max_distance: int = 25000,
    return_layer: bool = True,
    return_raw: bool = False,
    feedback: QgsProcessingFeedback = None,
) -> QgsVectorLayer:
    """
    Shortest path algorithm based on Dijkstra's algorithm

    :param network_layer: road network
    :param points_layer: combined from to points
    :param relations_data: tabular from to id data
    :param origin_field: name of from field
    :param destination_field: name of to field
    :param max_distance: maximum distance/cost
    :param crs: output layer crs
    """

    if not network_layer.wkbType() & QgsWkbTypes.LineString:
        raise Exception('Network layer must be of type LineString')
    crs = network_layer.crs()

    ## prepare graph
    director = QgsVectorLayerDirector(
        source=network_layer,
        directionFieldId=-1,
        directDirectionValue='',
        reverseDirectionValue='',
        bothDirectionValue='',
        defaultDirection=QgsVectorLayerDirector.DirectionBoth,
    )
    # First strategy is for actual shortest distance calculation
    director.addStrategy(QgsNetworkDistanceStrategy())  # 0
    # Second strategy is a hack to be able to recover the edge id
    director.addStrategy(SaveFidStrategy())  # 1
    builder = QgsGraphBuilder(crs)

    ## spatial index

    poi_sidx = QgsSpatialIndex(poi_layer)
    work_sidx = QgsSpatialIndex(work_layer)
    school_sidx = QgsSpatialIndex(school_layer)

    ## prepare points
    orig_n = len(origin_layer)
    poi_n = len(poi_layer)
    work_n = len(work_layer) if work_layer else 0
    school_n = len(school_layer) if school_layer else 0
    dest_n = poi_n + work_n + school_n

    orig_points = [None] * orig_n
    orig_sizes = np.zeros(orig_n, dtype=float)
    if socio_data:
        orig_socio = np.zeros(orig_n, dtype=float)
    dest_points = [None] * dest_n
    dest_sizes = [None] * dest_n
    dest_fids = [None] * dest_n
    dest_cats = [None] * dest_n

    orig_id_field = 'deso'
    for i, feat in enumerate(origin_layer.getFeatures()):
        orig_points[i] = feat.geometry().asPoint()
        orig_sizes[i] = feat[size_field] * (
            feat[origin_weight_field] if origin_weight_field else 1
        )

        if socio_data:
            orig_socio[i] = socio_data[
                feat[orig_id_field]
            ]  # FIXME: check if all origins have data

    if socio_data:
        orig_socio = orig_socio / np.mean(orig_socio)
        orig_sizes *= orig_socio

    for i, feat in enumerate(poi_layer.getFeatures()):
        dest_points[i] = feat.geometry().asPoint()
        dest_fids[i] = feat.id()
        dest_sizes[i] = 1  # TODO: dest size
        dest_cats[i] = poi_class_map.get(feat[class_field])

    if work_layer:
        for i, feat in enumerate(work_layer.getFeatures(), start=poi_n):
            dest_points[i] = feat.geometry().asPoint()
            dest_fids[i] = feat.id()
            dest_sizes[i] = feat[work_size_field]  # TODO: dest size
            dest_cats[i] = 'work'

    if school_layer:
        for i, feat in enumerate(school_layer.getFeatures(), start=(poi_n + work_n)):
            dest_points[i] = feat.geometry().asPoint()
            dest_fids[i] = feat.id()
            dest_sizes[i] = feat[school_size_field]  # TODO: dest size
            dest_cats[i] = 'school'

    # points = [origin.point for origin in origins_data] + [
    #    dest.point for dest in dests_data
    # ]

    if feedback is None:
        feedback = QgsProcessingFeedback()

        def progress(p):
            if int(10 * p % 100) == 0:
                print(f'{int(p):#3d}%')

        feedback.progressChanged.connect(progress)

    with timing('build network graph'):
        tied_points = director.makeGraph(
            builder, orig_points + dest_points, feedback=feedback
        )
        graph = builder.graph()

    orig_tied_points = tied_points[:orig_n]
    dest_tied_points = tied_points[orig_n:]

    poi_tied_points = dest_tied_points[:poi_n]
    work_tied_points = dest_tied_points[poi_n : poi_n + work_n]
    school_tied_points = dest_tied_points[poi_n + work_n :]

    dest_fid_to_tied_points = dict(zip(dest_fids, enumerate(dest_tied_points)))

    poi_fid_to_tied_points = dict(zip(dest_fids[:poi_n], enumerate(poi_tied_points)))
    work_fid_to_tied_points = dict(
        zip(dest_fids[poi_n : poi_n + work_n], enumerate(work_tied_points, start=poi_n))
    )
    school_fid_to_tied_points = dict(
        zip(
            dest_fids[poi_n + work_n :],
            enumerate(school_tied_points, start=poi_n + work_n),
        )
    )

    orig_dests = [None] * orig_n
    for i, point in enumerate(orig_points):
        orig_dests[i] = (
            [
                poi_fid_to_tied_points[fid]
                for fid in poi_sidx.nearestNeighbor(
                    point, neighbors=MAX_NEIGHBORS, maxDistance=max_distance
                )
            ]
            + [
                work_fid_to_tied_points[fid]
                for fid in work_sidx.nearestNeighbor(
                    point, neighbors=MAX_NEIGHBORS, maxDistance=max_distance
                )
            ]
            + [
                school_fid_to_tied_points[fid]
                for fid in school_sidx.nearestNeighbor(
                    point, neighbors=MAX_NEIGHBORS, maxDistance=max_distance
                )
            ]
        )

    step = 100.0 / orig_n
    time_dijkstra = 0.0
    time_find = 0.0
    time_route = 0.0
    with timing('calculate connecting routes'):
        routes = []
        # for i, (origin_fid, dest_fids) in enumerate(od_data):
        for i, (orig_point, dests) in enumerate(zip(orig_tied_points, orig_dests)):
            origin_vertex_id = graph.findVertex(orig_point)

            # Calculate the tree and cost using the distance strategy (#0)
            ts = time()
            (tree, cost) = QgsGraphAnalyzer.dijkstra(graph, origin_vertex_id, 0)
            time_dijkstra += time() - ts

            for j, dest_point in dests:
                if feedback.isCanceled():
                    return
                if dest_sizes[j] <= 0:
                    continue
                category = dest_cats[j]
                if category is None:
                    continue
                ts = time()
                dest_vertex_id = graph.findVertex(dest_point)
                time_find += time() - ts
                if tree[dest_vertex_id] != -1 and (
                    cost[dest_vertex_id] <= MAX_DISTANCE_M
                    or MAX_DISTANCE_M <= 0  # TODO: enable skipping max distance
                ):
                    route_distance = cost[dest_vertex_id]
                    # route_points = [graph.vertex(dest_vertex_id).point()]
                    cur_vertex_id = dest_vertex_id
                    route_fids = []
                    # Iterate the graph from dest to origin saving the edges
                    ts = time()
                    while cur_vertex_id != origin_vertex_id:
                        cur_edge = graph.edge(tree[cur_vertex_id])
                        # Here we recover the edge id through strategy #1
                        route_fids.append(cur_edge.cost(1))
                        cur_vertex_id = cur_edge.fromVertex()
                        # route_points.append(graph.vertex(cur_vertex_id).point())
                    time_route += time() - ts

                    # route_points.reverse()
                    # route_geom = QgsGeometry.fromPolylineXY(route_points))

                    # Hack to remove duplicate fids
                    route_fids = list(
                        dict.fromkeys(route_fids)
                    )  # NOTE: requires python >= 3.7 for ordered dict FIXME: add python version check
                    route_fids.reverse()

                    # Calc
                    # TODO: Move to matrix and vectorize calculation using numpy
                    gravity_value = poi_gravity_values[category]
                    bike_params = mode_params_bike[category]
                    ebike_params = mode_params_ebike[category]

                    # NOTE: we include dest size in decay here
                    decay = dest_sizes[j] * math.exp(
                        gravity_value * route_distance / 1000.0
                    )
                    p_bike = sigmoid(*bike_params, route_distance)
                    p_ebike = sigmoid(*ebike_params, route_distance)

                    # TODO: use namedtuple or dataclass
                    routes.append(
                        Route(
                            i,
                            j,
                            category,
                            route_distance,
                            decay,
                            p_bike,
                            p_ebike,
                            route_fids,
                        )
                    )
            feedback.setProgress(i * step)

        print(f'dijkstra took: {time_dijkstra:#1.2f} sec')
        print(f'find vertex took: {time_find:#1.2f} sec')
        print(f'route took: {time_route:#1.2f} sec')

    with timing('post process routes'):
        alpha_bike = 0.8
        alpha_ebke = 0.2

        decay_sums = {cat: defaultdict(float) for cat in poi_categories}
        bike_values = {cat: defaultdict(float) for cat in poi_categories}
        ebike_values = {cat: defaultdict(float) for cat in poi_categories}

        for route in routes:
            # NOTE: dest size is included in decay
            decay_sums[route.cat][route.i] += route.decay
        for route in routes:
            decay_sum = decay_sums[route.cat][route.i]
            # TODO: add T_p and alpha_m
            T_p = trip_generation[route.cat]
            bike_value = (
                T_p
                * alpha_bike
                * orig_sizes[route.i]
                * route.p_bike
                * route.decay
                / decay_sum
            )
            ebike_value = (
                T_p
                * alpha_ebke
                * orig_sizes[route.i]
                * route.p_ebike
                * route.decay
                / decay_sum
            )
            for fid in route.net_fids:
                bike_values[route.cat][fid] += float(bike_value)
                ebike_values[route.cat][fid] += float(ebike_value)

    # FIXME: Un-kludge this
    with timing('create result features'):
        fields = get_fields()

        segments = []
        for feature in network_layer.getFeatures():
            fid = feature.id()
            segment = QgsFeature(fields)
            segment.setGeometry(QgsGeometry(feature.geometry()))

            segment['network_fid'] = fid
            flow = 0.0
            for cat in poi_categories:
                bike_field = f'{cat}_bike_value'
                ebike_field = f'{cat}_ebike_value'

                flow_bike = segment[bike_field] = bike_values[cat].get(fid)
                flow_ebke = segment[ebike_field] = ebike_values[cat].get(fid)

                if flow_bike is not None:
                    flow += flow_bike
                if flow_ebke is not None:
                    flow += flow_ebke

            segment['flow'] = flow
            segment['lts'] = feature['lts']
            segment['vgu'] = feature['vgu']
            segment['R'] = flow * feature['ratio']
            segments.append(segment)

    if not return_layer:
        if return_raw:
            return segments, bike_values, ebike_values
        return segments

    with timing('create result layer'):
        output_layer = QgsVectorLayer(
            f'LineString?crs={crs.toWkt()}', 'segments', 'memory'
        )
        with edit(output_layer):
            for field in fields:
                output_layer.addAttribute(field)
            output_layer.addFeatures(segments, flags=QgsFeatureSink.FastInsert)

    return output_layer
Exemple #27
0
    def mergeDataSources2Vrt(self,
                             dataSources,
                             outFile,
                             union=False,
                             relative=False,
                             schema=False,
                             feedback=None):
        '''Function to do the work of merging datasources in a single vrt format

        @param data_sources: Array of path strings
        @param outfile: the output vrt file to generate
        @param relative: Write relative flag. DOES NOT relativise paths. They have to be already relative
        @param schema: Schema flag
        @return: vrt in string format
        '''
        if feedback is None:
            feedback = QgsProcessingFeedback()

        vrt = '<OGRVRTDataSource>'
        if union:
            vrt += '<OGRVRTUnionLayer name="UnionedLayer">'

        total = 100.0 / len(dataSources) if dataSources else 1
        for current, layer in enumerate(dataSources):
            if feedback.isCanceled():
                break

            feedback.setProgress(int(current * total))

            inFile = layer.source()
            srcDS = ogr.Open(inFile, 0)
            if srcDS is None:
                raise QgsProcessingException(
                    self.tr('Invalid datasource: {}'.format(inFile)))

            if schema:
                inFile = '@dummy@'

            for layer in srcDS:
                layerDef = layer.GetLayerDefn()
                layerName = layerDef.GetName()

                vrt += '<OGRVRTLayer name="{}">'.format(self.XmlEsc(layerName))
                vrt += '<SrcDataSource relativeToVRT="{}" shared="{}">{}</SrcDataSource>'.format(
                    1 if relative else 0, not schema, self.XmlEsc(inFile))
                if schema:
                    vrt += '<SrcLayer>@dummy@</SrcLayer>'
                else:
                    vrt += '<SrcLayer>{}</SrcLayer>'.format(
                        self.XmlEsc(layerName))

                vrt += '<GeometryType>{}</GeometryType>'.format(
                    self.GeomType2Name(layerDef.GetGeomType()))

                crs = layer.GetSpatialRef()
                if crs is not None:
                    vrt += '<LayerSRS>{}</LayerSRS>'.format(
                        self.XmlEsc(crs.ExportToWkt()))

                # Process all the fields.
                for fieldIdx in range(layerDef.GetFieldCount()):
                    fieldDef = layerDef.GetFieldDefn(fieldIdx)
                    vrt += '<Field name="{}" type="{}"'.format(
                        self.XmlEsc(fieldDef.GetName()),
                        self.fieldType2Name(fieldDef.GetType()))
                    if not schema:
                        vrt += ' src="{}"'.format(
                            self.XmlEsc(fieldDef.GetName()))
                    if fieldDef.GetWidth() > 0:
                        vrt += ' width="{}"'.format(fieldDef.GetWidth())
                    if fieldDef.GetPrecision() > 0:
                        vrt += ' precision="{}"'.format(
                            fieldDef.GetPrecision())
                    vrt += '/>'

                vrt += '</OGRVRTLayer>'

            srcDS.Destroy()

        if union:
            vrt += '</OGRVRTUnionLayer>'

        vrt += '</OGRVRTDataSource>'

        #TODO: pretty-print XML

        if outFile is not None:
            with codecs.open(outFile, 'w') as f:
                f.write(vrt)

        return vrt
Exemple #28
0
def execute_in_place_run(alg, active_layer, parameters, context=None, feedback=None, raise_exceptions=False):
    """Executes an algorithm modifying features in-place in the input layer.

    The input layer must be editable or an exception is raised.

    :param alg: algorithm to run
    :type alg: QgsProcessingAlgorithm
    :param active_layer: the editable layer
    :type active_layer: QgsVectoLayer
    :param parameters: parameters of the algorithm
    :type parameters: dict
    :param context: context, defaults to None
    :param context: QgsProcessingContext, optional
    :param feedback: feedback, defaults to None
    :param feedback: QgsProcessingFeedback, optional
    :raises QgsProcessingException: raised when the layer is not editable or the layer cannot be found in the current project
    :return: a tuple with true if success and results
    :rtype: tuple
    """

    if feedback is None:
        feedback = QgsProcessingFeedback()
    if context is None:
        context = dataobjects.createContext(feedback)

    if active_layer is None or not active_layer.isEditable():
        raise QgsProcessingException(tr("Layer is not editable or layer is None."))

    if not alg.supportInPlaceEdit(active_layer):
        raise QgsProcessingException(tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."))

    parameters['OUTPUT'] = 'memory:'

    try:
        new_feature_ids = []

        active_layer.beginEditCommand(alg.name())

        req = QgsFeatureRequest(QgsExpression(r"$id < 0"))
        req.setFlags(QgsFeatureRequest.NoGeometry)
        req.setSubsetOfAttributes([])

        # Checks whether the algorithm has a processFeature method
        if hasattr(alg, 'processFeature'):  # in-place feature editing
            # Make a clone or it will crash the second time the dialog
            # is opened and run
            alg = alg.create()
            if not alg.prepare(parameters, context, feedback):
                raise QgsProcessingException(tr("Could not prepare selected algorithm."))
            # Check again for compatibility after prepare
            if not alg.supportInPlaceEdit(active_layer):
                raise QgsProcessingException(tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."))
            field_idxs = range(len(active_layer.fields()))
            feature_iterator = active_layer.getFeatures(QgsFeatureRequest(active_layer.selectedFeatureIds())) if parameters['INPUT'].selectedFeaturesOnly else active_layer.getFeatures()
            for f in feature_iterator:
                new_features = alg.processFeature(f, context, feedback)
                new_features = make_features_compatible(new_features, active_layer)
                if len(new_features) == 0:
                    active_layer.deleteFeature(f.id())
                elif len(new_features) == 1:
                    new_f = new_features[0]
                    if not f.geometry().equals(new_f.geometry()):
                        active_layer.changeGeometry(f.id(), new_f.geometry())
                    if f.attributes() != new_f.attributes():
                        active_layer.changeAttributeValues(f.id(), dict(zip(field_idxs, new_f.attributes())), dict(zip(field_idxs, f.attributes())))
                    new_feature_ids.append(f.id())
                else:
                    active_layer.deleteFeature(f.id())
                    # Get the new ids
                    old_ids = set([f.id() for f in active_layer.getFeatures(req)])
                    if not active_layer.addFeatures(new_features):
                        raise QgsProcessingException(tr("Error adding processed features back into the layer."))
                    new_ids = set([f.id() for f in active_layer.getFeatures(req)])
                    new_feature_ids += list(new_ids - old_ids)

            results, ok = {}, True

        else:  # Traditional 'run' with delete and add features cycle
            results, ok = alg.run(parameters, context, feedback)

            if ok:
                result_layer = QgsProcessingUtils.mapLayerFromString(results['OUTPUT'], context)
                # TODO: check if features have changed before delete/add cycle
                active_layer.deleteFeatures(active_layer.selectedFeatureIds())
                new_features = []
                for f in result_layer.getFeatures():
                    new_features.extend(make_features_compatible([f], active_layer))

                # Get the new ids
                old_ids = set([f.id() for f in active_layer.getFeatures(req)])
                if not active_layer.addFeatures(new_features):
                    raise QgsProcessingException(tr("Error adding processed features back into the layer."))
                new_ids = set([f.id() for f in active_layer.getFeatures(req)])
                new_feature_ids += list(new_ids - old_ids)

        active_layer.endEditCommand()

        if ok and new_feature_ids:
            active_layer.selectByIds(new_feature_ids)
        elif not ok:
            active_layer.rollBack()

        return ok, results

    except QgsProcessingException as e:
        active_layer.endEditCommand()
        active_layer.rollBack()
        if raise_exceptions:
            raise e
        QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.Critical)
        if feedback is not None:
            feedback.reportError(getattr(e, 'msg', str(e)))

    return False, {}
Exemple #29
0
    def runAlgorithm(algOrName,
                     parameters,
                     onFinish=None,
                     feedback=None,
                     context=None):
        if isinstance(algOrName, QgsProcessingAlgorithm):
            alg = algOrName
        else:
            alg = QgsApplication.processingRegistry().createAlgorithmById(
                algOrName)

        if feedback is None:
            feedback = QgsProcessingFeedback()

        if alg is None:
            msg = Processing.tr('Error: Algorithm {0} not found\n').format(
                algOrName)
            feedback.reportError(msg)
            raise QgsProcessingException(msg)

        if context is None:
            context = dataobjects.createContext(feedback)

        if context.feedback() is None:
            context.setFeedback(feedback)

        ok, msg = alg.checkParameterValues(parameters, context)
        if not ok:
            msg = Processing.tr('Unable to execute algorithm\n{0}').format(msg)
            feedback.reportError(msg)
            raise QgsProcessingException(msg)

        if not alg.validateInputCrs(parameters, context):
            feedback.pushInfo(
                Processing.
                tr('Warning: Not all input layers use the same CRS.\nThis can cause unexpected results.'
                   ))

        ret, results = execute(alg, parameters, context, feedback)
        if ret:
            feedback.pushInfo(Processing.tr('Results: {}').format(results))

            if onFinish is not None:
                onFinish(alg, context, feedback)
            else:
                # auto convert layer references in results to map layers
                for out in alg.outputDefinitions():
                    if out.name() not in results:
                        continue

                    if isinstance(out, (QgsProcessingOutputVectorLayer,
                                        QgsProcessingOutputRasterLayer,
                                        QgsProcessingOutputMapLayer)):
                        result = results[out.name()]
                        if not isinstance(result, QgsMapLayer):
                            layer = context.takeResultLayer(
                                result
                            )  # transfer layer ownership out of context
                            if layer:
                                results[out.name(
                                )] = layer  # replace layer string ref with actual layer (+ownership)
                    elif isinstance(out, QgsProcessingOutputMultipleLayers):
                        result = results[out.name()]
                        if result:
                            layers_result = []
                            for l in result:
                                if not isinstance(result, QgsMapLayer):
                                    layer = context.takeResultLayer(
                                        l
                                    )  # transfer layer ownership out of context
                                    if layer:
                                        layers_result.append(layer)
                                    else:
                                        layers_result.append(l)
                                else:
                                    layers_result.append(l)

                            results[out.name(
                            )] = layers_result  # replace layers strings ref with actual layers (+ownership)

        else:
            msg = Processing.tr("There were errors executing the algorithm.")
            feedback.reportError(msg)
            raise QgsProcessingException(msg)

        if isinstance(feedback, MessageBarProgress):
            feedback.close()
        return results
Exemple #30
0
    def create_feature_from_observation(
        self,
        observation: Observation,
        geometriobjekter: Dict[str, GeometriObjekt],
        idents: Dict[str, str],
        feedback: QgsProcessingFeedback,
    ):
        observation_id = observation.objektid

        fikspunkt1_id = observation.opstillingspunktid
        fikspunkt1_ident = "uuid:" + fikspunkt1_id
        if fikspunkt1_id in idents:
            fikspunkt1_ident = idents[fikspunkt1_id]

        fikspunkt2_id = observation.sigtepunktid
        fikspunkt2_ident = "uuid:" + fikspunkt2_id
        if fikspunkt2_id in idents:
            fikspunkt2_ident = idents[fikspunkt2_id]

        geometriobjekt1 = geometriobjekter[fikspunkt1_id]
        geometriobjekt2 = geometriobjekter[fikspunkt2_id]
        line_geometry = self.create_line_geometry_from_geometriobjekter(
            geometriobjekt1, geometriobjekt2, feedback)

        if line_geometry:
            # create the feature
            fet = QgsFeature()
            fet.setGeometry(line_geometry)
            # Felter, der skal gemmes på feature:
            #    [QgsField("observation_id", QVariant.String),
            #     QgsField("observation_type_id", QVariant.Double)
            #     QgsField("fikspunkt1_id", QVariant.String),
            #     QgsField("fikspunkt1_ident", QVariant.String),
            #     QgsField("fikspunkt2_id", QVariant.String),
            #     QgsField("fikspunkt2_ident", QVariant.String),
            #     QgsField("registrering_fra", QVariant.DateTime),
            #     QgsField("registrering_fra_iso", QVariant.String),
            #     QgsField("koteforskel", QVariant.Double),
            #     QgsField("nivellementslaengde", QVariant.Double),
            #     QgsField("antal_opstillinger", QVariant.Double), Value3
            #     QgsField("afstandsafhaengig_varians", QVariant.Double),  (value5 for id=1, value4 for id=2)
            #     QgsField("afstandsuafhaengig_varians", QVariant.Double),  (value6 for id=1, value5 for id=2)
            #     QgsField("Praecisionsnivellement", QVariant.Double)],  (value7 for id=1, 0 for id=2)

            observation_type_id = observation.observationstypeid
            registrering_fra = QDateTime(observation.registreringfra)
            registrering_fra_iso = registrering_fra.toString(Qt.ISODate)
            koteforskel = observation.value1
            nivellementslaengde = observation.value2
            antal_opstillinger = observation.value3
            if observation_type_id == 1:
                afstandsafhaengig_varians = observation.value5
                afstandsuafhaengig_varians = observation.value6
                Praecisionsnivellement = observation.value7
            elif observation_type_id == 2:
                afstandsafhaengig_varians = observation.value4
                afstandsuafhaengig_varians = observation.value5
                Praecisionsnivellement = 0
            else:
                # Observationstypeid > 2
                feedback.setProgressText(
                    "observation_type_id > 2 for observation med id =  {id}. Springes over"
                    .format(id=observation_id))
                return None

            # create the feature
            feature = QgsFeature()
            feature.setGeometry(line_geometry)
            feature.setAttributes([
                observation_id,
                observation_type_id,
                fikspunkt1_id,
                fikspunkt1_ident,
                fikspunkt2_id,
                fikspunkt2_ident,
                registrering_fra,
                registrering_fra_iso,
                koteforskel,
                nivellementslaengde,
                antal_opstillinger,
                afstandsafhaengig_varians,
                afstandsuafhaengig_varians,
                Praecisionsnivellement,
            ])

            return feature
        else:
            # A geometry could not be established
            feedback.setProgressText(
                "En liniegeometri kunne IKKE opettes for observation med id =  {id}"
                .format(id=observation_id))
            return None
Exemple #31
0
 def __init__(self, dialog):
     QgsProcessingFeedback.__init__(self)
     self.dialog = dialog
Exemple #32
0
def execute_in_place_run(alg, active_layer, parameters, context=None, feedback=None, raise_exceptions=False):
    """Executes an algorithm modifying features in-place in the input layer.

    The input layer must be editable or an exception is raised.

    :param alg: algorithm to run
    :type alg: QgsProcessingAlgorithm
    :param active_layer: the editable layer
    :type active_layer: QgsVectoLayer
    :param parameters: parameters of the algorithm
    :type parameters: dict
    :param context: context, defaults to None
    :param context: QgsProcessingContext, optional
    :param feedback: feedback, defaults to None
    :param feedback: QgsProcessingFeedback, optional
    :raises QgsProcessingException: raised when the layer is not editable or the layer cannot be found in the current project
    :return: a tuple with true if success and results
    :rtype: tuple
    """

    if feedback is None:
        feedback = QgsProcessingFeedback()
    if context is None:
        context = dataobjects.createContext(feedback)

    if active_layer is None or not active_layer.isEditable():
        raise QgsProcessingException(tr("Layer is not editable or layer is None."))

    if not alg.supportInPlaceEdit(active_layer):
        raise QgsProcessingException(tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."))

    parameters['OUTPUT'] = 'memory:'

    try:
        new_feature_ids = []

        active_layer.beginEditCommand(alg.displayName())

        req = QgsFeatureRequest(QgsExpression(r"$id < 0"))
        req.setFlags(QgsFeatureRequest.NoGeometry)
        req.setSubsetOfAttributes([])

        # Checks whether the algorithm has a processFeature method
        if hasattr(alg, 'processFeature'):  # in-place feature editing
            # Make a clone or it will crash the second time the dialog
            # is opened and run
            alg = alg.create()
            if not alg.prepare(parameters, context, feedback):
                raise QgsProcessingException(tr("Could not prepare selected algorithm."))
            # Check again for compatibility after prepare
            if not alg.supportInPlaceEdit(active_layer):
                raise QgsProcessingException(tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."))
            field_idxs = range(len(active_layer.fields()))
            feature_iterator = active_layer.getFeatures(QgsFeatureRequest(active_layer.selectedFeatureIds())) if parameters['INPUT'].selectedFeaturesOnly else active_layer.getFeatures()
            step = 100 / len(active_layer.selectedFeatureIds()) if active_layer.selectedFeatureIds() else 1
            for current, f in enumerate(feature_iterator):
                feedback.setProgress(current * step)
                if feedback.isCanceled():
                    break

                # need a deep copy, because python processFeature implementations may return
                # a shallow copy from processFeature
                input_feature = QgsFeature(f)
                new_features = alg.processFeature(input_feature, context, feedback)
                new_features = QgsVectorLayerUtils.makeFeaturesCompatible(new_features, active_layer)
                if len(new_features) == 0:
                    active_layer.deleteFeature(f.id())
                elif len(new_features) == 1:
                    new_f = new_features[0]
                    if not f.geometry().equals(new_f.geometry()):
                        active_layer.changeGeometry(f.id(), new_f.geometry())
                    if f.attributes() != new_f.attributes():
                        active_layer.changeAttributeValues(f.id(), dict(zip(field_idxs, new_f.attributes())), dict(zip(field_idxs, f.attributes())))
                    new_feature_ids.append(f.id())
                else:
                    active_layer.deleteFeature(f.id())
                    # Get the new ids
                    old_ids = set([f.id() for f in active_layer.getFeatures(req)])
                    if not active_layer.addFeatures(new_features):
                        raise QgsProcessingException(tr("Error adding processed features back into the layer."))
                    new_ids = set([f.id() for f in active_layer.getFeatures(req)])
                    new_feature_ids += list(new_ids - old_ids)

            results, ok = {}, True

        else:  # Traditional 'run' with delete and add features cycle
            results, ok = alg.run(parameters, context, feedback)

            if ok:
                result_layer = QgsProcessingUtils.mapLayerFromString(results['OUTPUT'], context)
                # TODO: check if features have changed before delete/add cycle
                active_layer.deleteFeatures(active_layer.selectedFeatureIds())
                new_features = []
                for f in result_layer.getFeatures():
                    new_features.extend(QgsVectorLayerUtils.
                                        makeFeaturesCompatible([f], active_layer))

                # Get the new ids
                old_ids = set([f.id() for f in active_layer.getFeatures(req)])
                if not active_layer.addFeatures(new_features):
                    raise QgsProcessingException(tr("Error adding processed features back into the layer."))
                new_ids = set([f.id() for f in active_layer.getFeatures(req)])
                new_feature_ids += list(new_ids - old_ids)

        active_layer.endEditCommand()

        if ok and new_feature_ids:
            active_layer.selectByIds(new_feature_ids)
        elif not ok:
            active_layer.rollBack()

        return ok, results

    except QgsProcessingException as e:
        active_layer.endEditCommand()
        active_layer.rollBack()
        if raise_exceptions:
            raise e
        QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.Critical)
        if feedback is not None:
            feedback.reportError(getattr(e, 'msg', str(e)))

    return False, {}
Exemple #33
0
    def testOneSidedBuffer(self):
        context = QgsProcessingContext()
        feedback = QgsProcessingFeedback()
        source = os.path.join(testDataPath, 'polys.gml')
        source_with_space = os.path.join(testDataPath,
                                         'filename with spaces.gml')
        alg = OneSideBuffer()
        alg.initAlgorithm()

        with tempfile.TemporaryDirectory() as outdir:
            self.assertEqual(
                alg.getConsoleCommands(
                    {
                        'INPUT': source,
                        'DISTANCE': 5,
                        'OUTPUT': outdir + '/check.shp'
                    }, context, feedback),
                [
                    'ogr2ogr', outdir + '/check.shp ' + source + ' ' +
                    '-dialect sqlite -sql "SELECT ST_SingleSidedBuffer(geometry, 5.0, 0) AS geometry,* FROM \\"polys2\\"" '
                    + '-f "ESRI Shapefile"'
                ])

            self.assertEqual(
                alg.getConsoleCommands(
                    {
                        'INPUT': source,
                        'DISTANCE': 5,
                        'DISSOLVE': True,
                        'OUTPUT': outdir + '/check.shp'
                    }, context, feedback),
                [
                    'ogr2ogr', outdir + '/check.shp ' + source + ' ' +
                    '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* FROM \\"polys2\\"" '
                    + '-f "ESRI Shapefile"'
                ])

            self.assertEqual(
                alg.getConsoleCommands(
                    {
                        'INPUT': source,
                        'DISTANCE': 5,
                        'EXPLODE_COLLECTIONS': True,
                        'OUTPUT': outdir + '/check.shp'
                    }, context, feedback),
                [
                    'ogr2ogr', outdir + '/check.shp ' + source + ' ' +
                    '-dialect sqlite -sql "SELECT ST_SingleSidedBuffer(geometry, 5.0, 0) AS geometry,* FROM \\"polys2\\"" '
                    + '-explodecollections -f "ESRI Shapefile"'
                ])

            self.assertEqual(
                alg.getConsoleCommands(
                    {
                        'INPUT': source,
                        'DISTANCE': 5,
                        'FIELD': 'total population',
                        'OUTPUT': outdir + '/check.shp'
                    }, context, feedback),
                [
                    'ogr2ogr', outdir + '/check.shp ' + source + ' ' +
                    '-dialect sqlite -sql "SELECT ST_Union(ST_SingleSidedBuffer(geometry, 5.0, 0)) AS geometry,* '
                    +
                    'FROM \\"polys2\\" GROUP BY \\"total population\\"" -f "ESRI Shapefile"'
                ])
Exemple #34
0
    def mergeDataSources2Vrt(self, dataSources, outFile, union=False, relative=False,
                             schema=False, feedback=None):
        '''Function to do the work of merging datasources in a single vrt format

        @param data_sources: Array of path strings
        @param outfile: the output vrt file to generate
        @param relative: Write relative flag. DOES NOT relativise paths. They have to be already relative
        @param schema: Schema flag
        @return: vrt in string format
        '''
        if feedback is None:
            feedback = QgsProcessingFeedback()

        vrt = '<OGRVRTDataSource>'
        if union:
            vrt += '<OGRVRTUnionLayer name="UnionedLayer">'

        total = 100.0 / len(dataSources) if dataSources else 1
        for current, layer in enumerate(dataSources):
            if feedback.isCanceled():
                break

            feedback.setProgress(int(current * total))

            inFile = layer.source()
            srcDS = ogr.Open(inFile, 0)
            if srcDS is None:
                raise QgsProcessingException(
                    self.tr('Invalid datasource: {}'.format(inFile)))

            if schema:
                inFile = '@dummy@'

            for layer in srcDS:
                layerDef = layer.GetLayerDefn()
                layerName = layerDef.GetName()

                vrt += '<OGRVRTLayer name="{}">'.format(self.XmlEsc(layerName))
                vrt += '<SrcDataSource relativeToVRT="{}" shared="{}">{}</SrcDataSource>'.format(1 if relative else 0, not schema, self.XmlEsc(inFile))
                if schema:
                    vrt += '<SrcLayer>@dummy@</SrcLayer>'
                else:
                    vrt += '<SrcLayer>{}</SrcLayer>'.format(self.XmlEsc(layerName))

                vrt += '<GeometryType>{}</GeometryType>'.format(self.GeomType2Name(layerDef.GetGeomType()))

                crs = layer.GetSpatialRef()
                if crs is not None:
                    vrt += '<LayerSRS>{}</LayerSRS>'.format(self.XmlEsc(crs.ExportToWkt()))

                # Process all the fields.
                for fieldIdx in range(layerDef.GetFieldCount()):
                    fieldDef = layerDef.GetFieldDefn(fieldIdx)
                    vrt += '<Field name="{}" type="{}"'.format(self.XmlEsc(fieldDef.GetName()), self.fieldType2Name(fieldDef.GetType()))
                    if not schema:
                        vrt += ' src="{}"'.format(self.XmlEsc(fieldDef.GetName()))
                    if fieldDef.GetWidth() > 0:
                        vrt += ' width="{}"'.format(fieldDef.GetWidth())
                    if fieldDef.GetPrecision() > 0:
                        vrt += ' precision="{}"'.format(fieldDef.GetPrecision())
                    vrt += '/>'

                vrt += '</OGRVRTLayer>'

            srcDS.Destroy()

        if union:
            vrt += '</OGRVRTUnionLayer>'

        vrt += '</OGRVRTDataSource>'

        #TODO: pretty-print XML

        if outFile is not None:
            with codecs.open(outFile, 'w') as f:
                f.write(vrt)

        return vrt
Exemple #35
0
def calculate_zonal_stats(callback,
                          zonal_layer,
                          points_layer,
                          join_fields,
                          output_layer_name,
                          discard_nonmatching=False,
                          predicates=('intersects', ),
                          summaries=('sum', )):
    """
    Leveraging the QGIS processing algorithm 'Join attributes by location
    (summary)', that is described in QGIS as follows:
    This algorithm takes an input vector layer and creates a new vector layer
    that is an extended version of the input one, with additional attributes in
    its attribute table. The additional attributes and their values are taken
    from a second vector layer. A spatial criteria is applied to select the
    values from the second layer that are added to each feature from the first
    layer in the resulting one. The algorithm calculates a statistical summary
    for the values from matching features in the second layer (e.g. maximum
    value, mean value, etc).
    The full description of the algorithm can be obtained as follows:
    processing.algorithmHelp('qgis:joinbylocationsummary') and it includes
    the lists of predicates and summaries.
    The code of the algorithm is here:
    https://github.com/qgis/QGIS/blob
    /483b4ff977e3d36b166fac792254c31e89e3aeae/python/plugins/processing/algs
    /qgis/SpatialJoinSummary.py  # NOQA

    :param callback: function to be called once the aggregation is complete,
        passing the output zonal layer as a parameter
    :param zonal_layer: vector layer containing polygons (or its path)
    :param points_layer: vector layer containing points (or its path)
    :param join_fields: fields for which we want to calculate statistics
        (e.g. structural)
    :param output_layer_name: a memory layer will be produced, named
        'memory:output_layer_name'
    :param discard_nonmatching: discard records which could not be joined
        (in our case, purge zones that contain no loss/damage points)
    :param predicates: geometric predicates (default: 'intersects')
    :param summaries: statistics to be calculated for each join field
        (default: 'sum')

    :returns: it waits until the task is complete or terminated, then it
        calls the callback function, passing the output QgsVectorLayer as
        parameter, or None in case of failure
    """

    processing.Processing.initialize()
    alg = QgsApplication.processingRegistry().algorithmById(
        'qgis:joinbylocationsummary')
    # make sure to use the actual lists of predicates and summaries as defined
    # in the algorithm when it is instantiated
    predicate_keys = [predicate[0] for predicate in alg.predicates]
    PREDICATES = dict(zip(predicate_keys, range(len(predicate_keys))))
    summary_keys = [statistic[0] for statistic in alg.statistics]
    SUMMARIES = dict(zip(summary_keys, range(len(summary_keys))))

    context = QgsProcessingContext()
    feedback = QgsProcessingFeedback()

    params = {
        'DISCARD_NONMATCHING': discard_nonmatching,
        'INPUT': zonal_layer,
        'JOIN': points_layer,
        'PREDICATE': [PREDICATES[predicate] for predicate in predicates],
        'JOIN_FIELDS': join_fields,
        'SUMMARIES': [SUMMARIES[summary] for summary in summaries],
        'OUTPUT': 'memory:%s' % output_layer_name
    }

    task = QgsProcessingAlgRunnerTask(alg, params, context, feedback)
    task.executed.connect(partial(task_finished, context, callback))
    QgsApplication.taskManager().addTask(task)

    while True:
        # the user can "cancel" the task, interrupting this loop
        QgsApplication.processEvents()
        # status can be queued, onhold, running, complete, terminated
        if task.status() > 2:  # Complete or terminated
            return
        time.sleep(0.1)
Exemple #36
0
def test_context(outputdir, data):
    """ Context with Copy layer
    """
    alg = _find_algorithm('pyqgiswps_test:testcopylayer')

    inputs = {
        p.name(): [parse_input_definition(p)]
        for p in alg.parameterDefinitions()
    }
    outputs = {
        p.name(): parse_output_definition(p)
        for p in alg.outputDefinitions()
    }

    inputs['INPUT'][0].data = 'france_parts'
    inputs['OUTPUT'][0].data = 'france_parts_2'

    context = ProcessingContext(str(outputdir), 'france_parts.qgs')
    feedback = QgsProcessingFeedback()

    parameters = dict(
        input_to_processing(ident, inp, alg, context)
        for ident, inp in inputs.items())

    assert isinstance(parameters['OUTPUT'], QgsProcessingOutputLayerDefinition)

    destination = get_valid_filename(alg.id())

    context.wms_url = "http://localhost/wms/MAP=test/{name}.qgs".format(
        name=destination)
    # Run algorithm
    with chdir(outputdir):
        results = run_algorithm(alg,
                                parameters=parameters,
                                feedback=feedback,
                                context=context,
                                outputs=outputs)

    assert context.destination_project.count() == 1

    # Save destination project
    ok = context.write_result(context.workdir, destination)

    assert ok
    assert context.destination_project.fileName() == str(
        outputdir / (destination + '.qgs'))

    # WFS configuration inserted
    WFSLayers = context.destination_project.readListEntry('WFSLayers', '/')[0]
    assert len(WFSLayers) != 0

    # All Vector Layers has been published in WFS
    mapLayers = context.destination_project.mapLayers()
    assert len(WFSLayers) == len([
        lid for lid, lyr in mapLayers.items()
        if lyr.type() == QgsMapLayer.VectorLayer
    ])

    # Verifying th WFS configuration
    for lid in WFSLayers:
        lyr = context.destination_project.mapLayer(lid)
        # Is the WFS layer id references a Map Layer
        assert lyr
        # Is the WFS layer id references a Vector Layer
        assert lyr.type() == QgsMapLayer.VectorLayer
        # The WFS layer precision is defined
        assert context.destination_project.readNumEntry(
            "WFSLayersPrecision", "/" + lid)[0] == 6
Exemple #37
0
def handleAlgorithmResults(alg, context, feedback=None, showResults=True, parameters={}):
    wrongLayers = []
    if feedback is None:
        feedback = QgsProcessingFeedback()
    feedback.setProgressText(QCoreApplication.translate('Postprocessing', 'Loading resulting layers'))
    i = 0

    for l, details in context.layersToLoadOnCompletion().items():
        if feedback.isCanceled():
            return False

        if len(context.layersToLoadOnCompletion()) > 2:
            # only show progress feedback if we're loading a bunch of layers
            feedback.setProgress(100 * i / float(len(context.layersToLoadOnCompletion())))
        try:
            layer = QgsProcessingUtils.mapLayerFromString(l, context, typeHint=details.layerTypeHint)
            if layer is not None:
                set_layer_name(layer, details)

                '''If running a model, the execution will arrive here when an algorithm that is part of
                that model is executed. We check if its output is a final otuput of the model, and
                adapt the output name accordingly'''
                outputName = details.outputName
                expcontext = QgsExpressionContext()
                scope = QgsExpressionContextScope()
                expcontext.appendScope(scope)
                for out in alg.outputDefinitions():
                    if out.name() not in parameters:
                        continue
                    outValue = parameters[out.name()]
                    if hasattr(outValue, "sink"):
                        outValue = outValue.sink.valueAsString(expcontext)[0]
                    else:
                        outValue = str(outValue)
                    if outValue == l:
                        outputName = out.name()
                        break
                style = None
                if outputName:
                    style = RenderingStyles.getStyle(alg.id(), outputName)
                if style is None:
                    if layer.type() == QgsMapLayer.RasterLayer:
                        style = ProcessingConfig.getSetting(ProcessingConfig.RASTER_STYLE)
                    else:
                        if layer.geometryType() == QgsWkbTypes.PointGeometry:
                            style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_POINT_STYLE)
                        elif layer.geometryType() == QgsWkbTypes.LineGeometry:
                            style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_LINE_STYLE)
                        else:
                            style = ProcessingConfig.getSetting(ProcessingConfig.VECTOR_POLYGON_STYLE)
                if style:
                    layer.loadNamedStyle(style)

                details.project.addMapLayer(context.temporaryLayerStore().takeMapLayer(layer))

                if details.postProcessor():
                    details.postProcessor().postProcessLayer(layer, context, feedback)

            else:
                wrongLayers.append(str(l))
        except Exception:
            QgsMessageLog.logMessage(QCoreApplication.translate('Postprocessing', "Error loading result layer:") + "\n" + traceback.format_exc(), 'Processing', Qgis.Critical)
            wrongLayers.append(str(l))
        i += 1

    feedback.setProgress(100)

    if wrongLayers:
        msg = QCoreApplication.translate('Postprocessing', "The following layers were not correctly generated.")
        msg += "<ul>" + "".join(["<li>%s</li>" % lay for lay in wrongLayers]) + "</ul>"
        msg += QCoreApplication.translate('Postprocessing', "You can check the 'Log Messages Panel' in QGIS main window to find more information about the execution of the algorithm.")
        feedback.reportError(msg)

    return len(wrongLayers) == 0
def main():
    """reads in a pre-processed groundwater layer, with recharge-discharge (CSV) and returns tif
    
    Args:
        state(str): state for which well elevations must be obtained
        season(str): e.g. rech-96, disc-96
        
    Returns:
        None: well elevations with locations stored in CSV as SHP
    
    """
    state = sys.argv[1]
    season = sys.argv[2]
    dataPath = root.joinpath("data","groundwater")
    metaPath = root.joinpath("outputs","groundwater","csv",state+"_metadata.log")
    outputsPath = root.joinpath("outputs","groundwater")
    
    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s %(message)s',
                        datefmt='%m/%d/%Y %I:%M:%S %p',
                        handlers=[logging.FileHandler(str(metaPath))],
                       )
    
    logging.info("get Recharge-Discharge for '%s' dataset",state)

    # Initialize QGIS Application
    QgsApplication.setPrefixPath("G:\\Users\\Craig\\miniconda3\\envs\\geo_env\\Library\\python\\qgis", True)
    qgs = QgsApplication([], False)
    qgs.initQgis()
    
    # Append the path where QGIS processing plugin can be found
    sys.path.append('G:\\Users\\Craig\\miniconda3\\envs\\geo_env\\Library\\python\\plugins')
    import processing
    from processing.core.Processing import Processing
    Processing.initialize()
    feedback = QgsProcessingFeedback()
    
    QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms())

    # Get file with recharge-discharge values from previous step
    vectorPath = outputsPath.joinpath("shapefiles",state+"_processed_wRD.shp")
    print(vectorPath,vectorPath.exists())
    vLayer = QgsVectorLayer(str(vectorPath), 'well_rech_disc_layer', 'ogr') #.setSubsetString(season + " IS NOT NULL")
    print("islayer valid:", vLayer.isValid())
    
    # subset layer for the chosen season and choose only non null values
    filter = "\"" + season + "\"" + " IS NOT NULL"
    expr = QgsExpression(filter)
    subset = vLayer.getFeatures(QgsFeatureRequest(expr))
    vLayer.selectByIds([k.id() for k in subset])  # why didn't direct selection work? addFeature (false)
    print(vLayer.selectedFeatureCount())
    
    # write subsetted layer to shapefile
    subsetPath = outputsPath.joinpath("shapefiles","noNulls",state+"_"+season+"_noNulls.shp")
    _writer = QgsVectorFileWriter.writeAsVectorFormat(vLayer, str(subsetPath), "utf-8", vLayer.crs(), "ESRI Shapefile", onlySelected=True)
    
    # import subsetted layer
    subLayer = QgsVectorLayer(str(subsetPath), 'well_rech_disc_layer_nonulls', 'ogr') 
    print("is sub layer valid:", subLayer.isValid())
    
    # declare params for grid layer 
    # https://gdal.org/tutorials/gdal_grid_tut.html
    params = {
        'INPUT':subLayer,
        'POWER':2,    # FOR gridinversedistance
#         'RADIUS':0.25,    # FOR gridinversedistancenearestneighbor / gridlinear
#         'RADIUS_1':0.25,    # FOR gridinversedistance / gridnearestneighbor / gridaverage
#         'RADIUS_2':0.25,    # FOR gridinversedistance  /  gridnearestneighbor / gridaverage
        'MAX_POINTS':12,    # FOR gridinversedistance 
        'MIN_POINTS':1,    # FOR gridinversedistance / gridaverage
        'NODATA': -9999,
        'Z_FIELD':season,
        'OUTPUT':str(outputsPath.joinpath("tif","idw",state+"_"+season+"_grid_id_min_1_max_12_nonulls.tif"))
    }
    
    res = processing.run("gdal:gridinversedistance",params,feedback=feedback)
    print(res['OUTPUT'])
Exemple #39
0
    def processAlgorithm(self, parameters: Dict[str, Any],
                         context: QgsProcessingContext,
                         feedback: QgsProcessingFeedback) -> Union[dict, Dict[str, Any]]:
        result = dict()

        canalsfield: str = self.parameterAsFields(parameters, self.CANALSFIELD, context)[0]
        pointsfield: str = self.parameterAsFields(parameters, self.POINTSFIELD, context)[0]

        typefield: str = self.parameterAsFields(parameters, self.TYPEFIELD, context)[0]
        typevalue: str = self.parameterAsString(parameters, self.TYPEVALUE, context)

        tolerancepoints: float = self.parameterAsDouble(parameters, self.TOLERANCEPOINTS, context)
        tolerancecanals: float = self.parameterAsDouble(parameters, self.TOLERANCECANALS, context)

        model_feedback = QgsProcessingMultiStepFeedback(3, feedback)

        if feedback.isCanceled():
            return result

        snappedcanals_out_name = 'native:splitwithlines_1:{}'.format(self.SNAPPEDCANALS)
        intersect_out_name = 'native:fieldcalculator_1:INTERSECTIONS'
        points_with_uuid_name = 'qgis:advancedpythonfieldcalculator_1:{}'.format(self.POINTSWITHUUID)

        proc_result = processing.run(self.snap_lines.model(),
                                     {
                                         'CANALS': parameters[self.CANALS],
                                         'DELIVERYPOINTS': parameters[self.DELIVERYPOINTS],
                                         'TOLERANCECANALS': tolerancecanals,
                                         'TYPEFIELD': typefield,
                                         'TYPEVALUE': typevalue,
                                         'VERBOSE_LOG': True,
                                         snappedcanals_out_name: 'TEMPORARY_OUTPUT',
                                         intersect_out_name: 'TEMPORARY_OUTPUT',
                                         points_with_uuid_name: 'TEMPORARY_OUTPUT',
                                     },
                                     context=context,
                                     feedback=model_feedback,
                                     is_child_algorithm=True)
        # TODO SNAPPEDCANALS добавить в result в конце, когда они будут порезаны по пересечениям

        print("Main processing complete")

        model_feedback.setCurrentStep(1)

        if feedback.isCanceled():
            return result

        snapped_canals: QgsVectorLayer = context.takeResultLayer(
            proc_result[snappedcanals_out_name])

        intersections: QgsVectorLayer = context.takeResultLayer(
            proc_result[intersect_out_name])

        points_with_uuid: QgsVectorLayer = context.takeResultLayer(
            proc_result[points_with_uuid_name])

        (snapped_canals_sink, snapped_canals_id) = self.parameterAsSink(parameters, self.SNAPPEDCANALS,
                                                                        context, snapped_canals.fields(),
                                                                        snapped_canals.wkbType(),
                                                                        snapped_canals.sourceCrs())

        (points_with_uuid_sink, points_with_uuid_id) = self.parameterAsSink(parameters, self.POINTSWITHUUID,
                                                                            context, points_with_uuid.fields(),
                                                                            points_with_uuid.wkbType(),
                                                                            points_with_uuid.sourceCrs())

        snapped_canals_sink.addFeatures(snapped_canals.getFeatures())
        points_with_uuid_sink.addFeatures(points_with_uuid.getFeatures())

        result.update({
            self.SNAPPEDCANALS: snapped_canals_id,
            self.POINTSWITHUUID: points_with_uuid_id,
        })

        snapped_points_layers = []

        for line_name in points_with_uuid.uniqueValues(points_with_uuid.fields().indexFromName(pointsfield)):
            line_expression = QgsExpression().createFieldEqualityExpression(canalsfield, line_name)
            line_request = QgsFeatureRequest()
            line_request.setFilterExpression(line_expression)

            point_expression = QgsExpression().createFieldEqualityExpression(pointsfield, line_name)
            point_request = QgsFeatureRequest()
            point_request.setFilterExpression(point_expression)

            subset_snapped_canals = snapped_canals.materialize(line_request, model_feedback)
            subset_points_with_uuid = points_with_uuid.materialize(point_request, model_feedback)

            snapped_points_layers.append(
                processing.run("native:snapgeometries",
                               {
                                   'INPUT': subset_points_with_uuid,
                                   'REFERENCE_LAYER': subset_snapped_canals,
                                   'TOLERANCE': tolerancepoints,
                                   'BEHAVIOR': 1,
                                   'OUTPUT': 'TEMPORARY_OUTPUT'
                               },
                               context=context,
                               # feedback=model_feedback,
                               is_child_algorithm=True)['OUTPUT']
            )

        print("Cycle complete")

        model_feedback.setCurrentStep(2)

        if feedback.isCanceled():
            return result

        snapped_points_layers.append(intersections)

        snapped_points_id = processing.run("native:mergevectorlayers",
                                           {
                                               'LAYERS': snapped_points_layers,
                                               'CRS': points_with_uuid.crs(),
                                               'OUTPUT': 'TEMPORARY_OUTPUT'
                                           },
                                           context=context,
                                           feedback=model_feedback,
                                           is_child_algorithm=True)['OUTPUT']

        snapped_points: QgsVectorLayer = context.takeResultLayer(snapped_points_id)

        (snapped_points_sink, snapped_points_id) = self.parameterAsSink(parameters, self.SNAPPEDPOINTS,
                                                                        context, snapped_points.fields(),
                                                                        snapped_points.wkbType(),
                                                                        snapped_points.sourceCrs())

        snapped_points_sink.addFeatures(snapped_points.getFeatures())

        print("Vectors merged")

        model_feedback.setCurrentStep(3)

        if feedback.isCanceled():
            return result

        result.update({
            self.SNAPPEDPOINTS: snapped_points_id,
        })

        print(result)
        return result
Exemple #40
0
    def runGdal(commands, feedback=None):
        if feedback is None:
            feedback = QgsProcessingFeedback()
        envval = os.getenv('PATH')
        # We need to give some extra hints to get things picked up on OS X
        isDarwin = False
        try:
            isDarwin = platform.system() == 'Darwin'
        except IOError:  # https://travis-ci.org/m-kuhn/QGIS#L1493-L1526
            pass
        if isDarwin and os.path.isfile(
                os.path.join(QgsApplication.prefixPath(), "bin", "gdalinfo")):
            # Looks like there's a bundled gdal. Let's use it.
            os.environ['PATH'] = "{}{}{}".format(
                os.path.join(QgsApplication.prefixPath(), "bin"), os.pathsep,
                envval)
            os.environ['DYLD_LIBRARY_PATH'] = os.path.join(
                QgsApplication.prefixPath(), "lib")
        else:
            # Other platforms should use default gdal finder codepath
            settings = QgsSettings()
            path = settings.value('/GdalTools/gdalPath', '')
            if not path.lower() in envval.lower().split(os.pathsep):
                envval += '{}{}'.format(os.pathsep, path)
                os.putenv('PATH', envval)

        fused_command = ' '.join([str(c) for c in commands])
        QgsMessageLog.logMessage(fused_command, 'Processing', Qgis.Info)
        feedback.pushInfo(GdalUtils.tr('GDAL command:'))
        feedback.pushCommandInfo(fused_command)
        feedback.pushInfo(GdalUtils.tr('GDAL command output:'))

        loglines = [GdalUtils.tr('GDAL execution console output')]

        def on_stdout(ba):
            val = ba.data().decode('UTF-8')
            # catch progress reports
            if val == '100 - done.':
                on_stdout.progress = 100
                feedback.setProgress(on_stdout.progress)
            elif val in ('0', '10', '20', '30', '40', '50', '60', '70', '80',
                         '90'):
                on_stdout.progress = int(val)
                feedback.setProgress(on_stdout.progress)
            elif val == '.':
                on_stdout.progress += 2.5
                feedback.setProgress(on_stdout.progress)

            on_stdout.buffer += val
            if on_stdout.buffer.endswith('\n') or on_stdout.buffer.endswith(
                    '\r'):
                # flush buffer
                feedback.pushConsoleInfo(on_stdout.buffer.rstrip())
                loglines.append(on_stdout.buffer.rstrip())
                on_stdout.buffer = ''

        on_stdout.progress = 0
        on_stdout.buffer = ''

        def on_stderr(ba):
            val = ba.data().decode('UTF-8')
            on_stderr.buffer += val

            if on_stderr.buffer.endswith('\n') or on_stderr.buffer.endswith(
                    '\r'):
                # flush buffer
                feedback.reportError(on_stderr.buffer.rstrip())
                loglines.append(on_stderr.buffer.rstrip())
                on_stderr.buffer = ''

        on_stderr.buffer = ''

        command, *arguments = QgsRunProcess.splitCommand(fused_command)
        proc = QgsBlockingProcess(command, arguments)
        proc.setStdOutHandler(on_stdout)
        proc.setStdErrHandler(on_stderr)

        res = proc.run(feedback)
        if feedback.isCanceled() and res != 0:
            feedback.pushInfo(
                GdalUtils.tr('Process was canceled and did not complete'))
        elif not feedback.isCanceled() and proc.exitStatus(
        ) == QProcess.CrashExit:
            raise QgsProcessingException(
                GdalUtils.tr('Process was unexpectedly terminated'))
        elif res == 0:
            feedback.pushInfo(GdalUtils.tr('Process completed successfully'))
        else:
            feedback.reportError(
                GdalUtils.tr('Process returned error code {}').format(res))

        return loglines
Exemple #41
0
    def runAlgorithm(algOrName, parameters, onFinish=None, feedback=None, context=None):
        if isinstance(algOrName, QgsProcessingAlgorithm):
            alg = algOrName
        else:
            alg = QgsApplication.processingRegistry().createAlgorithmById(algOrName)

        if feedback is None:
            feedback = QgsProcessingFeedback()

        if alg is None:
            msg = Processing.tr('Error: Algorithm {0} not found\n').format(algOrName)
            feedback.reportError(msg)
            raise QgsProcessingException(msg)

        if context is None:
            context = dataobjects.createContext(feedback)

        if context.feedback() is None:
            context.setFeedback(feedback)

        ok, msg = alg.checkParameterValues(parameters, context)
        if not ok:
            msg = Processing.tr('Unable to execute algorithm\n{0}').format(msg)
            feedback.reportError(msg)
            raise QgsProcessingException(msg)

        if not alg.validateInputCrs(parameters, context):
            feedback.pushInfo(
                Processing.tr('Warning: Not all input layers use the same CRS.\nThis can cause unexpected results.'))

        ret, results = execute(alg, parameters, context, feedback)
        if ret:
            feedback.pushInfo(
                Processing.tr('Results: {}').format(results))

            if onFinish is not None:
                onFinish(alg, context, feedback)
            else:
                # auto convert layer references in results to map layers
                for out in alg.outputDefinitions():
                    if out.name() not in results:
                        continue

                    if isinstance(out, (QgsProcessingOutputVectorLayer, QgsProcessingOutputRasterLayer, QgsProcessingOutputMapLayer)):
                        result = results[out.name()]
                        if not isinstance(result, QgsMapLayer):
                            layer = context.takeResultLayer(result) # transfer layer ownership out of context
                            if layer:
                                results[out.name()] = layer # replace layer string ref with actual layer (+ownership)
                    elif isinstance(out, QgsProcessingOutputMultipleLayers):
                        result = results[out.name()]
                        if result:
                            layers_result = []
                            for l in result:
                                if not isinstance(result, QgsMapLayer):
                                    layer = context.takeResultLayer(l) # transfer layer ownership out of context
                                    if layer:
                                        layers_result.append(layer)
                                    else:
                                        layers_result.append(l)
                                else:
                                    layers_result.append(l)

                            results[out.name()] = layers_result # replace layers strings ref with actual layers (+ownership)

        else:
            msg = Processing.tr("There were errors executing the algorithm.")
            feedback.reportError(msg)
            raise QgsProcessingException(msg)

        if isinstance(feedback, MessageBarProgress):
            feedback.close()
        return results
Exemple #42
0
    def testGdalTranslate(self):
        context = QgsProcessingContext()
        feedback = QgsProcessingFeedback()
        source = os.path.join(testDataPath, 'dem.tif')
        translate_alg = translate()
        translate_alg.initAlgorithm()

        # with no NODATA value
        self.assertEqual(
            translate_alg.getConsoleCommands(
                {
                    'INPUT': source,
                    'OUTPUT': 'd:/temp/check.jpg'
                }, context, feedback),
            [
                'gdal_translate',
                '-ot Float32 -of JPEG ' + source + ' ' + 'd:/temp/check.jpg'
            ])
        # with NODATA value
        self.assertEqual(
            translate_alg.getConsoleCommands(
                {
                    'INPUT': source,
                    'NODATA': 9999,
                    'OUTPUT': 'd:/temp/check.jpg'
                }, context, feedback),
            [
                'gdal_translate', '-a_nodata 9999.0 ' +
                '-ot Float32 -of JPEG ' + source + ' ' + 'd:/temp/check.jpg'
            ])
        # with "0" NODATA value
        self.assertEqual(
            translate_alg.getConsoleCommands(
                {
                    'INPUT': source,
                    'NODATA': 0,
                    'OUTPUT': 'd:/temp/check.jpg'
                }, context, feedback),
            [
                'gdal_translate', '-a_nodata 0.0 ' + '-ot Float32 -of JPEG ' +
                source + ' ' + 'd:/temp/check.jpg'
            ])
        # with target srs
        self.assertEqual(
            translate_alg.getConsoleCommands(
                {
                    'INPUT': source,
                    'TARGET_CRS': 'EPSG:3111',
                    'OUTPUT': 'd:/temp/check.jpg'
                }, context, feedback),
            [
                'gdal_translate', '-a_srs EPSG:3111 ' +
                '-ot Float32 -of JPEG ' + source + ' ' + 'd:/temp/check.jpg'
            ])
        # with target srs
        self.assertEqual(
            translate_alg.getConsoleCommands(
                {
                    'INPUT': source,
                    'TARGET_CRS': 'EPSG:3111',
                    'OUTPUT': 'd:/temp/check.jpg'
                }, context, feedback),
            [
                'gdal_translate', '-a_srs EPSG:3111 ' +
                '-ot Float32 -of JPEG ' + source + ' ' + 'd:/temp/check.jpg'
            ])
        # with copy subdatasets
        self.assertEqual(
            translate_alg.getConsoleCommands(
                {
                    'INPUT': source,
                    'COPY_SUBDATASETS': True,
                    'OUTPUT': 'd:/temp/check.tif'
                }, context, feedback), [
                    'gdal_translate', '-sds ' + '-ot Float32 -of GTiff ' +
                    source + ' ' + 'd:/temp/check.tif'
                ])
def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exceptions=False):
    """Executes an algorithm modifying features in-place in the input layer.

    :param alg: algorithm to run
    :type alg: QgsProcessingAlgorithm
    :param parameters: parameters of the algorithm
    :type parameters: dict
    :param context: context, defaults to None
    :type context: QgsProcessingContext, optional
    :param feedback: feedback, defaults to None
    :type feedback: QgsProcessingFeedback, optional
    :param raise_exceptions: useful for testing, if True exceptions are raised, normally exceptions will be forwarded to the feedback
    :type raise_exceptions: boo, default to False
    :raises QgsProcessingException: raised when there is no active layer, or it cannot be made editable
    :return: a tuple with true if success and results
    :rtype: tuple
    """

    if feedback is None:
        feedback = QgsProcessingFeedback()
    if context is None:
        context = dataobjects.createContext(feedback)

    # Only feature based algs have sourceFlags
    try:
        if alg.sourceFlags() & QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks:
            context.setInvalidGeometryCheck(QgsFeatureRequest.GeometryNoCheck)
    except AttributeError:
        pass

    active_layer = parameters['INPUT']

    # Run some checks and prepare the layer for in-place execution by:
    # - getting the active layer and checking that it is a vector
    # - making the layer editable if it was not already
    # - selecting all features if none was selected
    # - checking in-place support for the active layer/alg/parameters
    # If one of the check fails and raise_exceptions is True an exception
    # is raised, else the execution is aborted and the error reported in
    # the feedback
    try:
        if active_layer is None:
            raise QgsProcessingException(tr("There is not active layer."))

        if not isinstance(active_layer, QgsVectorLayer):
            raise QgsProcessingException(tr("Active layer is not a vector layer."))

        if not active_layer.isEditable():
            if not active_layer.startEditing():
                raise QgsProcessingException(tr("Active layer is not editable (and editing could not be turned on)."))

        if not alg.supportInPlaceEdit(active_layer):
            raise QgsProcessingException(tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."))
    except QgsProcessingException as e:
        if raise_exceptions:
            raise e
        QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.Critical)
        if feedback is not None:
            feedback.reportError(getattr(e, 'msg', str(e)), fatalError=True)
        return False, {}

    if not active_layer.selectedFeatureIds():
        active_layer.selectAll()

    # Make sure we are working on selected features only
    parameters['INPUT'] = QgsProcessingFeatureSourceDefinition(active_layer.id(), True)
    parameters['OUTPUT'] = 'memory:'

    req = QgsFeatureRequest(QgsExpression(r"$id < 0"))
    req.setFlags(QgsFeatureRequest.NoGeometry)
    req.setSubsetOfAttributes([])

    # Start the execution
    # If anything goes wrong and raise_exceptions is True an exception
    # is raised, else the execution is aborted and the error reported in
    # the feedback
    try:
        new_feature_ids = []

        active_layer.beginEditCommand(alg.displayName())

        # Checks whether the algorithm has a processFeature method
        if hasattr(alg, 'processFeature'):  # in-place feature editing
            # Make a clone or it will crash the second time the dialog
            # is opened and run
            alg = alg.create()
            if not alg.prepare(parameters, context, feedback):
                raise QgsProcessingException(tr("Could not prepare selected algorithm."))
            # Check again for compatibility after prepare
            if not alg.supportInPlaceEdit(active_layer):
                raise QgsProcessingException(tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."))
            field_idxs = range(len(active_layer.fields()))
            iterator_req = QgsFeatureRequest(active_layer.selectedFeatureIds())
            iterator_req.setInvalidGeometryCheck(context.invalidGeometryCheck())
            feature_iterator = active_layer.getFeatures(iterator_req)
            step = 100 / len(active_layer.selectedFeatureIds()) if active_layer.selectedFeatureIds() else 1
            for current, f in enumerate(feature_iterator):
                feedback.setProgress(current * step)
                if feedback.isCanceled():
                    break

                # need a deep copy, because python processFeature implementations may return
                # a shallow copy from processFeature
                input_feature = QgsFeature(f)
                new_features = alg.processFeature(input_feature, context, feedback)
                new_features = QgsVectorLayerUtils.makeFeaturesCompatible(new_features, active_layer)

                if len(new_features) == 0:
                    active_layer.deleteFeature(f.id())
                elif len(new_features) == 1:
                    new_f = new_features[0]
                    if not f.geometry().equals(new_f.geometry()):
                        active_layer.changeGeometry(f.id(), new_f.geometry())
                    if f.attributes() != new_f.attributes():
                        active_layer.changeAttributeValues(f.id(), dict(zip(field_idxs, new_f.attributes())), dict(zip(field_idxs, f.attributes())))
                    new_feature_ids.append(f.id())
                else:
                    active_layer.deleteFeature(f.id())
                    # Get the new ids
                    old_ids = set([f.id() for f in active_layer.getFeatures(req)])
                    if not active_layer.addFeatures(new_features):
                        raise QgsProcessingException(tr("Error adding processed features back into the layer."))
                    new_ids = set([f.id() for f in active_layer.getFeatures(req)])
                    new_feature_ids += list(new_ids - old_ids)

            results, ok = {}, True

        else:  # Traditional 'run' with delete and add features cycle

            # There is no way to know if some features have been skipped
            # due to invalid geometries
            if context.invalidGeometryCheck() == QgsFeatureRequest.GeometrySkipInvalid:
                selected_ids = active_layer.selectedFeatureIds()
            else:
                selected_ids = []

            results, ok = alg.run(parameters, context, feedback)

            if ok:
                result_layer = QgsProcessingUtils.mapLayerFromString(results['OUTPUT'], context)
                # TODO: check if features have changed before delete/add cycle

                new_features = []

                # Check if there are any skipped features
                if context.invalidGeometryCheck() == QgsFeatureRequest.GeometrySkipInvalid:
                    missing_ids = list(set(selected_ids) - set(result_layer.allFeatureIds()))
                    if missing_ids:
                        for f in active_layer.getFeatures(QgsFeatureRequest(missing_ids)):
                            if not f.geometry().isGeosValid():
                                new_features.append(f)

                active_layer.deleteFeatures(active_layer.selectedFeatureIds())

                for f in result_layer.getFeatures():
                    new_features.extend(QgsVectorLayerUtils.
                                        makeFeaturesCompatible([f], active_layer))

                # Get the new ids
                old_ids = set([f.id() for f in active_layer.getFeatures(req)])
                if not active_layer.addFeatures(new_features):
                    raise QgsProcessingException(tr("Error adding processed features back into the layer."))
                new_ids = set([f.id() for f in active_layer.getFeatures(req)])
                new_feature_ids += list(new_ids - old_ids)

        active_layer.endEditCommand()

        if ok and new_feature_ids:
            active_layer.selectByIds(new_feature_ids)
        elif not ok:
            active_layer.rollBack()

        return ok, results

    except QgsProcessingException as e:
        active_layer.endEditCommand()
        active_layer.rollBack()
        if raise_exceptions:
            raise e
        QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.Critical)
        if feedback is not None:
            feedback.reportError(getattr(e, 'msg', str(e)), fatalError=True)

    return False, {}
Exemple #44
0
    def get_missing_boundary_points_in_boundaries(self, db,
                                                  boundary_point_layer,
                                                  boundary_layer):
        res = dict()

        feedback = QgsProcessingFeedback()
        extracted_vertices = processing.run("native:extractvertices", {
            'INPUT': boundary_layer,
            'OUTPUT': 'memory:'
        },
                                            feedback=feedback)
        extracted_vertices_layer = extracted_vertices['OUTPUT']

        # From vertices layer, get points with no overlap
        overlapping_points = self.geometry.get_overlapping_points(
            extracted_vertices_layer)

        extracted_vertices_ids = [
            feature.id() for feature in extracted_vertices_layer.getFeatures()
        ]

        # Unpack list of lists into single list
        overlapping_point_ids = [
            item for sublist in overlapping_points for item in sublist
        ]

        # Unpack list of lists into single list selecting only the first point
        # per list. That means, discard overlapping points, and only keep one
        cleaned_point_ids = [sublist[0] for sublist in overlapping_points]

        # All vertices (even duplicated, due to the alg we use), minus all
        # overlapping ids, plus only one of the overlapping ids
        # This gets a list of all vertex ids with no duplicates
        no_duplicate_ids = list(
            set(extracted_vertices_ids) -
            set(overlapping_point_ids)) + cleaned_point_ids

        if boundary_point_layer.featureCount() == 0:
            # Return all extracted and cleaned vertices
            for feature in extracted_vertices_layer.getFeatures(
                    no_duplicate_ids):
                if feature[db.names.T_ID_F] in res:
                    res[feature[db.names.T_ID_F]].append(feature.geometry())
                else:
                    res[feature[db.names.T_ID_F]] = [feature.geometry()]

            return res

        index = QgsSpatialIndex(
            boundary_point_layer.getFeatures(
                QgsFeatureRequest().setSubsetOfAttributes([])), feedback)

        for feature in extracted_vertices_layer.getFeatures(no_duplicate_ids):
            if feature.hasGeometry():
                geom = feature.geometry()
                diff_geom = QgsGeometry(geom)

                # Use a custom bbox to include very near but not exactly equal points
                point_vert = {
                    'x': diff_geom.asPoint().x(),
                    'y': diff_geom.asPoint().y()
                }
                bbox = QgsRectangle(
                    QgsPointXY(point_vert['x'] - 0.0001,
                               point_vert['y'] - 0.0001),
                    QgsPointXY(point_vert['x'] + 0.0001,
                               point_vert['y'] + 0.0001))
                intersects = index.intersects(bbox)

                if not intersects:
                    if feature[db.names.T_ID_F] in res:
                        res[feature[db.names.T_ID_F]].append(diff_geom)
                    else:
                        res[feature[db.names.T_ID_F]] = [diff_geom]
        return res
Exemple #45
0
    def check_algorithm(self, name, defs):
        """
        Will run an algorithm definition and check if it generates the expected result
        :param name: The identifier name used in the test output heading
        :param defs: A python dict containing a test algorithm definition
        """
        self.vector_layer_params = {}
        QgsProject.instance().removeAllMapLayers()

        params = self.load_params(defs['params'])

        print('Running alg: "{}"'.format(defs['algorithm']))
        alg = QgsApplication.processingRegistry().createAlgorithmById(
            defs['algorithm'])

        parameters = {}
        if isinstance(params, list):
            for param in zip(alg.parameterDefinitions(), params):
                parameters[param[0].name()] = param[1]
        else:
            for k, p in list(params.items()):
                parameters[k] = p

        for r, p in list(defs['results'].items()):
            if not 'in_place_result' in p or not p['in_place_result']:
                parameters[r] = self.load_result_param(p)

        expectFailure = False
        if 'expectedFailure' in defs:
            exec(('\n'.join(defs['expectedFailure'][:-1])), globals(),
                 locals())
            expectFailure = eval(defs['expectedFailure'][-1])

        # ignore user setting for invalid geometry handling
        context = QgsProcessingContext()
        context.setProject(QgsProject.instance())

        if 'skipInvalid' in defs and defs['skipInvalid']:
            context.setInvalidGeometryCheck(
                QgsFeatureRequest.GeometrySkipInvalid)

        feedback = QgsProcessingFeedback()

        print('Algorithm parameters are {}'.format(parameters))

        # first check that algorithm accepts the parameters we pass...
        ok, msg = alg.checkParameterValues(parameters, context)
        self.assertTrue(
            ok,
            'Algorithm failed checkParameterValues with result {}'.format(msg))

        if expectFailure:
            try:
                results, ok = alg.run(parameters, context, feedback)
                self.check_results(results, context, parameters,
                                   defs['results'])
                if ok:
                    raise _UnexpectedSuccess
            except Exception:
                pass
        else:
            results, ok = alg.run(parameters, context, feedback)
            self.assertTrue(
                ok, 'params: {}, results: {}'.format(parameters, results))
            self.check_results(results, context, parameters, defs['results'])
Exemple #46
0
def execute_in_place_run(alg,
                         parameters,
                         context=None,
                         feedback=None,
                         raise_exceptions=False):
    """Executes an algorithm modifying features in-place in the input layer.

    :param alg: algorithm to run
    :type alg: QgsProcessingAlgorithm
    :param parameters: parameters of the algorithm
    :type parameters: dict
    :param context: context, defaults to None
    :type context: QgsProcessingContext, optional
    :param feedback: feedback, defaults to None
    :type feedback: QgsProcessingFeedback, optional
    :param raise_exceptions: useful for testing, if True exceptions are raised, normally exceptions will be forwarded to the feedback
    :type raise_exceptions: boo, default to False
    :raises QgsProcessingException: raised when there is no active layer, or it cannot be made editable
    :return: a tuple with true if success and results
    :rtype: tuple
    """

    if feedback is None:
        feedback = QgsProcessingFeedback()
    if context is None:
        context = dataobjects.createContext(feedback)

    # Only feature based algs have sourceFlags
    try:
        if alg.sourceFlags(
        ) & QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks:
            context.setInvalidGeometryCheck(QgsFeatureRequest.GeometryNoCheck)
    except AttributeError:
        pass

    active_layer = parameters['INPUT']

    # Run some checks and prepare the layer for in-place execution by:
    # - getting the active layer and checking that it is a vector
    # - making the layer editable if it was not already
    # - selecting all features if none was selected
    # - checking in-place support for the active layer/alg/parameters
    # If one of the check fails and raise_exceptions is True an exception
    # is raised, else the execution is aborted and the error reported in
    # the feedback
    try:
        if active_layer is None:
            raise QgsProcessingException(tr("There is not active layer."))

        if not isinstance(active_layer, QgsVectorLayer):
            raise QgsProcessingException(
                tr("Active layer is not a vector layer."))

        if not active_layer.isEditable():
            if not active_layer.startEditing():
                raise QgsProcessingException(
                    tr("Active layer is not editable (and editing could not be turned on)."
                       ))

        if not alg.supportInPlaceEdit(active_layer):
            raise QgsProcessingException(
                tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."
                   ))
    except QgsProcessingException as e:
        if raise_exceptions:
            raise e
        QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing',
                                 Qgis.Critical)
        if feedback is not None:
            feedback.reportError(getattr(e, 'msg', str(e)), fatalError=True)
        return False, {}

    if not active_layer.selectedFeatureIds():
        active_layer.selectAll()

    # Make sure we are working on selected features only
    parameters['INPUT'] = QgsProcessingFeatureSourceDefinition(
        active_layer.id(), True)
    parameters['OUTPUT'] = 'memory:'

    req = QgsFeatureRequest(QgsExpression(r"$id < 0"))
    req.setFlags(QgsFeatureRequest.NoGeometry)
    req.setSubsetOfAttributes([])

    # Start the execution
    # If anything goes wrong and raise_exceptions is True an exception
    # is raised, else the execution is aborted and the error reported in
    # the feedback
    try:
        new_feature_ids = []

        active_layer.beginEditCommand(alg.displayName())

        # Checks whether the algorithm has a processFeature method
        if hasattr(alg, 'processFeature'):  # in-place feature editing
            # Make a clone or it will crash the second time the dialog
            # is opened and run
            alg = alg.create()
            if not alg.prepare(parameters, context, feedback):
                raise QgsProcessingException(
                    tr("Could not prepare selected algorithm."))
            # Check again for compatibility after prepare
            if not alg.supportInPlaceEdit(active_layer):
                raise QgsProcessingException(
                    tr("Selected algorithm and parameter configuration are not compatible with in-place modifications."
                       ))
            field_idxs = range(len(active_layer.fields()))
            iterator_req = QgsFeatureRequest(active_layer.selectedFeatureIds())
            iterator_req.setInvalidGeometryCheck(
                context.invalidGeometryCheck())
            feature_iterator = active_layer.getFeatures(iterator_req)
            step = 100 / len(active_layer.selectedFeatureIds()
                             ) if active_layer.selectedFeatureIds() else 1
            for current, f in enumerate(feature_iterator):
                feedback.setProgress(current * step)
                if feedback.isCanceled():
                    break

                # need a deep copy, because python processFeature implementations may return
                # a shallow copy from processFeature
                input_feature = QgsFeature(f)
                new_features = alg.processFeature(input_feature, context,
                                                  feedback)
                new_features = QgsVectorLayerUtils.makeFeaturesCompatible(
                    new_features, active_layer)

                if len(new_features) == 0:
                    active_layer.deleteFeature(f.id())
                elif len(new_features) == 1:
                    new_f = new_features[0]
                    if not f.geometry().equals(new_f.geometry()):
                        active_layer.changeGeometry(f.id(), new_f.geometry())
                    if f.attributes() != new_f.attributes():
                        active_layer.changeAttributeValues(
                            f.id(), dict(zip(field_idxs, new_f.attributes())),
                            dict(zip(field_idxs, f.attributes())))
                    new_feature_ids.append(f.id())
                else:
                    active_layer.deleteFeature(f.id())
                    # Get the new ids
                    old_ids = set(
                        [f.id() for f in active_layer.getFeatures(req)])
                    if not active_layer.addFeatures(new_features):
                        raise QgsProcessingException(
                            tr("Error adding processed features back into the layer."
                               ))
                    new_ids = set(
                        [f.id() for f in active_layer.getFeatures(req)])
                    new_feature_ids += list(new_ids - old_ids)

            results, ok = {}, True

        else:  # Traditional 'run' with delete and add features cycle

            # There is no way to know if some features have been skipped
            # due to invalid geometries
            if context.invalidGeometryCheck(
            ) == QgsFeatureRequest.GeometrySkipInvalid:
                selected_ids = active_layer.selectedFeatureIds()
            else:
                selected_ids = []

            results, ok = alg.run(parameters, context, feedback)

            if ok:
                result_layer = QgsProcessingUtils.mapLayerFromString(
                    results['OUTPUT'], context)
                # TODO: check if features have changed before delete/add cycle

                new_features = []

                # Check if there are any skipped features
                if context.invalidGeometryCheck(
                ) == QgsFeatureRequest.GeometrySkipInvalid:
                    missing_ids = list(
                        set(selected_ids) - set(result_layer.allFeatureIds()))
                    if missing_ids:
                        for f in active_layer.getFeatures(
                                QgsFeatureRequest(missing_ids)):
                            if not f.geometry().isGeosValid():
                                new_features.append(f)

                active_layer.deleteFeatures(active_layer.selectedFeatureIds())

                for f in result_layer.getFeatures():
                    new_features.extend(
                        QgsVectorLayerUtils.makeFeaturesCompatible(
                            [f], active_layer))

                # Get the new ids
                old_ids = set([f.id() for f in active_layer.getFeatures(req)])
                if not active_layer.addFeatures(new_features):
                    raise QgsProcessingException(
                        tr("Error adding processed features back into the layer."
                           ))
                new_ids = set([f.id() for f in active_layer.getFeatures(req)])
                new_feature_ids += list(new_ids - old_ids)

        active_layer.endEditCommand()

        if ok and new_feature_ids:
            active_layer.selectByIds(new_feature_ids)
        elif not ok:
            active_layer.rollBack()

        return ok, results

    except QgsProcessingException as e:
        active_layer.endEditCommand()
        active_layer.rollBack()
        if raise_exceptions:
            raise e
        QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing',
                                 Qgis.Critical)
        if feedback is not None:
            feedback.reportError(getattr(e, 'msg', str(e)), fatalError=True)

    return False, {}
Exemple #47
0
 def __init__(self, dialog):
     QgsProcessingFeedback.__init__(self)
     self.dialog = dialog
    def testFeatureSourceInput(self):
        # create a memory layer and add to project and context
        layer = QgsVectorLayer(
            "Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer",
            "testmem", "memory")
        self.assertTrue(layer.isValid())
        pr = layer.dataProvider()
        f = QgsFeature()
        f.setAttributes(["test", 123])
        f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200)))
        f2 = QgsFeature()
        f2.setAttributes(["test2", 457])
        f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(110, 200)))
        self.assertTrue(pr.addFeatures([f, f2]))
        self.assertEqual(layer.featureCount(), 2)

        # select first feature
        layer.selectByIds([next(layer.getFeatures()).id()])
        self.assertEqual(len(layer.selectedFeatureIds()), 1)

        QgsProject.instance().addMapLayer(layer)
        context = QgsProcessingContext()
        context.setProject(QgsProject.instance())

        alg = QgsApplication.processingRegistry().createAlgorithmById(
            'grass7:v.buffer')
        self.assertIsNotNone(alg)
        temp_file = os.path.join(self.temp_dir, 'grass_output_sel.shp')
        parameters = {
            'input': QgsProcessingFeatureSourceDefinition('testmem', True),
            'cats': '',
            'where': '',
            'type': [0, 1, 4],
            'distance': 1,
            'minordistance': None,
            'angle': 0,
            'column': None,
            'scale': 1,
            'tolerance': 0.01,
            '-s': False,
            '-c': False,
            '-t': False,
            'output': temp_file,
            'GRASS_REGION_PARAMETER': None,
            'GRASS_SNAP_TOLERANCE_PARAMETER': -1,
            'GRASS_MIN_AREA_PARAMETER': 0.0001,
            'GRASS_OUTPUT_TYPE_PARAMETER': 0,
            'GRASS_VECTOR_DSCO': '',
            'GRASS_VECTOR_LCO': ''
        }
        feedback = QgsProcessingFeedback()

        results, ok = alg.run(parameters, context, feedback)
        self.assertTrue(ok)
        self.assertTrue(os.path.exists(temp_file))

        # make sure that layer has correct features
        res = QgsVectorLayer(temp_file, 'res')
        self.assertTrue(res.isValid())
        self.assertEqual(res.featureCount(), 1)

        QgsProject.instance().removeMapLayer(layer)