Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed #18919 -- Stopped dropping Z attribute when transforming geomet…

…ries

Previously, the wkb of geometries was dropping the Z attribute.
Thanks luizvital for the report and tests and georger.silva@gmail.com
for the tests.
  • Loading branch information...
commit ffdd6595ea2220f8e8a6fb3aacd3213b751d982f 1 parent 82a74dc
@claudep claudep authored
View
43 django/contrib/gis/geos/geometry.py
@@ -25,7 +25,7 @@
# These functions provide access to a thread-local instance
# of their corresponding GEOS I/O class.
-from django.contrib.gis.geos.prototypes.io import wkt_r, wkt_w, wkb_r, wkb_w, ewkb_w, ewkb_w3d
+from django.contrib.gis.geos.prototypes.io import wkt_r, wkt_w, wkb_r, wkb_w, ewkb_w
# For recognizing geometry input.
from django.contrib.gis.geometry.regex import hex_regex, wkt_regex, json_regex
@@ -388,28 +388,24 @@ def wkt(self):
def hex(self):
"""
Returns the WKB of this Geometry in hexadecimal form. Please note
- that the SRID and Z values are not included in this representation
- because it is not a part of the OGC specification (use the `hexewkb`
- property instead).
+ that the SRID is not included in this representation because it is not
+ a part of the OGC specification (use the `hexewkb` property instead).
"""
# A possible faster, all-python, implementation:
# str(self.wkb).encode('hex')
- return wkb_w().write_hex(self)
+ return wkb_w(self.hasz and 3 or 2).write_hex(self)
@uruz
uruz added a note

