Exemple #1
0
def internal_vector_to_memory(
    vector: Union[str, ogr.DataSource],
    memory_path: Optional[str] = None,
    copy_if_already_in_memory: bool = True,
    layer_to_extract: int = -1,
) -> str:
    """OBS: Internal. Single output.

    Copies a vector source to memory.
    """
    type_check(vector, [str, ogr.DataSource], "vector")
    type_check(memory_path, [str], "memory_path", allow_none=True)
    type_check(layer_to_extract, [int], "layer_to_extract")

    ref = open_vector(vector)
    path = get_vector_path(ref)
    metadata = internal_vector_to_metadata(ref)
    name = metadata["name"]

    if not copy_if_already_in_memory and metadata["in_memory"]:
        if layer_to_extract == -1:
            return path

    if memory_path is not None:
        if memory_path[0:8] == "/vsimem/":
            vector_name = memory_path
        else:
            vector_name = f"/vsimem/{memory_path}"
        driver = ogr.GetDriverByName(path_to_driver_vector(memory_path))
    else:
        vector_name = f"/vsimem/{name}_{uuid4().int}.gpkg"
        driver = ogr.GetDriverByName("GPKG")

    if driver is None:
        raise Exception(f"Error while parsing driver for: {vector}")

    copy = driver.CreateDataSource(vector_name)

    for layer_idx in range(metadata["layer_count"]):
        if layer_to_extract is not None and layer_idx != layer_to_extract:
            continue

        layername = metadata["layers"][layer_idx]["layer_name"]
        copy.CopyLayer(ref.GetLayer(layer_idx), layername, ["OVERWRITE=YES"])

    return vector_name
Exemple #2
0
def internal_singlepart_to_multipart(
    vector: Union[str, ogr.DataSource],
    out_path: Optional[str] = None,
    overwrite: bool = True,
    add_index: bool = True,
    process_layer: int = -1,
) -> str:
    type_check(vector, [str, ogr.DataSource], "vector")
    type_check(out_path, [str], "out_path", allow_none=True)
    type_check(overwrite, [bool], "overwrite")
    type_check(add_index, [bool], "add_index")
    type_check(process_layer, [int], "process_layer")

    vector_list, path_list = ready_io_vector(vector, out_path, overwrite=overwrite)
    ref = open_vector(vector_list[0])
    out_name = path_list[0]

    out_format = path_to_driver_vector(out_name)
    driver = ogr.GetDriverByName(out_format)
    overwrite_required(out_name, overwrite)

    metadata = internal_vector_to_metadata(ref)

    remove_if_overwrite(out_name, overwrite)

    destination: ogr.DataSource = driver.CreateDataSource(out_name)

    for index, layer_meta in enumerate(metadata["layers"]):
        if process_layer != -1 and index != process_layer:
            continue

        name = layer_meta["layer_name"]
        geom = layer_meta["column_geom"]

        sql = f"SELECT ST_Collect({geom}) AS geom FROM {name};"

        result = ref.ExecuteSQL(sql, dialect="SQLITE")
        destination.CopyLayer(result, name, ["OVERWRITE=YES"])

    if add_index:
        vector_add_index(destination)

    destination.FlushCache()

    return out_name
Exemple #3
0
def internal_vector_to_disk(
    vector: Union[str, ogr.DataSource],
    out_path: str,
    overwrite: bool = True,
) -> str:
    """OBS: Internal. Single output.

    Copies a vector source to disk.
    """
    type_check(vector, [str, ogr.DataSource], "vector")
    type_check(out_path, [str], "out_path")
    type_check(overwrite, [bool], "overwrite")

    overwrite_required(out_path, overwrite)

    datasource = open_vector(vector)
    metadata = internal_vector_to_metadata(vector)

    if not os.path.dirname(os.path.abspath(out_path)):
        raise ValueError(
            f"Output folder does not exist. Please create first. {out_path}")

    driver = ogr.GetDriverByName(path_to_driver_vector(out_path))

    if driver is None:
        raise Exception(f"Error while parsing driver for: {vector}")

    remove_if_overwrite(out_path, overwrite)

    copy = driver.CreateDataSource(out_path)

    for layer_idx in range(metadata["layer_count"]):
        layer_name = metadata["layers"][layer_idx]["layer_name"]
        copy.CopyLayer(datasource.GetLayer(layer_idx), str(layer_name),
                       ["OVERWRITE=YES"])

    # Flush to disk
    copy = None

    return out_path
