Ticket #18919: 18919-3.diff

File 18919-3.diff, 11.7 KB (added by Claude Paroz, 12 years ago)

Include Z value in wkb of geometries

  • django/contrib/gis/geos/geometry.py

    diff --git a/django/contrib/gis/geos/geometry.py b/django/contrib/gis/geos/geometry.py
    index 4e5409d..fae6a56 100644
    a b from django.contrib.gis.geos import prototypes as capi  
    2222
    2323# These functions provide access to a thread-local instance
    2424# of their corresponding GEOS I/O class.
    25 from django.contrib.gis.geos.prototypes.io import wkt_r, wkt_w, wkb_r, wkb_w, ewkb_w, ewkb_w3d
     25from django.contrib.gis.geos.prototypes.io import wkt_r, wkt_w, wkb_r, wkb_w, ewkb_w
    2626
    2727# For recognizing geometry input.
    2828from django.contrib.gis.geometry.regex import hex_regex, wkt_regex, json_regex
    class GEOSGeometry(GEOSBase, ListMixin):  
    385385    def hex(self):
    386386        """
    387387        Returns the WKB of this Geometry in hexadecimal form.  Please note
    388         that the SRID and Z values are not included in this representation
    389         because it is not a part of the OGC specification (use the `hexewkb`
    390         property instead).
     388        that the SRID is not included in this representation because it is not
     389        a part of the OGC specification (use the `hexewkb` property instead).
    391390        """
    392391        # A possible faster, all-python, implementation:
    393392        #  str(self.wkb).encode('hex')
    394         return wkb_w().write_hex(self)
     393        return wkb_w(self.hasz and 3 or 2).write_hex(self)
    395394
    396395    @property
    397396    def hexewkb(self):
    398397        """
    399398        Returns the EWKB of this Geometry in hexadecimal form.  This is an
    400         extension of the WKB specification that includes SRID and Z values
    401         that are a part of this geometry.
    402         """
    403         if self.hasz:
    404             if not GEOS_PREPARE:
    405                 # See: http://trac.osgeo.org/geos/ticket/216
    406                 raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D HEXEWKB.')
    407             return ewkb_w3d().write_hex(self)
    408         else:
    409             return ewkb_w().write_hex(self)
     399        extension of the WKB specification that includes SRID value that are
     400        a part of this geometry.
     401        """
     402        if self.hasz and not GEOS_PREPARE:
     403            # See: http://trac.osgeo.org/geos/ticket/216
     404            raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D HEXEWKB.')
     405        return ewkb_w(self.hasz and 3 or 2).write_hex(self)
    410406
    411407    @property
    412408    def json(self):
    class GEOSGeometry(GEOSBase, ListMixin):  
    426422        as a Python buffer.  SRID and Z values are not included, use the
    427423        `ewkb` property instead.
    428424        """
    429         return wkb_w().write(self)
     425        return wkb_w(self.hasz and 3 or 2).write(self)
    430426
    431427    @property
    432428    def ewkb(self):
    433429        """
    434430        Return the EWKB representation of this Geometry as a Python buffer.
    435431        This is an extension of the WKB specification that includes any SRID
    436         and Z values that are a part of this geometry.
     432        value that are a part of this geometry.
    437433        """
    438         if self.hasz:
    439             if not GEOS_PREPARE:
    440                 # See: http://trac.osgeo.org/geos/ticket/216
    441                 raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D EWKB.')
    442             return ewkb_w3d().write(self)
    443         else:
    444             return ewkb_w().write(self)
     434        if self.hasz and not GEOS_PREPARE:
     435            # See: http://trac.osgeo.org/geos/ticket/216
     436            raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D EWKB.')
     437        return ewkb_w(self.hasz and 3 or 2).write(self)
    445438
    446439    @property
    447440    def kml(self):
    class GEOSGeometry(GEOSBase, ListMixin):  
    513506            raise GEOSException("GDAL library is not available to transform() geometry.")
    514507
    515508        # Creating an OGR Geometry, which is then transformed.
    516         g = gdal.OGRGeometry(self.wkb, srid)
     509        g = self.ogr
    517510        g.transform(ct)
    518511        # Getting a new GEOS pointer
    519512        ptr = wkb_r().read(g.wkb)
  • django/contrib/gis/geos/prototypes/io.py

    diff --git a/django/contrib/gis/geos/prototypes/io.py b/django/contrib/gis/geos/prototypes/io.py
    index 053b994..91afb2a 100644
    a b class ThreadLocalIO(threading.local):  
    204204    wkb_r = None
    205205    wkb_w = None
    206206    ewkb_w = None
    207     ewkb_w3d = None
    208207
    209208thread_context = ThreadLocalIO()
    210209
    def wkb_r():  
    225224        thread_context.wkb_r = _WKBReader()
    226225    return thread_context.wkb_r
    227226
    228 def wkb_w():
     227def wkb_w(dim=2):
    229228   if not thread_context.wkb_w:
    230229       thread_context.wkb_w = WKBWriter()
     230   thread_context.wkb_w.outdim = dim
    231231   return thread_context.wkb_w
    232232
    233 def ewkb_w():
     233def ewkb_w(dim=2):
    234234    if not thread_context.ewkb_w:
    235235        thread_context.ewkb_w = WKBWriter()
    236236        thread_context.ewkb_w.srid = True
     237    thread_context.ewkb_w.outdim = dim
    237238    return thread_context.ewkb_w
    238 
    239 def ewkb_w3d():
    240     if not thread_context.ewkb_w3d:
    241         thread_context.ewkb_w3d = WKBWriter()
    242         thread_context.ewkb_w3d.srid = True
    243         thread_context.ewkb_w3d.outdim = 3
    244     return thread_context.ewkb_w3d
  • django/contrib/gis/geos/tests/test_geos.py

    diff --git a/django/contrib/gis/geos/tests/test_geos.py b/django/contrib/gis/geos/tests/test_geos.py
    index 7300ab9..03a407b 100644
    a b class GEOSTest(unittest.TestCase, TestDataMixin):  
    8888
    8989        # For testing HEX(EWKB).
    9090        ogc_hex = '01010000000000000000000000000000000000F03F'
     91        ogc_hex_3d = '01010000800000000000000000000000000000F03F0000000000000040'
    9192        # `SELECT ST_AsHEXEWKB(ST_GeomFromText('POINT(0 1)', 4326));`
    9293        hexewkb_2d = '0101000020E61000000000000000000000000000000000F03F'
    9394        # `SELECT ST_AsHEXEWKB(ST_GeomFromEWKT('SRID=4326;POINT(0 1 2)'));`
    class GEOSTest(unittest.TestCase, TestDataMixin):  
    9697        pnt_2d = Point(0, 1, srid=4326)
    9798        pnt_3d = Point(0, 1, 2, srid=4326)
    9899
    99         # OGC-compliant HEX will not have SRID nor Z value.
     100        # OGC-compliant HEX will not have SRID value.
    100101        self.assertEqual(ogc_hex, pnt_2d.hex)
    101         self.assertEqual(ogc_hex, pnt_3d.hex)
     102        self.assertEqual(ogc_hex_3d, pnt_3d.hex)
    102103
    103104        # HEXEWKB should be appropriate for its dimension -- have to use an
    104105        # a WKBWriter w/dimension set accordingly, else GEOS will insert
    class GEOSTest(unittest.TestCase, TestDataMixin):  
    829830    def test_gdal(self):
    830831        "Testing `ogr` and `srs` properties."
    831832        g1 = fromstr('POINT(5 23)')
    832         self.assertEqual(True, isinstance(g1.ogr, gdal.OGRGeometry))
    833         self.assertEqual(g1.srs, None)
     833        self.assertIsInstance(g1.ogr, gdal.OGRGeometry)
     834        self.assertIsNone(g1.srs)
     835
     836        if GEOS_PREPARE:
     837            g1_3d = fromstr('POINT(5 23 8)')
     838            self.assertIsInstance(g1_3d.ogr, gdal.OGRGeometry)
     839            self.assertEqual(g1_3d.ogr.z, 8)
    834840
    835841        g2 = fromstr('LINESTRING(0 0, 5 5, 23 23)', srid=4326)
    836         self.assertEqual(True, isinstance(g2.ogr, gdal.OGRGeometry))
    837         self.assertEqual(True, isinstance(g2.srs, gdal.SpatialReference))
     842        self.assertIsInstance(g2.ogr, gdal.OGRGeometry)
     843        self.assertIsInstance(g2.srs, gdal.SpatialReference)
    838844        self.assertEqual(g2.hex, g2.ogr.hex)
    839845        self.assertEqual('WGS 84', g2.srs.name)
    840846
    class GEOSTest(unittest.TestCase, TestDataMixin):  
    847853        self.assertNotEqual(poly._ptr, cpy1._ptr)
    848854        self.assertNotEqual(poly._ptr, cpy2._ptr)
    849855
    850     @unittest.skipUnless(gdal.HAS_GDAL, "gdal is required")
     856    @unittest.skipUnless(gdal.HAS_GDAL, "gdal is required to transform geometries")
    851857    def test_transform(self):
    852858        "Testing `transform` method."
    853859        orig = GEOSGeometry('POINT (-104.609 38.255)', 4326)
    class GEOSTest(unittest.TestCase, TestDataMixin):  
    872878            self.assertAlmostEqual(trans.x, p.x, prec)
    873879            self.assertAlmostEqual(trans.y, p.y, prec)
    874880
     881    @unittest.skipUnless(gdal.HAS_GDAL, "gdal is required to transform geometries")
     882    def test_transform_3d(self):
     883        p3d = GEOSGeometry('POINT (5 23 100)', 4326)
     884        p3d.transform(2774)
     885        if GEOS_PREPARE:
     886            self.assertEqual(p3d.z, 100)
     887        else:
     888            self.assertIsNone(p3d.z)
     889
    875890    def test_transform_noop(self):
    876891        """ Testing `transform` method (SRID match) """
    877892        # transform() should no-op if source & dest SRIDs match,
  • django/contrib/gis/tests/geo3d/tests.py

    diff --git a/django/contrib/gis/tests/geo3d/tests.py b/django/contrib/gis/tests/geo3d/tests.py
    index 0aba38f..f7590fe 100644
    a b import os  
    44import re
    55
    66from django.contrib.gis.db.models import Union, Extent3D
    7 from django.contrib.gis.geos import GEOSGeometry, Point, Polygon
     7from django.contrib.gis.geos import GEOSGeometry, LineString, Point, Polygon
    88from django.contrib.gis.utils import LayerMapping, LayerMapError
    99from django.test import TestCase
    1010
    class Geo3DTest(TestCase):  
    6767        # Interstate (2D / 3D and Geographic/Projected variants)
    6868        for name, line, exp_z in interstate_data:
    6969            line_3d = GEOSGeometry(line, srid=4269)
    70             # Using `hex` attribute because it omits 3D.
    71             line_2d = GEOSGeometry(line_3d.hex, srid=4269)
     70            line_2d = LineString([l[:2] for l in line_3d.coords], srid=4269)
    7271
    7372            # Creating a geographic and projected version of the
    7473            # interstate in both 2D and 3D.
  • docs/ref/contrib/gis/geos.txt

    diff --git a/docs/ref/contrib/gis/geos.txt b/docs/ref/contrib/gis/geos.txt
    index b569a74..726e6a7 100644
    a b Essentially the SRID is prepended to the WKT representation, for example  
    273273.. attribute:: GEOSGeometry.hex
    274274
    275275Returns the WKB of this Geometry in hexadecimal form.  Please note
    276 that the SRID and Z values are not included in this representation
     276that the SRID value is not included in this representation
    277277because it is not a part of the OGC specification (use the
    278278:attr:`GEOSGeometry.hexewkb` property instead).
    279279
     280.. versionchanged:: 1.5
     281
     282    Prior to Django 1.5, the Z value of the geometry was dropped.
     283
    280284.. attribute:: GEOSGeometry.hexewkb
    281285
    282286Returns the EWKB of this Geometry in hexadecimal form.  This is an
    283 extension of the WKB specification that includes SRID and Z values
     287extension of the WKB specification that includes the SRID value
    284288that are a part of this geometry.
    285289
    286290.. note::
    correspondg to the GEOS geometry.  
    319323.. attribute:: GEOSGeometry.wkb
    320324
    321325Returns the WKB (Well-Known Binary) representation of this Geometry
    322 as a Python buffer.  SRID and Z values are not included, use the
     326as a Python buffer.  SRID value is not included, use the
    323327:attr:`GEOSGeometry.ewkb` property instead.
    324328
     329.. versionchanged:: 1.5
     330
     331    Prior to Django 1.5, the Z value of the geometry was dropped.
     332
    325333.. _ewkb:
    326334
    327335.. attribute:: GEOSGeometry.ewkb
    328336
    329337Return the EWKB representation of this Geometry as a Python buffer.
    330338This is an extension of the WKB specification that includes any SRID
    331 and Z values that are a part of this geometry.
     339value that are a part of this geometry.
    332340
    333341.. note::
    334342
    Writer Objects  
    797805All writer objects have a ``write(geom)`` method that returns either the
    798806WKB or WKT of the given geometry.  In addition, :class:`WKBWriter` objects
    799807also have properties that may be used to change the byte order, and or
    800 include the SRID and 3D values (in other words, EWKB).
     808include the SRID value (in other words, EWKB).
    801809
    802810.. class:: WKBWriter
    803811
    so that the Z value is included in the WKB.  
    859867Outdim Value Description
    860868============ ===========================
    8618692            The default, output 2D WKB.
    862 3            Output 3D EWKB.
     8703            Output 3D WKB.
    863871============ ===========================
    864872
    865873Example::
Back to Top