def processAlgorithm(self, parameters, context, feedback):
        crs = self.parameterAsCrs(parameters, self.TARGET_CRS, context)
        extent = self.parameterAsExtent(parameters, self.EXTENT, context, crs)
        value = self.parameterAsDouble(parameters, self.NUMBER, context)
        pixelSize = self.parameterAsDouble(parameters, self.PIXEL_SIZE, context)

        outputFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
        outputFormat = QgsRasterFileWriter.driverForExtension(os.path.splitext(outputFile)[1])

        rows = max([math.ceil(extent.height() / pixelSize) + 1, 1.0])
        cols = max([math.ceil(extent.width() / pixelSize) + 1, 1.0])

        writer = QgsRasterFileWriter(outputFile)
        writer.setOutputProviderKey('gdal')
        writer.setOutputFormat(outputFormat)
        provider = writer.createOneBandRaster(Qgis.Float32, cols, rows, extent, crs)
        provider.setNoDataValue(1, -9999)

        data = [value] * cols
        block = QgsRasterBlock(Qgis.Float32, cols, 1)
        block.setData(struct.pack('{}f'.format(len(data)), *data))

        total = 100.0 / rows if rows else 0
        for i in range(rows):
            if feedback.isCanceled():
                break

            provider.writeBlock(block, 1, 0, i)
            feedback.setProgress(int(i * rows))

        provider.setEditable(False)

        return {self.OUTPUT: outputFile}
Beispiel #2
0
    def processAlgorithm(self, parameters, context, feedback):
        crs = self.parameterAsCrs(parameters, self.TARGET_CRS, context)
        extent = self.parameterAsExtent(parameters, self.EXTENT, context, crs)
        value = self.parameterAsDouble(parameters, self.NUMBER, context)
        pixelSize = self.parameterAsDouble(parameters, self.PIXEL_SIZE, context)

        outputFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
        outputFormat = QgsRasterFileWriter.driverForExtension(os.path.splitext(outputFile)[1])

        rows = max([math.ceil(extent.height() / pixelSize) + 1, 1.0])
        cols = max([math.ceil(extent.width() / pixelSize) + 1, 1.0])

        writer = QgsRasterFileWriter(outputFile)
        writer.setOutputProviderKey('gdal')
        writer.setOutputFormat(outputFormat)
        provider = writer.createOneBandRaster(Qgis.Float32, cols, rows, extent, crs)
        provider.setNoDataValue(1, -9999)

        data = [value] * cols
        block = QgsRasterBlock(Qgis.Float32, cols, 1)
        block.setData(struct.pack('{}f'.format(len(data)), *data))

        total = 100.0 / rows if rows else 0
        for i in range(rows):
            if feedback.isCanceled():
                break

            provider.writeBlock(block, 1, 0, i)
            feedback.setProgress(int(i * rows))

        provider.setEditable(False)

        return {self.OUTPUT: outputFile}
 def write_block(self, const_values=None, low_pass_filter=False):
     """
     Construct raster block for each band, apply the values and write to file.
     If const_values are given (a list of const values for each band) they are used for each selected cell.
     In other case the memory layer with values calculated for each cell selected will be used.
     Alternatively, selected cells values can be filtered using low-pass 3x3 filter.
     """
     if self.logger:
         vals = f"const values ({const_values})" if const_values else "expression values."
         self.logger.debug(f"Writing blocks with {vals}")
     if not self.provider.isEditable():
         res = self.provider.setEditable(True)
         if not res:
             if self.uc:
                 self.uc.show_warn('QGIS can\'t modify this type of raster')
             return None
     if self.logger:
         self.logger.debug("Calculating block origin coordinates...")
     b_orig_x, b_orig_y = self.index_to_point(self.block_row_min,
                                              self.block_col_min)
     cols = self.block_col_max - self.block_col_min + 1
     rows = self.block_row_max - self.block_row_min + 1
     b_end_x = b_orig_x + cols * self.pixel_size_x
     b_end_y = b_orig_y - rows * self.pixel_size_y
     block_bbox = QgsRectangle(b_orig_x, b_end_y, b_end_x, b_orig_y)
     if self.logger:
         self.logger.debug(f"Block bbox: {block_bbox.toString()}")
         self.logger.debug(
             f"Nr of cells in the block: rows={rows}, cols={cols}")
     old_blocks = []
     new_blocks = []
     cell_values = dict()
     if const_values is None and not low_pass_filter:
         for feat in self.cell_pts_layer.getFeatures():
             cell_values[feat.id()] = feat.attribute(self.exp_field_idx)
     for band_nr in self.active_bands:
         block = self.provider.block(band_nr, block_bbox, cols, rows)
         new_blocks.append(block)
         block_data = block.data().data()
         old_block = QgsRasterBlock(self.data_types[band_nr - 1], cols,
                                    rows)
         old_block.setData(block_data)
         for abs_row, abs_col in self.selected_cells:
             row = abs_row - self.block_row_min
             col = abs_col - self.block_col_min
             if const_values:
                 idx = band_nr - 1 if len(self.active_bands) > 1 else 0
                 new_val = const_values[idx]
             elif low_pass_filter:
                 # the filter is applied for cells inside the block only
                 if block.height() < 3 or block.width() < 3:
                     # the selected block is too small for filtering -> keep the old value
                     new_val = None
                 else:
                     new_val = low_pass_filtered(
                         old_block, row, col,
                         self.nodata_values[band_nr - 1])
             else:
                 # set the expression value
                 feat_id = self.selected_cells_feats[(abs_row, abs_col)]
                 if cell_values[feat_id] is not None:
                     new_val = None if math.isnan(cell_values[feat_id]) or \
                                   cell_values[feat_id] is None else cell_values[feat_id]
                 else:
                     new_val = None
             new_val = old_block.value(row,
                                       col) if new_val is None else new_val
             set_res = block.setValue(row, col, new_val)
             if self.logger:
                 self.logger.debug(
                     f"Setting block value for band {band_nr}, row {row}, col: {col}: {set_res}"
                 )
         old_blocks.append(old_block)
         band_res = self.provider.writeBlock(block, band_nr,
                                             self.block_col_min,
                                             self.block_row_min)
         if self.logger:
             self.logger.debug(
                 f"Writing block for band {band_nr}: {band_res}")
     self.provider.setEditable(False)
     change = RasterChange(self.active_bands, self.block_row_min,
                           self.block_col_min, old_blocks, new_blocks)
     self.raster_changed.emit(change)
     return True