Exemple #4
0
def merge_vectors(
    vectors: List[Union[str, ogr.DataSource]],
    out_path: Optional[str] = None,
    preserve_fid: bool = True,
) -> str:
    """Merge vectors to a single geopackage."""
    type_check(vectors, [list], "vector")
    type_check(out_path, [str], "out_path", allow_none=True)
    type_check(preserve_fid, [bool], "preserve_fid")

    vector_list = to_vector_list(vectors)

    out_driver = "GPKG"
    out_format = ".gpkg"
    out_target = f"/vsimem/clipped_{uuid4().int}{out_format}"

    if out_path is not None:
        out_target = out_path
        out_driver = path_to_driver_vector(out_path)
        out_format = path_to_ext(out_path)

    driver = ogr.GetDriverByName(out_driver)

    merged_ds: ogr.DataSource = driver.CreateDataSource(out_target)

    for vector in vector_list:
        ref = open_vector(vector)
        metadata = internal_vector_to_metadata(ref)

        for layer in metadata["layers"]:
            name = layer["layer_name"]
            merged_ds.CopyLayer(ref.GetLayer(name), name, ["OVERWRITE=YES"])

    merged_ds.FlushCache()

    return out_target
Exemple #5
0
def internal_intersect_vector(
    vector: Union[str, ogr.DataSource],
    clip_geom: Union[str, ogr.DataSource, gdal.Dataset],
    out_path: Optional[str] = None,
    to_extent: bool = False,
    process_layer: int = 0,
    process_layer_clip: int = 0,
    add_index: bool = True,
    preserve_fid: bool = True,
    overwrite: bool = True,
    return_bool: bool = False,
) -> str:
    """Clips a vector to a geometry.

    Returns:
        A clipped ogr.Datasource or the path to one.
    """
    type_check(vector, [ogr.DataSource, str, list], "vector")
    type_check(clip_geom, [ogr.DataSource, gdal.Dataset, str, list, tuple], "clip_geom")
    type_check(out_path, [str], "out_path", allow_none=True)
    type_check(to_extent, [bool], "to_extent")
    type_check(process_layer, [int], "process_layer")
    type_check(process_layer_clip, [int], "process_layer_clip")
    type_check(add_index, [bool], "add_index")
    type_check(preserve_fid, [bool], "preserve_fid")
    type_check(overwrite, [bool], "overwrite")

    _vector_list, path_list = ready_io_vector(vector, out_path, overwrite=overwrite)
    out_name = path_list[0]

    match_projection = internal_reproject_vector(clip_geom, vector)
    geometry_to_clip = open_vector(match_projection)

    merged = open_vector(merge_vectors([vector, match_projection]))

    if add_index:
        vector_add_index(merged)

    vector_metadata = internal_vector_to_metadata(vector)
    vector_layername = vector_metadata["layers"][process_layer]["layer_name"]
    vector_geom_col = vector_metadata["layers"][process_layer]["column_geom"]

    clip_geom_metadata = internal_vector_to_metadata(geometry_to_clip)
    clip_geom_layername = clip_geom_metadata["layers"][process_layer_clip]["layer_name"]
    clip_geom_col = clip_geom_metadata["layers"][process_layer_clip]["column_geom"]

    if return_bool:
        sql = f"SELECT A.* FROM '{vector_layername}' A, '{clip_geom_layername}' B WHERE ST_INTERSECTS(A.{vector_geom_col}, B.{clip_geom_col});"
    else:
        sql = f"SELECT A.* FROM '{vector_layername}' A, '{clip_geom_layername}' B WHERE ST_INTERSECTS(A.{vector_geom_col}, B.{clip_geom_col});"

    result = merged.ExecuteSQL(sql, dialect="SQLITE")

    if return_bool:
        if result.GetFeatureCount() == 0:
            return False
        else:
            return True

    driver = ogr.GetDriverByName(path_to_driver_vector(out_name))
    destination: ogr.DataSource = driver.CreateDataSource(out_name)
    destination.CopyLayer(result, vector_layername, ["OVERWRITE=YES"])

    if destination is None:
        raise Exception("Error while running intersect.")

    destination.FlushCache()

    return out_name
