예제 #1
0
 def loadRasterLayer(self,
                     name,
                     layer,
                     external=True,
                     band=1,
                     destName=None):
     """
     Creates a dedicated command to load a raster into
     the temporary GRASS DB.
     :param name: name of the parameter.
     :param layer: QgsMapLayer for the raster layer.
     :param external: True if using r.external.
     :param band: imports only specified band. None for all bands.
     :param destName: force the destination name of the raster.
     """
     self.inputLayers.append(layer)
     self.setSessionProjectionFromLayer(layer)
     if not destName:
         destName = 'rast_{}'.format(os.path.basename(getTempFilename()))
     self.exportedLayers[name] = destName
     command = '{0} input="{1}" {2}output="{3}" --overwrite -o'.format(
         'r.external' if external else 'r.in.gdal',
         os.path.normpath(layer.source()),
         'band={} '.format(band) if band else '', destName)
     self.commands.append(command)
예제 #2
0
    def loadVectorLayer(self, name, layer, external=False):
        """
        Creates a dedicated command to load a vector into
        temporary GRASS DB.
        :param name: name of the parameter
        :param layer: QgsMapLayer for the vector layer.
        :param external: use v.external (v.in.ogr if False).
        """
        # TODO: support multiple input formats
        if external is None:
            external = ProcessingConfig.getSetting(
                Grass7Utils.GRASS_USE_VEXTERNAL)

        # safety check: we can only use external for ogr layers which support random read
        if external:
            ds = ogr.Open(layer.source())
            if ds is not None:
                ogr_layer = ds.GetLayer()
                if ogr_layer is None or not ogr_layer.TestCapability(
                        ogr.OLCRandomRead):
                    external = False
            else:
                external = False

        self.inputLayers.append(layer)
        self.setSessionProjectionFromLayer(layer)
        destFilename = 'vector_{}'.format(os.path.basename(getTempFilename()))
        self.exportedLayers[name] = destFilename
        command = '{0}{1}{2} input="{3}" output="{4}" --overwrite -o'.format(
            'v.external' if external else 'v.in.ogr',
            ' min_area={}'.format(self.minArea) if not external else '',
            ' snap={}'.format(self.snapTolerance) if not external else '',
            os.path.normpath(layer.source()), destFilename)
        self.commands.append(command)
    def processAlgorithm(self, parameters, context, feedback):
        # TODO: check correct num of bands
        inLayer = self.parameterAsRasterLayer(parameters, self.INPUT, context)
        input = inLayer.source()
        temp = getTempFilename(None).replace('.', '')
        basename = os.path.basename(temp)
        validChars = \
            'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
        safeBasename = ''.join(c for c in basename if c in validChars)
        temp = os.path.join(os.path.dirname(temp), safeBasename)

        r = self.parameterAsOutputLayer(parameters, self.R, context)
        g = self.parameterAsOutputLayer(parameters, self.G, context)
        b = self.parameterAsOutputLayer(parameters, self.B, context)

        commands = []
        version = SagaUtils.getInstalledVersion(True)
        trailing = ""
        lib = ""
        commands.append('%sio_gdal 0 -GRIDS "%s" -FILES "%s"' %
                        (lib, temp, input))
        commands.append(
            '%sio_gdal 1 -GRIDS "%s_%s1.sgrd" -FORMAT 1 -TYPE 0 -FILE "%s"' %
            (lib, temp, trailing, r))
        commands.append(
            '%sio_gdal 1 -GRIDS "%s_%s2.sgrd" -FORMAT 1 -TYPE 0 -FILE "%s"' %
            (lib, temp, trailing, g))
        commands.append(
            '%sio_gdal 1 -GRIDS "%s_%s3.sgrd" -FORMAT 1 -TYPE 0 -FILE "%s"' %
            (lib, temp, trailing, b))

        SagaUtils.createSagaBatchJobFileFromSagaCommands(commands)
        SagaUtils.executeSaga(feedback)

        return {self.R: r, self.G: g, self.B: b}
