summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Fedoseev <fedoseev.sergey@gmail.com>2016-12-01 14:26:12 +0500
committerTim Graham <timograham@gmail.com>2016-12-06 13:58:22 -0500
commitb90d72facf1e4294df1c2e6b51b26f6879bf2992 (patch)
tree4af5c45bb0147c4c1bb6d823661bde36a0b021a3
parent181f492ad021aeb43105aa9d38106ad7baf00211 (diff)
Refs #26789 -- Fixed output of WKBWriter for empty points and polygons.
-rw-r--r--django/contrib/gis/geos/prototypes/io.py28
-rw-r--r--tests/gis_tests/geos_tests/test_io.py41
2 files changed, 66 insertions, 3 deletions
diff --git a/django/contrib/gis/geos/prototypes/io.py b/django/contrib/gis/geos/prototypes/io.py
index 8ac4cfa21e..e563aa105e 100644
--- a/django/contrib/gis/geos/prototypes/io.py
+++ b/django/contrib/gis/geos/prototypes/io.py
@@ -226,13 +226,37 @@ class WKBWriter(IOBase):
super(WKBWriter, self).__init__()
self.outdim = dim
+ def _handle_empty_point(self, geom):
+ from django.contrib.gis.geos import Point
+ if isinstance(geom, Point) and geom.empty:
+ if self.srid:
+ # PostGIS uses POINT(NaN NaN) for WKB representation of empty
+ # points. Use it for EWKB as it's a PostGIS specific format.
+ # https://trac.osgeo.org/postgis/ticket/3181
+ geom = Point(float('NaN'), float('NaN'), srid=geom.srid)
+ else:
+ raise ValueError('Empty point is not representable in WKB.')
+ return geom
+
def write(self, geom):
"Returns the WKB representation of the given geometry."
- return six.memoryview(wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t())))
+ from django.contrib.gis.geos import Polygon
+ geom = self._handle_empty_point(geom)
+ wkb = wkb_writer_write(self.ptr, geom.ptr, byref(c_size_t()))
+ if isinstance(geom, Polygon) and geom.empty:
+ # Fix GEOS output for empty polygon.
+ # See https://trac.osgeo.org/geos/ticket/680.
+ wkb = wkb[:-8] + b'\0' * 4
+ return six.memoryview(wkb)
def write_hex(self, geom):
"Returns the HEXEWKB representation of the given geometry."
- return wkb_writer_write_hex(self.ptr, geom.ptr, byref(c_size_t()))
+ from django.contrib.gis.geos.polygon import Polygon
+ geom = self._handle_empty_point(geom)
+ wkb = wkb_writer_write_hex(self.ptr, geom.ptr, byref(c_size_t()))
+ if isinstance(geom, Polygon) and geom.empty:
+ wkb = wkb[:-16] + b'0' * 8
+ return wkb
# ### WKBWriter Properties ###
diff --git a/tests/gis_tests/geos_tests/test_io.py b/tests/gis_tests/geos_tests/test_io.py
index 00fe3b67fd..601301331e 100644
--- a/tests/gis_tests/geos_tests/test_io.py
+++ b/tests/gis_tests/geos_tests/test_io.py
@@ -4,7 +4,8 @@ import binascii
from unittest import skipUnless
from django.contrib.gis.geos import (
- HAS_GEOS, GEOSGeometry, Point, WKBReader, WKBWriter, WKTReader, WKTWriter,
+ HAS_GEOS, GEOSGeometry, Point, Polygon, WKBReader, WKBWriter, WKTReader,
+ WKTWriter,
)
from django.test import SimpleTestCase
from django.utils.six import memoryview
@@ -155,3 +156,41 @@ class GEOSIOTest(SimpleTestCase):
with self.assertRaisesMessage(AttributeError, 'WKT output rounding precision must be '):
wkt_w.precision = 'potato'
+
+ def test_empty_point_wkb(self):
+ p = Point(srid=4326)
+ wkb_w = WKBWriter()
+
+ wkb_w.srid = False
+ with self.assertRaisesMessage(ValueError, 'Empty point is not representable in WKB.'):
+ wkb_w.write(p)
+ with self.assertRaisesMessage(ValueError, 'Empty point is not representable in WKB.'):
+ wkb_w.write_hex(p)
+
+ wkb_w.srid = True
+ for byteorder, hex in enumerate([
+ b'0020000001000010E67FF80000000000007FF8000000000000',
+ b'0101000020E6100000000000000000F87F000000000000F87F',
+ ]):
+ wkb_w.byteorder = byteorder
+ self.assertEqual(wkb_w.write_hex(p), hex)
+ self.assertEqual(GEOSGeometry(wkb_w.write_hex(p)), p)
+ self.assertEqual(wkb_w.write(p), memoryview(binascii.a2b_hex(hex)))
+ self.assertEqual(GEOSGeometry(wkb_w.write(p)), p)
+
+ def test_empty_polygon_wkb(self):
+ p = Polygon(srid=4326)
+ p_no_srid = Polygon()
+ wkb_w = WKBWriter()
+ wkb_w.srid = True
+ for byteorder, hexes in enumerate([
+ (b'000000000300000000', b'0020000003000010E600000000'),
+ (b'010300000000000000', b'0103000020E610000000000000'),
+ ]):
+ wkb_w.byteorder = byteorder
+ for srid, hex in enumerate(hexes):
+ wkb_w.srid = srid
+ self.assertEqual(wkb_w.write_hex(p), hex)
+ self.assertEqual(GEOSGeometry(wkb_w.write_hex(p)), p if srid else p_no_srid)
+ self.assertEqual(wkb_w.write(p), memoryview(binascii.a2b_hex(hex)))
+ self.assertEqual(GEOSGeometry(wkb_w.write(p)), p if srid else p_no_srid)