Style comment: this is better written with 3 if self.hasz else 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@property
def hexewkb(self):
"""
Returns the EWKB of this Geometry in hexadecimal form. This is an
- extension of the WKB specification that includes SRID and Z values
- that are a part of this geometry.
- """
- if self.hasz:
- if not GEOS_PREPARE:
- # See: http://trac.osgeo.org/geos/ticket/216
- raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D HEXEWKB.')
- return ewkb_w3d().write_hex(self)
- else:
- return ewkb_w().write_hex(self)
+ extension of the WKB specification that includes SRID value that are
+ a part of this geometry.
+ """
+ if self.hasz and not GEOS_PREPARE:
+ # See: http://trac.osgeo.org/geos/ticket/216
+ raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D HEXEWKB.')
+ return ewkb_w(self.hasz and 3 or 2).write_hex(self)
@property
def json(self):
@@ -429,22 +425,19 @@ def wkb(self):
as a Python buffer. SRID and Z values are not included, use the
`ewkb` property instead.
"""
- return wkb_w().write(self)
+ return wkb_w(self.hasz and 3 or 2).write(self)
@property
def ewkb(self):
"""
Return the EWKB representation of this Geometry as a Python buffer.
This is an extension of the WKB specification that includes any SRID
- and Z values that are a part of this geometry.
+ value that are a part of this geometry.
"""
- if self.hasz:
- if not GEOS_PREPARE:
- # See: http://trac.osgeo.org/geos/ticket/216
- raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D EWKB.')
- return ewkb_w3d().write(self)
- else:
- return ewkb_w().write(self)
+ if self.hasz and not GEOS_PREPARE:
+ # See: http://trac.osgeo.org/geos/ticket/216
+ raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D EWKB.')
+ return ewkb_w(self.hasz and 3 or 2).write(self)
@property
def kml(self):
@@ -516,7 +509,7 @@ def transform(self, ct, clone=False):
raise GEOSException("GDAL library is not available to transform() geometry.")
# Creating an OGR Geometry, which is then transformed.
- g = gdal.OGRGeometry(self.wkb, srid)
+ g = self.ogr
g.transform(ct)
# Getting a new GEOS pointer
ptr = wkb_r().read(g.wkb)
View
14 django/contrib/gis/geos/prototypes/io.py
@@ -207,7 +207,6 @@ class ThreadLocalIO(threading.local):
wkb_r = None
wkb_w = None
ewkb_w = None
- ewkb_w3d = None
thread_context = ThreadLocalIO()
@@ -228,20 +227,15 @@ def wkb_r():
thread_context.wkb_r = _WKBReader()
return thread_context.wkb_r
-def wkb_w():
+def wkb_w(dim=2):
if not thread_context.wkb_w:
thread_context.wkb_w = WKBWriter()
+ thread_context.wkb_w.outdim = dim
return thread_context.wkb_w
-def ewkb_w():
+def ewkb_w(dim=2):
if not thread_context.ewkb_w:
thread_context.ewkb_w = WKBWriter()
thread_context.ewkb_w.srid = True
+ thread_context.ewkb_w.outdim = dim
return thread_context.ewkb_w
-
-def ewkb_w3d():
- if not thread_context.ewkb_w3d:
- thread_context.ewkb_w3d = WKBWriter()
- thread_context.ewkb_w3d.srid = True
- thread_context.ewkb_w3d.outdim = 3
- return thread_context.ewkb_w3d
View
29 django/contrib/gis/geos/tests/test_geos.py
@@ -92,6 +92,7 @@ def test_hexewkb(self):
"Testing (HEX)EWKB output."
# For testing HEX(EWKB).
ogc_hex = b'01010000000000000000000000000000000000F03F'
+ ogc_hex_3d = b'01010000800000000000000000000000000000F03F0000000000000040'
# `SELECT ST_AsHEXEWKB(ST_GeomFromText('POINT(0 1)', 4326));`
hexewkb_2d = b'0101000020E61000000000000000000000000000000000F03F'
# `SELECT ST_AsHEXEWKB(ST_GeomFromEWKT('SRID=4326;POINT(0 1 2)'));`
@@ -100,9 +101,9 @@ def test_hexewkb(self):
pnt_2d = Point(0, 1, srid=4326)
pnt_3d = Point(0, 1, 2, srid=4326)
- # OGC-compliant HEX will not have SRID nor Z value.
+ # OGC-compliant HEX will not have SRID value.
self.assertEqual(ogc_hex, pnt_2d.hex)
- self.assertEqual(ogc_hex, pnt_3d.hex)
+ self.assertEqual(ogc_hex_3d, pnt_3d.hex)
# HEXEWKB should be appropriate for its dimension -- have to use an
# a WKBWriter w/dimension set accordingly, else GEOS will insert
@@ -830,12 +831,17 @@ def test_collections_of_collections(self):
def test_gdal(self):
"Testing `ogr` and `srs` properties."
g1 = fromstr('POINT(5 23)')
- self.assertEqual(True, isinstance(g1.ogr, gdal.OGRGeometry))
- self.assertEqual(g1.srs, None)
+ self.assertIsInstance(g1.ogr, gdal.OGRGeometry)
+ self.assertIsNone(g1.srs)
+
+ if GEOS_PREPARE:
+ g1_3d = fromstr('POINT(5 23 8)')
+ self.assertIsInstance(g1_3d.ogr, gdal.OGRGeometry)
+ self.assertEqual(g1_3d.ogr.z, 8)
g2 = fromstr('LINESTRING(0 0, 5 5, 23 23)', srid=4326)
- self.assertEqual(True, isinstance(g2.ogr, gdal.OGRGeometry))
- self.assertEqual(True, isinstance(g2.srs, gdal.SpatialReference))
+ self.assertIsInstance(g2.ogr, gdal.OGRGeometry)
+ self.assertIsInstance(g2.srs, gdal.SpatialReference)
self.assertEqual(g2.hex, g2.ogr.hex)
self.assertEqual('WGS 84', g2.srs.name)
@@ -848,7 +854,7 @@ def test_copy(self):
self.assertNotEqual(poly._ptr, cpy1._ptr)
self.assertNotEqual(poly._ptr, cpy2._ptr)
- @unittest.skipUnless(gdal.HAS_GDAL, "gdal is required")
+ @unittest.skipUnless(gdal.HAS_GDAL, "gdal is required to transform geometries")
def test_transform(self):
"Testing `transform` method."
orig = GEOSGeometry('POINT (-104.609 38.255)', 4326)
@@ -873,6 +879,15 @@ def test_transform(self):
self.assertAlmostEqual(trans.x, p.x, prec)
self.assertAlmostEqual(trans.y, p.y, prec)
+ @unittest.skipUnless(gdal.HAS_GDAL, "gdal is required to transform geometries")
+ def test_transform_3d(self):
+ p3d = GEOSGeometry('POINT (5 23 100)', 4326)
+ p3d.transform(2774)
+ if GEOS_PREPARE:
+ self.assertEqual(p3d.z, 100)
+ else:
+ self.assertIsNone(p3d.z)
+
def test_transform_noop(self):
""" Testing `transform` method (SRID match) """
# transform() should no-op if source & dest SRIDs match,
View
5 django/contrib/gis/tests/geo3d/tests.py
@@ -4,7 +4,7 @@
import re
from django.contrib.gis.db.models import Union, Extent3D
-from django.contrib.gis.geos import GEOSGeometry, Point, Polygon
+from django.contrib.gis.geos import GEOSGeometry, LineString, Point, Polygon
from django.contrib.gis.utils import LayerMapping, LayerMapError
from django.test import TestCase
@@ -67,8 +67,7 @@ def _load_interstate_data(self):
# Interstate (2D / 3D and Geographic/Projected variants)
for name, line, exp_z in interstate_data:
line_3d = GEOSGeometry(line, srid=4269)
- # Using `hex` attribute because it omits 3D.
- line_2d = GEOSGeometry(line_3d.hex, srid=4269)
+ line_2d = LineString([l[:2] for l in line_3d.coords], srid=4269)
# Creating a geographic and projected version of the
# interstate in both 2D and 3D.
View
20 docs/ref/contrib/gis/geos.txt
@@ -273,14 +273,18 @@ Essentially the SRID is prepended to the WKT representation, for example
.. attribute:: GEOSGeometry.hex
Returns the WKB of this Geometry in hexadecimal form. Please note
-that the SRID and Z values are not included in this representation
+that the SRID value is not included in this representation
because it is not a part of the OGC specification (use the
:attr:`GEOSGeometry.hexewkb` property instead).
+.. versionchanged:: 1.5
+
+ Prior to Django 1.5, the Z value of the geometry was dropped.
+
.. attribute:: GEOSGeometry.hexewkb
Returns the EWKB of this Geometry in hexadecimal form. This is an
-extension of the WKB specification that includes SRID and Z values
+extension of the WKB specification that includes the SRID value
that are a part of this geometry.
.. note::
@@ -319,16 +323,20 @@ correspondg to the GEOS geometry.
.. attribute:: GEOSGeometry.wkb
Returns the WKB (Well-Known Binary) representation of this Geometry
-as a Python buffer. SRID and Z values are not included, use the
+as a Python buffer. SRID value is not included, use the
:attr:`GEOSGeometry.ewkb` property instead.
+.. versionchanged:: 1.5
+
+ Prior to Django 1.5, the Z value of the geometry was dropped.
+
.. _ewkb:
.. attribute:: GEOSGeometry.ewkb
Return the EWKB representation of this Geometry as a Python buffer.
This is an extension of the WKB specification that includes any SRID
-and Z values that are a part of this geometry.
+value that are a part of this geometry.
.. note::
@@ -822,7 +830,7 @@ Writer Objects
All writer objects have a ``write(geom)`` method that returns either the
WKB or WKT of the given geometry. In addition, :class:`WKBWriter` objects
also have properties that may be used to change the byte order, and or
-include the SRID and 3D values (in other words, EWKB).
+include the SRID value (in other words, EWKB).
.. class:: WKBWriter
@@ -884,7 +892,7 @@ so that the Z value is included in the WKB.
Outdim Value Description
============ ===========================
2 The default, output 2D WKB.
-3 Output 3D EWKB.
+3 Output 3D WKB.
============ ===========================
Example::
View
2  docs/releases/1.5.txt
@@ -117,6 +117,8 @@ GeoDjango
:meth:`~django.contrib.gis.geos.GEOSGeometry.project()` methods
(so-called linear referencing).
+* The wkb and hex properties of `GEOSGeometry` objects preserve the Z dimension.
+
* Support for GDAL < 1.5 has been dropped.
Minor features

0 comments on commit ffdd659

Please sign in to comment.
Something went wrong with that request. Please try again.