Exemple #6
0
def internal_reproject_vector(
    vector: Union[str, ogr.DataSource],
    projection: Union[str, int, ogr.DataSource, gdal.Dataset,
                      osr.SpatialReference],
    out_path: Optional[str] = None,
    copy_if_same: bool = False,
    overwrite: bool = True,
) -> str:
    type_check(vector, [str, ogr.DataSource], "vector")
    type_check(
        projection,
        [str, int, ogr.DataSource, gdal.Dataset, osr.SpatialReference],
        "projection",
    )
    type_check(out_path, [str], "out_path", allow_none=True)
    type_check(copy_if_same, [bool], "copy_if_same")
    type_check(overwrite, [bool], "overwrite")

    vector_list, path_list = ready_io_vector(vector,
                                             out_path,
                                             overwrite=overwrite)
    origin = open_vector(vector_list[0])
    metadata = internal_vector_to_metadata(origin)
    out_name = path_list[0]

    origin_projection = metadata["projection_osr"]
    target_projection = parse_projection(projection)

    if not isinstance(target_projection, osr.SpatialReference):
        raise Exception("Error ")

    if origin_projection.IsSame(target_projection):
        if copy_if_same:
            if out_path is None:
                return internal_vector_to_memory(origin)

            return internal_vector_to_disk(origin, out_name)
        else:
            return get_vector_path(vector)

    # GDAL 3 changes axis order: https://github.com/OSGeo/gdal/issues/1546
    if int(osgeo.__version__[0]) >= 3:
        origin_projection.SetAxisMappingStrategy(
            osr.OAMS_TRADITIONAL_GIS_ORDER)
        target_projection.SetAxisMappingStrategy(
            osr.OAMS_TRADITIONAL_GIS_ORDER)

    coord_trans = osr.CoordinateTransformation(origin_projection,
                                               target_projection)

    remove_if_overwrite(out_path, overwrite)

    driver = ogr.GetDriverByName(path_to_driver_vector(out_name))
    destination: ogr.DataSource = driver.CreateDataSource(out_name)

    for layer_idx in range(len(metadata["layers"])):
        origin_layer = origin.GetLayerByIndex(layer_idx)
        origin_layer_defn = origin_layer.GetLayerDefn()

        layer_dict = metadata["layers"][layer_idx]
        layer_name = layer_dict["layer_name"]
        layer_geom_type = layer_dict["geom_type_ogr"]

        destination_layer = destination.CreateLayer(layer_name,
                                                    target_projection,
                                                    layer_geom_type)
        destination_layer_defn = destination_layer.GetLayerDefn()

        # Copy field definitions
        origin_layer_defn = origin_layer.GetLayerDefn()
        for i in range(0, origin_layer_defn.GetFieldCount()):
            field_defn = origin_layer_defn.GetFieldDefn(i)
            destination_layer.CreateField(field_defn)

        # Loop through the input features
        for _ in range(origin_layer.GetFeatureCount()):
            feature = origin_layer.GetNextFeature()
            geom = feature.GetGeometryRef()
            geom.Transform(coord_trans)

            new_feature = ogr.Feature(destination_layer_defn)
            new_feature.SetGeometry(geom)

            # Copy field values
            for i in range(0, destination_layer_defn.GetFieldCount()):
                new_feature.SetField(
                    destination_layer_defn.GetFieldDefn(i).GetNameRef(),
                    feature.GetField(i),
                )

            destination_layer.CreateFeature(new_feature)

        destination_layer.ResetReading()
        destination_layer = None

    destination.FlushCache()

    return out_name
Exemple #7
0
def internal_clip_vector(
    vector: Union[str, ogr.DataSource],
    clip_geom: Union[str, ogr.DataSource, gdal.Dataset],
    out_path: Optional[str] = None,
    process_layer: int = 0,
    process_layer_clip: int = 0,
    to_extent: bool = False,
    target_projection: Optional[Union[str, ogr.DataSource, gdal.Dataset,
                                      osr.SpatialReference, int]] = None,
    preserve_fid: bool = True,
) -> str:
    """Clips a vector to a geometry.

    Returns:
        A clipped ogr.Datasource or the path to one.
    """
    type_check(vector, [str, ogr.DataSource], "vector")
    type_check(clip_geom, [ogr.DataSource, gdal.Dataset, str, list, tuple],
               "clip_geom")
    type_check(out_path, [str], "out_path", allow_none=True)
    type_check(process_layer, [int], "process_layer")
    type_check(process_layer_clip, [int], "process_layer_clip")
    type_check(to_extent, [bool], "to_extent")
    type_check(
        target_projection,
        [str, ogr.DataSource, gdal.Dataset, osr.SpatialReference, int],
        "target_projection",
        allow_none=True,
    )
    type_check(preserve_fid, [bool], "preserve_fid")

    out_format = ".gpkg"
    out_target = f"/vsimem/clipped_{uuid4().int}{out_format}"

    if out_path is not None:
        out_target = out_path
        out_format = path_to_driver_vector(out_path)

    options = []

    geometry_to_clip = None
    if is_vector(clip_geom):
        if to_extent:
            extent = internal_vector_to_metadata(
                clip_geom, create_geometry=True)["extent_datasource"]
            geometry_to_clip = internal_vector_to_memory(extent)
        else:
            geometry_to_clip = open_vector(clip_geom, layer=process_layer_clip)
    elif is_raster(clip_geom):
        extent = internal_raster_to_metadata(
            clip_geom, create_geometry=True)["extent_datasource"]
        geometry_to_clip = internal_vector_to_memory(extent)
    else:
        raise ValueError(
            f"Invalid input in clip_geom, unable to parse: {clip_geom}")

    clip_vector_path = internal_vector_to_metadata(geometry_to_clip)["path"]
    options.append(f"-clipsrc {clip_vector_path}")

    if preserve_fid:
        options.append("-preserve_fid")
    else:
        options.append("-unsetFid")

    out_projection = None
    if target_projection is not None:
        out_projection = parse_projection(target_projection, return_wkt=True)
        options.append(f"-t_srs {out_projection}")

    origin = open_vector(vector, layer=process_layer)

    # dst  # src
    success = gdal.VectorTranslate(
        out_target,
        get_vector_path(origin),
        format=out_format,
        options=" ".join(options),
    )

    if success != 0:
        return out_target
    else:
        raise Exception("Error while clipping geometry.")
