Refs #26789 -- Fixed output of WKBWriter for empty points and polygons.
This commit is contained in:
parent
181f492ad0
commit
b90d72facf
|
@ -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 ###
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue