Source code for centerline.converters
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import logging
import os
import click
import fiona
from osgeo import gdal, ogr
from shapely.geometry import mapping, shape
from .exceptions import (
InvalidInputTypeError,
TooFewRidgesError,
UnsupportedVectorType,
)
from .geometry import Centerline
# Enable GDAL/OGR exceptions
gdal.UseExceptions()
@click.command()
@click.argument("src", nargs=1, type=click.Path(exists=True))
@click.argument("dst", nargs=1, type=click.Path(exists=False))
@click.option(
"--interpolation-distance",
default=0.5,
show_default=True,
help=(
"Densify the input geometry's border by placing additional "
"points at this distance"
),
)
def create_centerlines(src, dst, interpolation_distance=0.5):
"""Convert the geometries from the ``src`` file to centerlines in
the ``dst`` file.
Use the ``interpolation_distance`` parameter to adjust the level of
detail you want the centerlines to be produced with.
Only polygons and multipolygons are converted to centerlines,
whereas the other geometries are skipped. The polygon's attributes
are copied to its ``Centerline`` object.
If the ``interpolation_distance`` factor does not suit the polygon's
geometry, the ``TooFewRidgesError`` error is logged as a warning.
You should try readjusting the ``interpolation_distance`` factor and
rerun the command.
:param src: path to the file containing input geometries
:type src: str
:param dst: path to the file that will contain the centerlines
:type dst: str
:param interpolation_distance: densify the input geometry's
border by placing additional points at this distance, defaults
to 0.5 [meter].
:type interpolation_distance: float, optional
:return: ``dst`` file is generated
:rtype: None
"""
with fiona.Env():
with fiona.open(src, mode="r") as source_file:
schema = source_file.schema.copy()
schema.update({"geometry": "MultiLineString"})
driver = get_ogr_driver(filepath=dst)
with fiona.open(
dst,
mode="w",
driver=driver.GetName(),
schema=schema,
crs=source_file.crs,
encoding=source_file.encoding,
) as destination_file:
for record in source_file:
geom = record.get("geometry")
input_geom = shape(geom)
attributes = record.get("properties")
try:
centerline_obj = Centerline(
input_geom, interpolation_distance, **attributes
)
except (InvalidInputTypeError, TooFewRidgesError) as error:
logging.warning(error)
continue
centerline_dict = {
"geometry": mapping(centerline_obj.geometry),
"properties": {
k: v
for k, v in centerline_obj.__dict__.items()
if k in attributes.keys()
},
}
destination_file.write(centerline_dict)
return None
[docs]def get_ogr_driver(filepath):
"""Get the OGR driver based on the file's extension.
:param filepath: file's path
:type filepath: str
:raises UnsupportedVectorType: unsupported extension
:return: OGR driver
:rtype: osgeo.ogr.Driver
"""
filename, file_extension = os.path.splitext(filepath)
extension = file_extension[1:]
ogr_driver_count = ogr.GetDriverCount()
for idx in range(ogr_driver_count):
driver = ogr.GetDriver(idx)
driver_extension = driver.GetMetadataItem(str("DMD_EXTENSION")) or ""
driver_extensions = driver.GetMetadataItem(str("DMD_EXTENSIONS")) or ""
if extension == driver_extension or extension in driver_extensions:
return driver
raise UnsupportedVectorType