Skip to content

Commit

Permalink
Refs #34406 -- Added support for GDAL curved geometries.
Browse files Browse the repository at this point in the history
Co-authored-by: Fabien Le Frapper <[email protected]>
  • Loading branch information
smithdc1 and fabienheureux authored Oct 22, 2024
1 parent dd0a116 commit 04adff9
Show file tree
Hide file tree
Showing 6 changed files with 292 additions and 23 deletions.
63 changes: 61 additions & 2 deletions django/contrib/gis/gdal/geometries.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class OGRGeometry(GDALBase):
"""Encapsulate an OGR geometry."""

destructor = capi.destroy_geom
geos_support = True

def __init__(self, geom_input, srs=None):
"""Initialize Geometry on either WKT or an OGR pointer as input."""
Expand Down Expand Up @@ -304,6 +305,19 @@ def set_measured(self, value):
f"Input to 'set_measured' must be a boolean, got '{value!r}'."
)

@property
def has_curve(self):
"""Return True if the geometry is or has curve geometry."""
return capi.has_curve_geom(self.ptr, 0)

def get_linear_geometry(self):
"""Return a linear version of this geometry."""
return OGRGeometry(capi.get_linear_geom(self.ptr, 0, None))

def get_curve_geometry(self):
"""Return a curve version of this geometry."""
return OGRGeometry(capi.get_curve_geom(self.ptr, None))

# #### SpatialReference-related Properties ####

# The SRS property
Expand Down Expand Up @@ -360,9 +374,14 @@ def _geos_ptr(self):
@property
def geos(self):
"Return a GEOSGeometry object from this OGRGeometry."
from django.contrib.gis.geos import GEOSGeometry
if self.geos_support:
from django.contrib.gis.geos import GEOSGeometry

return GEOSGeometry(self._geos_ptr(), self.srid)
return GEOSGeometry(self._geos_ptr(), self.srid)
else:
from django.contrib.gis.geos import GEOSException

raise GEOSException(f"GEOS does not support {self.__class__.__qualname__}.")

@property
def gml(self):
Expand Down Expand Up @@ -727,6 +746,18 @@ def point_count(self):
return sum(self[i].point_count for i in range(self.geom_count))


class CircularString(LineString):
geos_support = False


class CurvePolygon(Polygon):
geos_support = False


class CompoundCurve(OGRGeometry):
geos_support = False


# Geometry Collection base class.
class GeometryCollection(OGRGeometry):
"The Geometry Collection class."
Expand Down Expand Up @@ -788,6 +819,14 @@ class MultiPolygon(GeometryCollection):
pass


class MultiSurface(GeometryCollection):
geos_support = False


class MultiCurve(GeometryCollection):
geos_support = False


