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__()
|
super(WKBWriter, self).__init__()
|
||||||
self.outdim = dim
|
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):
|
def write(self, geom):
|
||||||
"Returns the WKB representation of the given geometry."
|
"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):
|
def write_hex(self, geom):
|
||||||
"Returns the HEXEWKB representation of the given geometry."
|
"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 ###
|
# ### WKBWriter Properties ###
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@ import binascii
|
||||||
from unittest import skipUnless
|
from unittest import skipUnless
|
||||||
|
|
||||||
from django.contrib.gis.geos import (
|
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.test import SimpleTestCase
|
||||||
from django.utils.six import memoryview
|
from django.utils.six import memoryview
|
||||||
|
@ -155,3 +156,41 @@ class GEOSIOTest(SimpleTestCase):
|
||||||
|
|
||||||
with self.assertRaisesMessage(AttributeError, 'WKT output rounding precision must be '):
|
with self.assertRaisesMessage(AttributeError, 'WKT output rounding precision must be '):
|
||||||
wkt_w.precision = 'potato'
|
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