예제 #4
0
def orderedInput(alg, parameters, context, src, tgt, numSeq=None):
    """Import multiple rasters in order
    :param alg: algorithm object.
    :param parameters: algorithm parameters dict.
    :param context: algorithm context.
    :param src: Name of the source parameter.
    :param tgt: Name of a new input parameter.
    :param numSeq: List of a sequence for naming layers.
    """
    rootFilename = 'rast_{}.'.format(os.path.basename(getTempFilename()))
    #parameters[tgt] = rootFilename
    param = QgsProcessingParameterString(tgt, 'virtual input', rootFilename,
                                         False, False)
    alg.addParameter(param)

    rasters = alg.parameterAsLayerList(parameters, src, context)
    # Handle specific range
    if numSeq is None:
        numSeq = list(range(1, len(rasters) + 1))

    for idx, raster in enumerate(rasters):
        rasterName = '{}{}'.format(rootFilename, numSeq[idx])
        alg.loadRasterLayer(rasterName, raster, False, None, rasterName)

    # Don't forget to remove the old input parameter
    alg.removeParameter(src)
예제 #5
0
def processCommand(alg, parameters, context, feedback):
    # Temporary remove outputs and add a virtual output parameter
    outputName = 'output_{}'.format(os.path.basename(getTempFilename()))
    param = QgsProcessingParameterString('output', 'virtual output',
                                         outputName, False, False)
    alg.addParameter(param)
    alg.processCommand(parameters, context, feedback, True)
def processCommand(alg, parameters, context, feedback):
    """ Handle data preparation for v.net.distance:
    * Integrate point layers into network vector map.
    * Make v.net.distance use those layers.
    * Delete the threshold parameter.
    * If where statement, connect to the db
    """
    # Grab the point layer and delete this parameter
    lineLayer = alg.exportedLayers['input']
    fromLayer = alg.exportedLayers['flayer']
    toLayer = alg.exportedLayers['tlayer']
    intLayer = 'bufnet' + os.path.basename(getTempFilename())
    netLayer = 'net' + os.path.basename(getTempFilename())
    threshold = alg.parameterAsDouble(parameters, 'threshold', context)

    # Create the v.net connect command for from_layer integration
    command = u"v.net input={} points={} output={} operation=connect threshold={} arc_layer=1 node_layer=2".format(
        lineLayer, fromLayer, intLayer, threshold)
    alg.commands.append(command)

    # Do it again with to_layer
    command = u"v.net input={} points={} output={} operation=connect threshold={} arc_layer=1 node_layer=3".format(
        intLayer, toLayer, netLayer, threshold)
    alg.commands.append(command)

    # Connect the point layer database to the layer 2 of the network
    command = u"v.db.connect -o map={} table={} layer=2".format(
        netLayer, fromLayer)
    alg.commands.append(command)

    command = u"v.db.connect -o map={} table={} layer=3".format(
        netLayer, toLayer)
    alg.commands.append(command)

    # remove undesired parameters
    alg.removeParameter('flayer')
    alg.removeParameter('tlayer')
    alg.removeParameter('threshold')
    alg.exportedLayers['input'] = netLayer

    # Add the two new parameters
    fLayer = QgsProcessingParameterString('from_layer', None, 2, False, False)
    alg.addParameter(fLayer)
    tLayer = QgsProcessingParameterString('to_layer', None, 3, False, False)
    alg.addParameter(tLayer)
    alg.processCommand(parameters, context, feedback)
