Refs #35058 -- Added support for measured geometries to GDAL LineString.

This commit is contained in:
David Smith 2024-01-25 12:55:45 +00:00 committed by Mariusz Felisiak
parent 41aaf5aafa
commit 1df8983aa3
5 changed files with 57 additions and 11 deletions

View File

@ -625,10 +625,14 @@ class LineString(OGRGeometry):
def __getitem__(self, index): def __getitem__(self, index):
"Return the Point at the given index." "Return the Point at the given index."
if 0 <= index < self.point_count: if 0 <= index < self.point_count:
x, y, z = c_double(), c_double(), c_double() x, y, z, m = c_double(), c_double(), c_double(), c_double()
capi.get_point(self.ptr, index, byref(x), byref(y), byref(z)) capi.get_point(self.ptr, index, byref(x), byref(y), byref(z), byref(m))
if self.is_3d and self.is_measured:
return x.value, y.value, z.value, m.value
if self.is_3d: if self.is_3d:
return x.value, y.value, z.value return x.value, y.value, z.value
if self.is_measured:
return x.value, y.value, m.value
dim = self.coord_dim dim = self.coord_dim
if dim == 1: if dim == 1:
return (x.value,) return (x.value,)
@ -673,6 +677,12 @@ class LineString(OGRGeometry):
if self.is_3d: if self.is_3d:
return self._listarr(capi.getz) return self._listarr(capi.getz)
@property
def m(self):
"""Return the M coordinates in a list."""
if self.is_measured:
return self._listarr(capi.getm)
# LinearRings are used in Polygons. # LinearRings are used in Polygons.
class LinearRing(LineString): class LinearRing(LineString):
@ -789,9 +799,11 @@ GEO_CLASSES = {
7: GeometryCollection, 7: GeometryCollection,
101: LinearRing, 101: LinearRing,
2001: Point, # POINT M 2001: Point, # POINT M
2002: LineString, # LINESTRING M
3001: Point, # POINT ZM 3001: Point, # POINT ZM
3002: LineString, # LINESTRING ZM
1 + OGRGeomType.wkb25bit: Point, # POINT Z 1 + OGRGeomType.wkb25bit: Point, # POINT Z
2 + OGRGeomType.wkb25bit: LineString, 2 + OGRGeomType.wkb25bit: LineString, # LINESTRING Z
3 + OGRGeomType.wkb25bit: Polygon, 3 + OGRGeomType.wkb25bit: Polygon,
4 + OGRGeomType.wkb25bit: MultiPoint, 4 + OGRGeomType.wkb25bit: MultiPoint,
5 + OGRGeomType.wkb25bit: MultiLineString, 5 + OGRGeomType.wkb25bit: MultiLineString,

View File

@ -137,8 +137,15 @@ get_geom_name = const_string_output(
get_geom_type = int_output(lgdal.OGR_G_GetGeometryType, [c_void_p]) get_geom_type = int_output(lgdal.OGR_G_GetGeometryType, [c_void_p])
get_point_count = int_output(lgdal.OGR_G_GetPointCount, [c_void_p]) get_point_count = int_output(lgdal.OGR_G_GetPointCount, [c_void_p])
get_point = void_output( get_point = void_output(
lgdal.OGR_G_GetPoint, lgdal.OGR_G_GetPointZM,
[c_void_p, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_double)], [
c_void_p,
c_int,
POINTER(c_double),
POINTER(c_double),
POINTER(c_double),
POINTER(c_double),
],
errcheck=False, errcheck=False,
) )
geom_close_rings = void_output(lgdal.OGR_G_CloseRings, [c_void_p], errcheck=False) geom_close_rings = void_output(lgdal.OGR_G_CloseRings, [c_void_p], errcheck=False)

View File

@ -936,6 +936,17 @@ coordinate transformation:
>>> OGRGeometry("LINESTRING (1 2 3,4 5 6)").z >>> OGRGeometry("LINESTRING (1 2 3,4 5 6)").z
[3.0, 6.0] [3.0, 6.0]
.. attribute:: m
.. versionadded:: 5.1
Returns a list of M coordinates in this line or ``None`` if the line does
not have M coordinates:
.. code-block:: pycon
>>> OGRGeometry("LINESTRING(0 1 2 10, 1 2 3 11, 2 3 4 12)").m
[10.0, 11.0, 12.0]
.. class:: Polygon .. class:: Polygon

View File

@ -78,10 +78,11 @@ Minor features
* The new :meth:`.OGRGeometry.set_3d` method allows addition and removal of the * The new :meth:`.OGRGeometry.set_3d` method allows addition and removal of the
``Z`` coordinate dimension. ``Z`` coordinate dimension.
* :class:`~django.contrib.gis.gdal.OGRGeometry` and * :class:`~django.contrib.gis.gdal.OGRGeometry`,
:class:`~django.contrib.gis.gdal.Point` now support measured geometries :class:`~django.contrib.gis.gdal.Point`, and
via the new :attr:`.OGRGeometry.is_measured` and :attr:`.Point.m` properties, :class:`~django.contrib.gis.gdal.LineString` now support measured geometries
and the :meth:`.OGRGeometry.set_measured` method. via the new :attr:`.OGRGeometry.is_measured` and ``m`` properties, and the
:meth:`.OGRGeometry.set_measured` method.
* :attr:`.OGRGeometry.centroid` is now available on all supported geometry * :attr:`.OGRGeometry.centroid` is now available on all supported geometry
types. types.

View File

@ -673,7 +673,7 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
("TIN Z", 1016, False), ("TIN Z", 1016, False),
("Triangle Z", 1017, False), ("Triangle Z", 1017, False),
("Point M", 2001, True), ("Point M", 2001, True),
("LineString M", 2002, False), ("LineString M", 2002, True),
("Polygon M", 2003, False), ("Polygon M", 2003, False),
("MultiPoint M", 2004, False), ("MultiPoint M", 2004, False),
("MultiLineString M", 2005, False), ("MultiLineString M", 2005, False),
@ -688,7 +688,7 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
("TIN M", 2016, False), ("TIN M", 2016, False),
("Triangle M", 2017, False), ("Triangle M", 2017, False),
("Point ZM", 3001, True), ("Point ZM", 3001, True),
("LineString ZM", 3002, False), ("LineString ZM", 3002, True),
("Polygon ZM", 3003, False), ("Polygon ZM", 3003, False),
("MultiPoint ZM", 3004, False), ("MultiPoint ZM", 3004, False),
("MultiLineString ZM", 3005, False), ("MultiLineString ZM", 3005, False),
@ -900,6 +900,21 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
) )
self.assertEqual(geometrycollection.centroid.wkt, "POINT (110 30)") self.assertEqual(geometrycollection.centroid.wkt, "POINT (110 30)")
def test_linestring_m_dimension(self):
geom = OGRGeometry("LINESTRING(0 1 2 10, 1 2 3 11, 2 3 4 12)")
self.assertIs(geom.is_measured, True)
self.assertEqual(geom.m, [10.0, 11.0, 12.0])
self.assertEqual(geom[0], (0.0, 1.0, 2.0, 10.0))
geom = OGRGeometry("LINESTRING M (0 1 10, 1 2 11)")
self.assertIs(geom.is_measured, True)
self.assertEqual(geom.m, [10.0, 11.0])
self.assertEqual(geom[0], (0.0, 1.0, 10.0))
geom.set_measured(False)
self.assertIs(geom.is_measured, False)
self.assertIs(geom.m, None)
class DeprecationTests(SimpleTestCase): class DeprecationTests(SimpleTestCase):
def test_coord_setter_deprecation(self): def test_coord_setter_deprecation(self):