Exemple #8
0
def internal_dissolve_vector(
    vector: Union[str, ogr.DataSource],
    attribute: Optional[str] = None,
    out_path: str = None,
    overwrite: bool = True,
    add_index: bool = True,
    process_layer: int = -1,
) -> str:
    """Clips a vector to a geometry."""
    type_check(vector, [str, ogr.DataSource], "vector")
    type_check(attribute, [str], "attribute", allow_none=True)
    type_check(out_path, [str], "out_path", allow_none=True)
    type_check(overwrite, [bool], "overwrite")
    type_check(add_index, [bool], "add_index")
    type_check(process_layer, [int], "process_layer")

    vector_list, path_list = ready_io_vector(vector, out_path)
    out_name = path_list[0]
    out_format = path_to_driver_vector(out_name)

    driver = ogr.GetDriverByName(out_format)

    ref = open_vector(vector_list[0])
    metadata = internal_vector_to_metadata(ref)

    Layer_info = TypedDict(
        "Layer_info",
        {
            "name": str,
            "geom": str,
            "fields": List[str]
        },
    )

    layers: List[Layer_info] = []

    if process_layer == -1:
        for index in range(len(metadata["layers"])):
            layers.append({
                "name": metadata["layers"][index]["layer_name"],
                "geom": metadata["layers"][index]["column_geom"],
                "fields": metadata["layers"][index]["field_names"],
            })
    else:
        layers.append({
            "name":
            metadata["layers"][process_layer]["layer_name"],
            "geom":
            metadata["layers"][process_layer]["column_geom"],
            "fields":
            metadata["layers"][process_layer]["field_names"],
        })

    destination: ogr.DataSource = driver.CreateDataSource(out_name)

    # Check if attribute table is valid
    for index in range(len(metadata["layers"])):
        layer = layers[index]
        if attribute is not None and attribute not in layer["fields"]:
            layer_fields = layer["fields"]
            raise ValueError(
                f"Invalid attribute for layer. Layers has the following fields: {layer_fields}"
            )

        geom_col = layer["geom"]
        name = layer["name"]

        sql = None
        if attribute is None:
            sql = f"SELECT ST_Union({geom_col}) AS geom FROM {name};"
        else:
            sql = f"SELECT {attribute}, ST_Union({geom_col}) AS geom FROM {name} GROUP BY {attribute};"

        result = ref.ExecuteSQL(sql, dialect="SQLITE")
        destination.CopyLayer(result, name, ["OVERWRITE=YES"])

    if add_index:
        vector_add_index(destination)

    destination.FlushCache()

    return out_name
