Source code for rforge.library.containers.raster

import os
from typing import Dict, Optional, TypedDict, Union

import rasterio

from rforge.library.tools.rescale_dataset import rescale_dataset
from rforge.library.tools.exceptions import Errors

from rforge.library.containers.layer import Layer


class RasterImportConfig(TypedDict):
    id: int
    name: str


[docs] class Raster: """Represents a collection of layers in a geospatial dataset. Attributes: _layers (Dict[str, Layer]): Dictionary mapping layer names to Layer instances. _scale (int): The scale factor of the raster dataset. Methods: __init__: Initializes a Raster instance. __str__: Returns a string representation of the raster dataset. layers: Getter for the layers dictionary. count: Computes the number of layers in the dataset. scale: Getter for the scale factor. import_layers: Imports layers from a raster file. add_layer: Adds a layer to the raster dataset. remove_layer: Removes a layer from the raster dataset. edit_layer: Renames a layer in the raster dataset. """ _layers: Dict[str, Layer] _scale: int
[docs] def __init__(self, scale: int, layers: Optional[Dict[str, Layer]] = None): if not isinstance(scale, int) or (isinstance(scale, int) and scale <= 0): raise TypeError( Errors.bad_input(name="scale", expected_type="an integer larger than 0") ) if layers is None: layers = {} else: if not isinstance(layers, dict): raise TypeError( Errors.bad_input(name="layers", expected_type="a dictionary") ) for key, value in layers.items(): if not isinstance(key, str): raise TypeError( Errors.bad_input(name="layers keys", expected_type="strings") ) if not isinstance(value, Layer): raise TypeError( Errors.bad_input(name="layers values", expected_type="Layers") ) self._layers = layers self._scale = scale
[docs] def __str__(self): return str({key: value.__str__() for key, value in self._layers.items()})
@property def layers(self) -> Dict[str, Layer]: return self._layers @property def count(self) -> int: return len(self._layers) @property def scale(self) -> int: return self._scale
[docs] def import_layers( self, path: str, config: Optional[list[Dict[str, Union[str, int]]]] = None ): if not os.path.exists(path): raise FileNotFoundError(Errors.file_not_found(file_path=path)) with rasterio.open(path) as dataset: dataset = rescale_dataset(dataset, self.scale) if config is None: config = [] for id in range(1, dataset.count + 1): aux_config: Dict[str, Union[str, int]] = { "name": f"Layer {id}", "id": id, } config.append(aux_config) for item in config: array = dataset.read(item["id"]) bounds = { "left": dataset.bounds[0], "bottom": dataset.bounds[1], "right": dataset.bounds[2], "top": dataset.bounds[3], } crs = ( str(dataset.crs.to_epsg()) if dataset.crs.to_epsg() is not None else "4326" ) driver = dataset.meta["driver"].upper() no_data = dataset.nodata transform = ( dataset.transform.c, dataset.transform.a, dataset.transform.b, dataset.transform.f, dataset.transform.d, dataset.transform.e, ) units = dataset.units[int(item["id"]) - 1] layer = Layer( array=array, bounds=bounds, crs=crs, driver=driver, no_data=no_data, transform=transform, units=units, ) self._layers[str(item["name"])] = layer
[docs] def add_layer(self, layer: Layer, name: str): if not isinstance(layer, Layer): raise TypeError(Errors.bad_input(name="layer", expected_type="a Layer")) if not isinstance(name, str): raise TypeError( Errors.bad_input(name="layer name", expected_type="a string") ) if name not in self._layers.keys(): self._layers[name] = layer
[docs] def remove_layer(self, name: str): if not isinstance(name, str): raise TypeError( Errors.bad_input(name="layer name", expected_type="a string") ) if name in self._layers.keys(): self._layers.pop(name)
[docs] def edit_layer(self, current_name: str, new_name: str): if not isinstance(current_name, str): raise TypeError( Errors.bad_input(name="current layer name", expected_type="a string") ) if not isinstance(new_name, str): raise TypeError( Errors.bad_input(name="new layer name", expected_type="a string") ) if current_name in self._layers.keys(): self._layers[new_name] = self._layers.pop(current_name)