예제 #7
0
def configFile(alg, parameters, context, feedback, outputTxt=False):
    """Handle inline configuration
    :param parameters:
    """
    # Where is the GRASS7 user directory ?
    userGrass7Path = rliPath()
    if not os.path.isdir(userGrass7Path):
        mkdir(userGrass7Path)
    if not os.path.isdir(os.path.join(userGrass7Path, 'output')):
        mkdir(os.path.join(userGrass7Path, 'output'))

    # If we have a configuration file, we need to copy it into user dir
    if parameters['config']:
        fileName = alg.parameterAsString(parameters, 'config', context)
        configFilePath = os.path.join(userGrass7Path,
                                      os.path.basename(fileName))
        # Copy the file
        shutil.copy(parameters['config'], configFilePath)
        # Change the parameter value
        parameters['config'] = os.path.basename(configFilePath)
    # Handle inline configuration
    elif parameters['config_txt']:
        # Creates a temporary txt file in user r.li directory
        tempConfig = os.path.basename(getTempFilename())
        configFilePath = os.path.join(userGrass7Path, tempConfig)
        # Inject rules into temporary txt file
        with open(configFilePath, "w") as f:
            f.write(alg.parameterAsString(parameters, 'config_txt', context))
            f.write("\n")

        # Use temporary file as rules file
        parameters['config'] = os.path.basename(configFilePath)
        alg.removeParameter('config_txt')

    # For ascii output, we need a virtual output
    if outputTxt:
        param = QgsProcessingParameterString(
            'output', 'virtual output',
            'a' + os.path.basename(getTempFilename()), False, False)
        alg.addParameter(param)

    alg.processCommand(parameters, context, feedback, outputTxt)

    # Remove Config file:
    removeConfigFile(alg, parameters, context)
def processCommand(alg, parameters, context, feedback):
    # Handle inline rules
    txtRules = alg.parameterAsString(parameters, 'txtrules', context)
    if txtRules:
        # Creates a temporary txt file
        tempRulesName = getTempFilename()

        # Inject rules into temporary txt file
        with open(tempRulesName, "w") as tempRules:
            tempRules.write(txtRules)
        alg.removeParameter('txtrules')
        parameters['rules'] = tempRulesName

    alg.processCommand(parameters, context, feedback, True)
def processCommand(alg, parameters, context, feedback):
    # handle inline points
    inlinePoints = alg.parameterAsString(parameters, 'inline_points', context)
    if inlinePoints:
        # Creates a temporary txt file
        pointsName = getTempFilename()

        # Inject rules into temporary txt file
        with open(pointsName, "w") as tempPoints:
            tempPoints.write(inlinePoints)
        alg.removeParameter('inline_points')
        parameters['points'] = tempPoints

    alg.processCommand(parameters, context, feedback, True)
예제 #10
0
 def loadAttributeTable(self, name, layer, destName=None):
     """
     Creates a dedicated command to load an attribute table
     into the temporary GRASS DB.
     :param name: name of the input parameter.
     :param layer: a layer object to import from.
     :param destName: force the name for the table into GRASS DB.
     """
     self.inputLayers.append(layer)
     if not destName:
         destName = 'table_{}'.format(os.path.basename(getTempFilename()))
     self.exportedLayers[name] = destName
     command = 'db.in.ogr --overwrite input="{0}" output="{1}"'.format(
         os.path.normpath(layer.source()), destName)
     self.commands.append(command)
예제 #11
0
def incorporatePoints(alg, parameters, context, feedback, pointLayerName='points', networkLayerName='input'):
    """
    incorporate points with lines to form a GRASS network
    """

    # Grab the point layer and delete this parameter
    pointLayer = alg.parameterAsVectorLayer(parameters, pointLayerName, context)
    if pointLayer:
        # Create an intermediate GRASS layer which is the combination of network + centers
        intLayer = 'net' + os.path.basename(getTempFilename())

        pointLayer = alg.exportedLayers[pointLayerName]

        # Grab the network layer
        lineLayer = alg.parameterAsVectorLayer(parameters, networkLayerName, context)
        if lineLayer:
            lineLayer = alg.exportedLayers[networkLayerName]
        else:
            raise QgsProcessingException(
                alg.tr('GRASS GIS 7 v.net requires a lines layer!'))

        threshold = alg.parameterAsDouble(parameters, 'threshold', context)

        # Create the v.net connect command for point layer integration
        command = u"v.net input={} points={} output={} operation=connect threshold={}".format(
            lineLayer, pointLayer, intLayer, threshold)
        alg.commands.append(command)

        # Connect the point layer database to the layer 2 of the network
        command = u"v.db.connect -o map={} table={} layer=2".format(intLayer, pointLayer)
        alg.commands.append(command)

        # remove undesired parameters
        alg.removeParameter(pointLayerName)

        # Use temp layer for input
        alg.exportedLayers[networkLayerName] = intLayer

    # Process the command
    if 'threshold' in parameters:
        alg.removeParameter('threshold')

    alg.processCommand(parameters, context, feedback)