Exemple #9
0
def internal_multipart_to_singlepart(
    vector: Union[str, ogr.DataSource],
    out_path: Optional[str] = None,
    copy_attributes: bool = False,
    overwrite: bool = True,
    add_index: bool = True,
    process_layer: int = -1,
    verbose: int = 1,
) -> str:
    type_check(vector, [str, ogr.DataSource], "vector")
    type_check(out_path, [str], "out_path", allow_none=True)
    type_check(overwrite, [bool], "overwrite")
    type_check(add_index, [bool], "add_index")
    type_check(process_layer, [int], "process_layer")
    type_check(verbose, [int], "verbose")

    vector_list, path_list = ready_io_vector(vector, out_path, overwrite=overwrite)

    ref = open_vector(vector_list[0])
    out_name = path_list[0]

    driver = ogr.GetDriverByName(path_to_driver_vector(out_name))

    metadata = internal_vector_to_metadata(ref)

    remove_if_overwrite(out_name, overwrite)

    destination = driver.CreateDataSource(out_name)

    for index, layer_meta in enumerate(metadata["layers"]):
        if process_layer != -1 and index != process_layer:
            continue

        if verbose == 1:
            layer_name = layer_meta["layer_name"]
            print(f"Splitting layer: {layer_name}")

        target_unknown = False

        if layer_meta["geom_type_ogr"] == 4:  # MultiPoint
            target_type = 1  # Point
        elif layer_meta["geom_type_ogr"] == 5:  # MultiLineString
            target_type = 2  # LineString
        elif layer_meta["geom_type_ogr"] == 6:  # MultiPolygon
            target_type = 3  # Polygon
        elif layer_meta["geom_type_ogr"] == 1004:  # MultiPoint (z)
            target_type = 1001  # Point (z)
        elif layer_meta["geom_type_ogr"] == 1005:  # MultiLineString (z)
            target_type = 1002  # LineString (z)
        elif layer_meta["geom_type_ogr"] == 1006:  # MultiPolygon (z)
            target_type = 1003  # Polygon (z)
        elif layer_meta["geom_type_ogr"] == 2004:  # MultiPoint (m)
            target_type = 2001  # Point (m)
        elif layer_meta["geom_type_ogr"] == 2005:  # MultiLineString (m)
            target_type = 2002  # LineString (m)
        elif layer_meta["geom_type_ogr"] == 2006:  # MultiPolygon (m)
            target_type = 2003  # Polygon (m)
        elif layer_meta["geom_type_ogr"] == 3004:  # MultiPoint (zm)
            target_type = 3001  # Point (m)
        elif layer_meta["geom_type_ogr"] == 3005:  # MultiLineString (zm)
            target_type = 3002  # LineString (m)
        elif layer_meta["geom_type_ogr"] == 3006:  # MultiPolygon (zm)
            target_type = 3003  # Polygon (m)
        else:
            target_unknown = True
            target_type = layer_meta["geom_type_ogr"]

        destination_layer = destination.CreateLayer(
            layer_meta["layer_name"], layer_meta["projection_osr"], target_type
        )
        layer_defn = destination_layer.GetLayerDefn()
        field_count = layer_meta["field_count"]

        original_target = ref.GetLayerByIndex(index)
        feature_count = original_target.GetFeatureCount()

        if copy_attributes:
            first_feature = original_target.GetNextFeature()
            original_target.ResetReading()

            if verbose == 1:
                print("Creating attribute fields")

            for field_id in range(field_count):
                field_defn = first_feature.GetFieldDefnRef(field_id)

                fname = field_defn.GetName()
                ftype = field_defn.GetTypeName()
                fwidth = field_defn.GetWidth()
                fprecision = field_defn.GetPrecision()

                if ftype == "String" or ftype == "Date":
                    fielddefn = ogr.FieldDefn(fname, ogr.OFTString)
                    fielddefn.SetWidth(fwidth)
                elif ftype == "Real":
                    fielddefn = ogr.FieldDefn(fname, ogr.OFTReal)
                    fielddefn.SetWidth(fwidth)
                    fielddefn.SetPrecision(fprecision)
                else:
                    fielddefn = ogr.FieldDefn(fname, ogr.OFTInteger)

                destination_layer.CreateField(fielddefn)

        for _ in range(feature_count):
            feature = original_target.GetNextFeature()
            geom = feature.GetGeometryRef()

            if target_unknown:
                out_feat = ogr.Feature(layer_defn)
                out_feat.SetGeometry(geom)

                if copy_attributes:
                    for field_id in range(field_count):
                        values = feature.GetField(field_id)
                        out_feat.SetField(field_id, values)

                destination_layer.CreateFeature(out_feat)

            for geom_part in geom:
                out_feat = ogr.Feature(layer_defn)
                out_feat.SetGeometry(geom_part)

                if copy_attributes:
                    for field_id in range(field_count):
                        values = feature.GetField(field_id)
                        out_feat.SetField(field_id, values)

                destination_layer.CreateFeature(out_feat)

            if verbose == 1:
                progress(_, feature_count - 1, "Splitting.")

    if add_index:
        vector_add_index(destination)

    return out_name