Skip to content

Commit

Permalink
Draft of a geometry operations applicator
Browse files Browse the repository at this point in the history
Resolves #982
  • Loading branch information
sgillies committed Jun 3, 2022
1 parent ff313b3 commit 2259e43
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 2 deletions.
61 changes: 61 additions & 0 deletions fiona/_transform.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ from collections import UserDict

from fiona cimport _cpl, _csl, _geometry
from fiona.crs cimport OGRSpatialReferenceH, osr_set_traditional_axis_mapping_strategy
from fiona._err cimport exc_wrap_pointer

from fiona.compat import DICT_TYPES
from fiona.crs import CRS
Expand Down Expand Up @@ -263,3 +264,63 @@ def _transform_geom(src_crs, dst_crs, geom, antimeridian_cutting, antimeridian_o
OSRRelease(dst)

return out_geom


from libcpp.unordered_map cimport unordered_map

cdef OGRGeometryH segmentize(OGRGeometryH geom, double max_length):
cdef OGRGeometryH new_geom = NULL
new_geom = OGR_G_Clone(geom)
OGR_G_Segmentize(new_geom, max_length)
return new_geom


ctypedef OGRGeometryH (*geometry_func)(OGRGeometryH, double)
cdef unordered_map[int, geometry_func] func_map

func_map[1] = <geometry_func>segmentize

cdef geometry_func func_alias(int choice):
return func_map[choice]


def apply_geom(operations, geoms):
"""Apply a series of geometry transforming operations to one or more geometries.
Parameters
----------
operations: list
A list of operation names and extra arg as a tuple.
geoms: Geometry or Sequence[Geometry]
Geometries on which to apply operations.
Yields
------
Geometry
"""
cdef OGRGeometryH ogr_geom1 = NULL
cdef OGRGeometryH ogr_geom2 = NULL
cdef int choice = 0

op_map = {
"segmentize": 1
}

for geom in geoms:
ogr_geom1 = _geometry.OGRGeomBuilder().build(geom)

for op_name, op_arg in operations:
choice = op_map[op_name]
ogr_geom2 = func_alias(choice)(ogr_geom1, op_arg)
ogr_geom2 = exc_wrap_pointer(ogr_geom2)
OGR_G_DestroyGeometry(ogr_geom1)
ogr_geom1 = ogr_geom2

if ogr_geom2 == NULL:
raise Exception("NULL geometry")

output_geom = _geometry.GeomBuilder().build(ogr_geom2)
OGR_G_DestroyGeometry(ogr_geom2)

yield output_geom
3 changes: 3 additions & 0 deletions fiona/gdal.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,9 @@ cdef extern from "ogr_api.h" nogil:
void OGR_G_ImportFromWkb(OGRGeometryH geometry, unsigned char *bytes,
int nbytes)
int OGR_G_WkbSize(OGRGeometryH geometry)

void OGR_G_Segmentize(OGRGeometryH hGeom, double dfMaxLength)

OGRErr OGR_L_CreateFeature(OGRLayerH layer, OGRFeatureH feature)
int OGR_L_CreateField(OGRLayerH layer, OGRFieldDefnH, int flexible)
OGRErr OGR_L_GetExtent(OGRLayerH layer, void *extent, int force)
Expand Down
4 changes: 2 additions & 2 deletions fiona/ogrext.pyx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# These are extension functions and classes using the OGR C API.
"""Extension functions and classes using the OGR C API."""

from __future__ import absolute_import

include "gdal.pxi"
Expand Down Expand Up @@ -165,7 +166,6 @@ cdef void* gdal_create(void* cogr_driver, const char *path_c, options) except NU
CSLDestroy(creation_opts)



def _explode(coords):
"""Explode a GeoJSON geometry's coordinates object and yield
coordinate tuples. As long as the input is conforming, the type of
Expand Down
10 changes: 10 additions & 0 deletions tests/test_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,13 @@ def test_transform_issue971():
(512364.6014999999, 5866328.260199999)]}]}
geom_transformed = transform.transform_geom(source_crs, dest_src, geom, precision=3)
assert geom_transformed['geometries'][0]['coordinates'][0] == pytest.approx((9.184, 52.946))


def test_apply_geom():
from fiona._transform import apply_geom
from fiona.model import Geometry

input_geom = Geometry(type="LineString", coordinates=[(0, 0), (0, 10)])
output_geom = next(apply_geom([("segmentize", 1.0)], [input_geom]))
assert len(output_geom.coordinates) == 11
assert output_geom.coordinates[1] == (0.0, 1.0)

0 comments on commit 2259e43

Please sign in to comment.