예제 #12
0
def regroupRasters(alg,
                   parameters,
                   context,
                   src,
                   group,
                   subgroup=None,
                   extFile=None):
    """
    Group multiple input rasters into a group
    * If there is a subgroupField, a subgroup will automatically be created.
    * When an external file is provided, the file is copied into the respective
    directory of the subgroup.
    :param parameters:
    :param context:
    :param src: name of input parameter with multiple rasters.
    :param group: name of group.
    :param subgroup: name of subgroup.
    :param extFile: dict : parameterName:directory name
    """
    # Create a group parameter
    groupName = 'group_{}'.format(os.path.basename(getTempFilename()))
    param = QgsProcessingParameterString(group, 'virtual group', groupName,
                                         False, False)
    alg.addParameter(param)

    # Create a subgroup
    subgroupName = None
    if subgroup:
        subgroupName = 'subgroup_{}'.format(os.path.basename(
            getTempFilename()))
        param = QgsProcessingParameterString(subgroup, 'virtual subgroup',
                                             subgroupName, False, False)
        alg.addParameter(param)

    # Compute raster names
    rasters = alg.parameterAsLayerList(parameters, src, context)
    rasterNames = []
    for idx, raster in enumerate(rasters):
        name = '{}_{}'.format(src, idx)
        if name in alg.exportedLayers:
            rasterNames.append(alg.exportedLayers[name])

    # Insert a i.group command
    command = 'i.group group={}{} input={}'.format(
        groupName, ' subgroup={}'.format(subgroupName) if subgroup else '',
        ','.join(rasterNames))
    alg.commands.append(command)

    # Handle external files
    # if subgroupField and extFile:
    #     for ext in extFile.keys():
    #         extFileName = new_parameters[ext]
    #         if extFileName:
    #             shortFileName = os.path.basename(extFileName)
    #             destPath = os.path.join(Grass7Utils.grassMapsetFolder(),
    #                                     'PERMANENT',
    #                                     'group', new_parameters[group.name()],
    #                                     'subgroup', new_parameters[subgroup.name()],
    #                                     extFile[ext], shortFileName)
    #             copyFile(alg, extFileName, destPath)

    alg.removeParameter(src)

    return groupName, subgroupName
    def processAlgorithm(self, parameters, context, feedback):
        commands = list()
        self.exportedLayers = {}

        self.preProcessInputs()
        extent = None
        crs = None

        # 1: Export rasters to sgrd and vectors to shp
        # Tables must be in dbf format. We check that.
        for param in self.parameterDefinitions():
            if isinstance(param, QgsProcessingParameterRasterLayer):
                if param.name(
                ) not in parameters or parameters[param.name()] is None:
                    continue

                if isinstance(parameters[param.name()], str):
                    if parameters[param.name()].lower().endswith('sdat'):
                        self.exportedLayers[param.name(
                        )] = parameters[param.name()][:-4] + 'sgrd'
                    if parameters[param.name()].lower().endswith('sgrd'):
                        self.exportedLayers[param.name()] = parameters[
                            param.name()]
                    else:
                        layer = self.parameterAsRasterLayer(
                            parameters, param.name(), context)
                        exportCommand = self.exportRasterLayer(
                            param.name(), layer)
                        if exportCommand is not None:
                            commands.append(exportCommand)
                else:
                    if parameters[param.name()].source().lower().endswith(
                            'sdat'):
                        self.exportedLayers[param.name(
                        )] = parameters[param.name()].source()[:-4] + 'sgrd'
                    if parameters[param.name()].source().lower().endswith(
                            'sgrd'):
                        self.exportedLayers[param.name()] = parameters[
                            param.name()].source()
                    else:
                        exportCommand = self.exportRasterLayer(
                            param.name(), parameters[param.name()])
                        if exportCommand is not None:
                            commands.append(exportCommand)
            elif isinstance(param, QgsProcessingParameterFeatureSource):
                if param.name(
                ) not in parameters or parameters[param.name()] is None:
                    continue

                if not crs:
                    source = self.parameterAsSource(parameters, param.name(),
                                                    context)
                    crs = source.sourceCrs()

                layer_path = self.parameterAsCompatibleSourceLayerPath(
                    parameters,
                    param.name(),
                    context, ['shp'],
                    'shp',
                    feedback=feedback)
                if layer_path:
                    self.exportedLayers[param.name()] = layer_path
                else:
                    raise QgsProcessingException(
                        self.tr('Unsupported file format'))
            elif isinstance(param, QgsProcessingParameterMultipleLayers):
                if param.name(
                ) not in parameters or parameters[param.name()] is None:
                    continue

                layers = self.parameterAsLayerList(parameters, param.name(),
                                                   context)
                if layers is None or len(layers) == 0:
                    continue
                if param.layerType() == QgsProcessing.TypeRaster:
                    files = []
                    for i, layer in enumerate(layers):
                        if layer.source().lower().endswith('sdat'):
                            files.append(
                                parameters[param.name()].source()[:-4] +
                                'sgrd')
                        if layer.source().lower().endswith('sgrd'):
                            files.append(parameters[param.name()].source())
                        else:
                            exportCommand = self.exportRasterLayer(
                                param.name(), layer)
                            files.append(self.exportedLayers[param.name()])
                            if exportCommand is not None:
                                commands.append(exportCommand)

                    self.exportedLayers[param.name()] = files
                else:
                    temp_params = deepcopy(parameters)
                    for layer in layers:
                        temp_params[param.name()] = layer

                        if not crs:
                            source = self.parameterAsSource(
                                temp_params, param.name(), context)
                            crs = source.sourceCrs()

                        layer_path = self.parameterAsCompatibleSourceLayerPath(
                            temp_params,
                            param.name(),
                            context,
                            'shp',
                            feedback=feedback)
                        if layer_path:
                            if param.name() in self.exportedLayers:
                                self.exportedLayers[param.name()].append(
                                    layer_path)
                            else:
                                self.exportedLayers[param.name()] = [
                                    layer_path
                                ]
                        else:
                            raise QgsProcessingException(
                                self.tr('Unsupported file format'))

        # 2: Set parameters and outputs
        command = self.undecorated_group + ' "' + self.cmdname + '"'
        command += ' ' + ' '.join(self.hardcoded_strings)

        for param in self.parameterDefinitions():
            if not param.name() in parameters or parameters[
                    param.name()] is None:
                continue
            if param.isDestination():
                continue

            if isinstance(param, (QgsProcessingParameterRasterLayer,
                                  QgsProcessingParameterFeatureSource)):
                command += ' -{} "{}"'.format(
                    param.name(), self.exportedLayers[param.name()])
            elif isinstance(param, QgsProcessingParameterMultipleLayers):
                command += ' -{} "{}"'.format(
                    param.name(), ';'.join(self.exportedLayers[param.name()]))
            elif isinstance(param, QgsProcessingParameterBoolean):
                if self.parameterAsBool(parameters, param.name(), context):
                    command += ' -{} true'.format(param.name().strip())
                else:
                    command += ' -{} false'.format(param.name().strip())
            elif isinstance(param, QgsProcessingParameterMatrix):
                tempTableFile = getTempFilename('txt')
                with open(tempTableFile, 'w') as f:
                    f.write('\t'.join([col for col in param.headers()]) + '\n')
                    values = self.parameterAsMatrix(parameters, param.name(),
                                                    context)
                    for i in range(0, len(values), 3):
                        s = values[i] + '\t' + values[i + 1] + '\t' + values[
                            i + 2] + '\n'
                        f.write(s)
                command += ' -{} "{}"'.format(param.name(), tempTableFile)
            elif isinstance(param, QgsProcessingParameterExtent):
                # 'We have to substract/add half cell size, since SAGA is
                # center based, not corner based
                halfcell = self.getOutputCellsize(parameters, context) / 2
                offset = [halfcell, -halfcell, halfcell, -halfcell]
                rect = self.parameterAsExtent(parameters, param.name(),
                                              context)

                values = []
                values.append(rect.xMinimum())
                values.append(rect.xMaximum())
                values.append(rect.yMinimum())
                values.append(rect.yMaximum())

                for i in range(4):
                    command += ' -{} {}'.format(self.extentParamNames[i],
                                                float(values[i]) + offset[i])
            elif isinstance(param, QgsProcessingParameterNumber):
                if param.dataType() == QgsProcessingParameterNumber.Integer:
                    command += ' -{} {}'.format(
                        param.name(),
                        self.parameterAsInt(parameters, param.name(), context))
                else:
                    command += ' -{} {}'.format(
                        param.name(),
                        self.parameterAsDouble(parameters, param.name(),
                                               context))
            elif isinstance(param, QgsProcessingParameterEnum):
                command += ' -{} {}'.format(
                    param.name(),
                    self.parameterAsEnum(parameters, param.name(), context))
            elif isinstance(
                    param,
                (QgsProcessingParameterString, QgsProcessingParameterFile)):
                command += ' -{} "{}"'.format(
                    param.name(),
                    self.parameterAsFile(parameters, param.name(), context))
            elif isinstance(
                    param,
                (QgsProcessingParameterString, QgsProcessingParameterField)):
                command += ' -{} "{}"'.format(
                    param.name(),
                    self.parameterAsString(parameters, param.name(), context))

        output_layers = []
        output_files = {}
        for out in self.destinationParameterDefinitions():
            filePath = self.parameterAsOutputLayer(parameters, out.name(),
                                                   context)
            if isinstance(out, (QgsProcessingParameterRasterDestination,
                                QgsProcessingParameterVectorDestination)):
                output_layers.append(filePath)
            output_files[out.name()] = filePath
            command += ' -{} "{}"'.format(out.name(), filePath)

        commands.append(command)

        # special treatment for RGB algorithm
        # TODO: improve this and put this code somewhere else
        for out in self.destinationParameterDefinitions():
            if isinstance(out, QgsProcessingParameterRasterDestination):
                filename = self.parameterAsOutputLayer(parameters, out.name(),
                                                       context)
                filename2 = os.path.splitext(filename)[0] + '.sgrd'
                if self.cmdname == 'RGB Composite':
                    commands.append(
                        'io_grid_image 0 -IS_RGB -GRID:"{}" -FILE:"{}"'.format(
                            filename2, filename))

        # 3: Run SAGA
        commands = self.editCommands(commands)
        SagaUtils.createSagaBatchJobFileFromSagaCommands(commands)
        loglines = []
        loglines.append(self.tr('SAGA execution commands'))
        for line in commands:
            feedback.pushCommandInfo(line)
            loglines.append(line)
        if ProcessingConfig.getSetting(SagaUtils.SAGA_LOG_COMMANDS):
            QgsMessageLog.logMessage('\n'.join(loglines),
                                     self.tr('Processing'), Qgis.Info)
        SagaUtils.executeSaga(feedback)

        if crs is not None:
            for out in output_layers:
                prjFile = os.path.splitext(out)[0] + '.prj'
                with open(prjFile, 'w') as f:
                    f.write(crs.toWkt())

        result = {}
        for o in self.outputDefinitions():
            if o.name() in output_files:
                result[o.name()] = output_files[o.name()]
        return result