# Class mapping dictionary (using the OGRwkbGeometryType as the key)
GEO_CLASSES = {
1: Point,
Expand All @@ -797,21 +836,41 @@ class MultiPolygon(GeometryCollection):
5: MultiLineString,
6: MultiPolygon,
7: GeometryCollection,
8: CircularString,
9: CompoundCurve,
10: CurvePolygon,
11: MultiCurve,
12: MultiSurface,
101: LinearRing,
1008: CircularString, # CIRCULARSTRING Z
1009: CompoundCurve, # COMPOUNDCURVE Z
1010: CurvePolygon, # CURVEPOLYGON Z
1011: MultiCurve, # MULTICURVE Z
1012: MultiSurface, # MULTICURVE Z
2001: Point, # POINT M
2002: LineString, # LINESTRING M
2003: Polygon, # POLYGON M
2004: MultiPoint, # MULTIPOINT M
2005: MultiLineString, # MULTILINESTRING M
2006: MultiPolygon, # MULTIPOLYGON M
2007: GeometryCollection, # GEOMETRYCOLLECTION M
2008: CircularString, # CIRCULARSTRING M
2009: CompoundCurve, # COMPOUNDCURVE M
2010: CurvePolygon, # CURVEPOLYGON M
2011: MultiCurve, # MULTICURVE M
2012: MultiSurface, # MULTICURVE M
3001: Point, # POINT ZM
3002: LineString, # LINESTRING ZM
3003: Polygon, # POLYGON ZM
3004: MultiPoint, # MULTIPOINT ZM
3005: MultiLineString, # MULTILINESTRING ZM
3006: MultiPolygon, # MULTIPOLYGON ZM
3007: GeometryCollection, # GEOMETRYCOLLECTION ZM
3008: CircularString, # CIRCULARSTRING ZM
3009: CompoundCurve, # COMPOUNDCURVE ZM
3010: CurvePolygon, # CURVEPOLYGON ZM
3011: MultiCurve, # MULTICURVE ZM
3012: MultiSurface, # MULTISURFACE ZM
1 + OGRGeomType.wkb25bit: Point, # POINT Z
2 + OGRGeomType.wkb25bit: LineString, # LINESTRING Z
3 + OGRGeomType.wkb25bit: Polygon, # POLYGON Z
Expand Down
7 changes: 7 additions & 0 deletions django/contrib/gis/gdal/prototypes/geom.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ def topology_func(f):
set_3d = void_output(lgdal.OGR_G_Set3D, [c_void_p, c_int], errcheck=False)
is_measured = bool_output(lgdal.OGR_G_IsMeasured, [c_void_p])
set_measured = void_output(lgdal.OGR_G_SetMeasured, [c_void_p, c_int], errcheck=False)
has_curve_geom = bool_output(lgdal.OGR_G_HasCurveGeometry, [c_void_p, c_int])
get_linear_geom = geom_output(
lgdal.OGR_G_GetLinearGeometry, [c_void_p, c_double, POINTER(c_char_p)]
)
get_curve_geom = geom_output(
lgdal.OGR_G_GetCurveGeometry, [c_void_p, POINTER(c_char_p)]
)

# Geometry modification routines.
add_geom = void_output(lgdal.OGR_G_AddGeometry, [c_void_p, c_void_p])
Expand Down
20 changes: 20 additions & 0 deletions docs/ref/contrib/gis/gdal.txt
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,26 @@ coordinate transformation:
>>> polygon.geom_count
1

.. attribute:: has_curve

.. versionadded:: 5.2

A boolean indicating if this geometry is or contains a curve geometry.

.. method:: get_linear_geometry

.. versionadded:: 5.2

Returns a linear version of the geometry. If no conversion can be made, the
original geometry is returned.

.. method:: get_curve_geometry

.. versionadded:: 5.2

Returns a curved version of the geometry. If no conversion can be made, the
original geometry is returned.

.. attribute:: point_count

Returns the number of points used to describe this geometry:
Expand Down
6 changes: 5 additions & 1 deletion docs/releases/5.2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,11 @@ Minor features
:mod:`django.contrib.gis`
~~~~~~~~~~~~~~~~~~~~~~~~~

* ...
* GDAL now supports curved geometries ``CurvePolygon``, ``CompoundCurve``,
``CircularString``, ``MultiSurface``, and ``MultiCurve`` via the new
:attr:`.OGRGeometry.has_curve` property, and the
:meth:`.OGRGeometry.get_linear_geometry` and
:meth:`.OGRGeometry.get_curve_geometry` methods.

:mod:`django.contrib.messages`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
82 changes: 82 additions & 0 deletions tests/gis_tests/data/geometries.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,5 +137,87 @@
"union_geoms": [
{"wkt": "POLYGON ((-5 0,-5 10,5 10,5 5,10 5,10 -5,0 -5,0 0,-5 0))"},
{"wkt": "POLYGON ((2 0, 2 15, 18 15, 18 0, 2 0))"}
],
"curved_geoms": [
{"wkt": "CIRCULARSTRING(1 5, 6 2, 7 3)",
"name": "CircularString",
"num": 8
},
{"wkt": "COMPOUNDCURVE((5 3, 5 13), CIRCULARSTRING(5 13, 7 15, 9 13), (9 13, 9 3), CIRCULARSTRING(9 3, 7 1, 5 3))",
"name": "CompoundCurve",
"num": 9
},
{"wkt": "CURVEPOLYGON(CIRCULARSTRING(0 0, 4 0, 4 4, 0 4, 0 0),(1 1, 3 3, 3 1, 1 1))",
"name": "CurvePolygon",
"num": 10
},
{"wkt": "MULTICURVE((0 0, 5 5), CIRCULARSTRING(4 0, 4 4, 8 4))",
"name": "MultiCurve",
"num": 11
},
{"wkt": "MULTISURFACE(((0 0, 0 1, 1 1, 1 0, 0 0)), ((1 1, 1 2, 2 2, 2 1, 1 1)))",
"name": "MultiSurface",
"num": 12
},
{"wkt": "CIRCULARSTRING Z (1 5 1, 6 2 2, 7 3 3)",
"name": "CircularStringZ",
"num": 1008
},
{"wkt": "COMPOUNDCURVE Z ((5 3 0, 5 13 0), CIRCULARSTRING Z (5 13 0, 7 15 0, 9 13 0), (9 13 0 , 9 3 0), CIRCULARSTRING(9 3 0, 7 1 0, 5 3 0))",
"name": "CompoundCurveZ",
"num": 1009
},
{"wkt": "CURVEPOLYGON Z(CIRCULARSTRING Z (0 0 0, 4 0 0, 4 4 0, 0 4 0, 0 0 0),(1 1 0, 3 3 0, 3 1 0, 1 1 0))",
"name": "CurvePolygonZ",
"num": 1010
},
{"wkt": "MULTICURVE Z ((0 0 1, 5 5 2), CIRCULARSTRING Z (4 0 0, 4 4 0, 8 4 0))",
"name": "MultiCurveZ",
"num": 1011
},
{"wkt": "MULTISURFACE Z (((0 0 1, 0 1 2, 1 1 3, 1 0 4, 0 0 5)), ((1 1 0, 1 2 0, 2 2 0, 2 1 0, 1 1 0)))",
"name": "MultiSurfaceZ",
"num": 1012
},
{"wkt": "CIRCULARSTRING M (1 5 1, 6 2 2, 7 3 3)",
"name": "CircularStringM",
"num": 2008
},
{"wkt": "COMPOUNDCURVE M ((5 3 0, 5 13 0), CIRCULARSTRING M (5 13 0, 7 15 0, 9 13 0), (9 13 0 , 9 3 0), CIRCULARSTRING M (9 3 0, 7 1 0, 5 3 0))",
"name": "CompoundCurveM",
"num": 2009
},
{"wkt": "CURVEPOLYGON M (CIRCULARSTRING M (0 0 0, 4 0 0, 4 4 0, 0 4 0, 0 0 0),(1 1 0, 3 3 1, 3 1 1, 1 1 2))",
"name": "CurvePolygonM",
"num": 2010
},
{"wkt": "MULTICURVE M ((0 0 1, 5 5 2), CIRCULARSTRING M (4 0 0, 4 4 0, 8 4 0))",
"name": "MultiCurveM",
"num": 2011
},
{"wkt": "MULTISURFACE M (((0 0 1, 0 1 2, 1 1 3, 1 0 4, 0 0 5)), ((1 1 0, 1 2 0, 2 2 0, 2 1 0, 1 1 0)))",
"name": "MultiSurfaceM",
"num": 2012
},
{"wkt": "CIRCULARSTRING ZM (1 5 0 1, 6 2 0 2, 7 3 0 3)",
"name": "CircularStringZM",
"num": 3008
},
{"wkt": "COMPOUNDCURVE ZM ((5 3 0 0, 5 13 0 0), CIRCULARSTRING ZM (5 13 0 0, 7 15 0 0, 9 13 0 0), (9 13 0 0, 9 3 0 0), CIRCULARSTRING ZM (9 3 0 0, 7 1 0 0, 5 3 0 0))",
"name": "CompoundCurveZM",
"num": 3009
},
{"wkt": "CURVEPOLYGON ZM (CIRCULARSTRING ZM (0 0 0 0, 4 0 0 0, 4 4 0 0, 0 4 0 0, 0 0 0 0), (1 1 0 0, 3 3 0 0, 3 1 0 0, 1 1 0 0))",
"name": "CurvePolygonZM",
"num": 3010
},
{"wkt": "MULTICURVE ZM ((0 0 0 1, 5 5 0 2), CIRCULARSTRING ZM (4 0 0 0, 4 4 0 0, 8 4 0 0))",
"name": "MultiCurveZM",
"num": 3011
},
{"wkt": "MULTISURFACE ZM (((0 0 0 1, 0 1 0 2, 1 1 0 3, 1 0 0 4, 0 0 0 5)), ((1 1 0 0, 1 2 0 0, 2 2 0 0, 2 1 0 0, 1 1 0 0)))",
"name": "MultiSurfaceZM",
"num": 3012
}
]
}
Loading

0 comments on commit 04adff9

Please sign in to comment.