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
|
22 | 22 | |
23 | 23 | # These functions provide access to a thread-local instance |
24 | 24 | # 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 |
| 25 | from django.contrib.gis.geos.prototypes.io import wkt_r, wkt_w, wkb_r, wkb_w, ewkb_w |
26 | 26 | |
27 | 27 | # For recognizing geometry input. |
28 | 28 | from django.contrib.gis.geometry.regex import hex_regex, wkt_regex, json_regex |
… |
… |
class GEOSGeometry(GEOSBase, ListMixin):
|
385 | 385 | def hex(self): |
386 | 386 | """ |
387 | 387 | 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). |
391 | 390 | """ |
392 | 391 | # A possible faster, all-python, implementation: |
393 | 392 | # 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) |
395 | 394 | |
396 | 395 | @property |
397 | 396 | def hexewkb(self): |
398 | 397 | """ |
399 | 398 | 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) |
410 | 406 | |
411 | 407 | @property |
412 | 408 | def json(self): |
… |
… |
class GEOSGeometry(GEOSBase, ListMixin):
|
426 | 422 | as a Python buffer. SRID and Z values are not included, use the |
427 | 423 | `ewkb` property instead. |
428 | 424 | """ |
429 | | return wkb_w().write(self) |
| 425 | return wkb_w(self.hasz and 3 or 2).write(self) |
430 | 426 | |
431 | 427 | @property |
432 | 428 | def ewkb(self): |
433 | 429 | """ |
434 | 430 | Return the EWKB representation of this Geometry as a Python buffer. |
435 | 431 | 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. |
437 | 433 | """ |
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) |
445 | 438 | |
446 | 439 | @property |
447 | 440 | def kml(self): |
… |
… |
class GEOSGeometry(GEOSBase, ListMixin):
|
513 | 506 | raise GEOSException("GDAL library is not available to transform() geometry.") |
514 | 507 | |
515 | 508 | # Creating an OGR Geometry, which is then transformed. |
516 | | g = gdal.OGRGeometry(self.wkb, srid) |
| 509 | g = self.ogr |
517 | 510 | g.transform(ct) |
518 | 511 | # Getting a new GEOS pointer |
519 | 512 | ptr = wkb_r().read(g.wkb) |
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):
|
204 | 204 | wkb_r = None |
205 | 205 | wkb_w = None |
206 | 206 | ewkb_w = None |
207 | | ewkb_w3d = None |
208 | 207 | |
209 | 208 | thread_context = ThreadLocalIO() |
210 | 209 | |
… |
… |
def wkb_r():
|
225 | 224 | thread_context.wkb_r = _WKBReader() |
226 | 225 | return thread_context.wkb_r |
227 | 226 | |
228 | | def wkb_w(): |
| 227 | def wkb_w(dim=2): |
229 | 228 | if not thread_context.wkb_w: |
230 | 229 | thread_context.wkb_w = WKBWriter() |
| 230 | thread_context.wkb_w.outdim = dim |
231 | 231 | return thread_context.wkb_w |
232 | 232 | |
233 | | def ewkb_w(): |
| 233 | def ewkb_w(dim=2): |
234 | 234 | if not thread_context.ewkb_w: |
235 | 235 | thread_context.ewkb_w = WKBWriter() |
236 | 236 | thread_context.ewkb_w.srid = True |
| 237 | thread_context.ewkb_w.outdim = dim |
237 | 238 | 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 |
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):
|
88 | 88 | |
89 | 89 | # For testing HEX(EWKB). |
90 | 90 | ogc_hex = '01010000000000000000000000000000000000F03F' |
| 91 | ogc_hex_3d = '01010000800000000000000000000000000000F03F0000000000000040' |
91 | 92 | # `SELECT ST_AsHEXEWKB(ST_GeomFromText('POINT(0 1)', 4326));` |
92 | 93 | hexewkb_2d = '0101000020E61000000000000000000000000000000000F03F' |
93 | 94 | # `SELECT ST_AsHEXEWKB(ST_GeomFromEWKT('SRID=4326;POINT(0 1 2)'));` |
… |
… |
class GEOSTest(unittest.TestCase, TestDataMixin):
|
96 | 97 | pnt_2d = Point(0, 1, srid=4326) |
97 | 98 | pnt_3d = Point(0, 1, 2, srid=4326) |
98 | 99 | |
99 | | # OGC-compliant HEX will not have SRID nor Z value. |
| 100 | # OGC-compliant HEX will not have SRID value. |
100 | 101 | self.assertEqual(ogc_hex, pnt_2d.hex) |
101 | | self.assertEqual(ogc_hex, pnt_3d.hex) |
| 102 | self.assertEqual(ogc_hex_3d, pnt_3d.hex) |
102 | 103 | |
103 | 104 | # HEXEWKB should be appropriate for its dimension -- have to use an |
104 | 105 | # a WKBWriter w/dimension set accordingly, else GEOS will insert |
… |
… |
class GEOSTest(unittest.TestCase, TestDataMixin):
|
829 | 830 | def test_gdal(self): |
830 | 831 | "Testing `ogr` and `srs` properties." |
831 | 832 | 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) |
834 | 840 | |
835 | 841 | 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) |
838 | 844 | self.assertEqual(g2.hex, g2.ogr.hex) |
839 | 845 | self.assertEqual('WGS 84', g2.srs.name) |
840 | 846 | |
… |
… |
class GEOSTest(unittest.TestCase, TestDataMixin):
|
847 | 853 | self.assertNotEqual(poly._ptr, cpy1._ptr) |
848 | 854 | self.assertNotEqual(poly._ptr, cpy2._ptr) |
849 | 855 | |
850 | | @unittest.skipUnless(gdal.HAS_GDAL, "gdal is required") |
| 856 | @unittest.skipUnless(gdal.HAS_GDAL, "gdal is required to transform geometries") |
851 | 857 | def test_transform(self): |
852 | 858 | "Testing `transform` method." |
853 | 859 | orig = GEOSGeometry('POINT (-104.609 38.255)', 4326) |
… |
… |
class GEOSTest(unittest.TestCase, TestDataMixin):
|
872 | 878 | self.assertAlmostEqual(trans.x, p.x, prec) |
873 | 879 | self.assertAlmostEqual(trans.y, p.y, prec) |
874 | 880 | |
| 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 | |
875 | 890 | def test_transform_noop(self): |
876 | 891 | """ Testing `transform` method (SRID match) """ |
877 | 892 | # transform() should no-op if source & dest SRIDs match, |
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
|
4 | 4 | import re |
5 | 5 | |
6 | 6 | from django.contrib.gis.db.models import Union, Extent3D |
7 | | from django.contrib.gis.geos import GEOSGeometry, Point, Polygon |
| 7 | from django.contrib.gis.geos import GEOSGeometry, LineString, Point, Polygon |
8 | 8 | from django.contrib.gis.utils import LayerMapping, LayerMapError |
9 | 9 | from django.test import TestCase |
10 | 10 | |
… |
… |
class Geo3DTest(TestCase):
|
67 | 67 | # Interstate (2D / 3D and Geographic/Projected variants) |
68 | 68 | for name, line, exp_z in interstate_data: |
69 | 69 | 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) |
72 | 71 | |
73 | 72 | # Creating a geographic and projected version of the |
74 | 73 | # interstate in both 2D and 3D. |
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
|
273 | 273 | .. attribute:: GEOSGeometry.hex |
274 | 274 | |
275 | 275 | Returns the WKB of this Geometry in hexadecimal form. Please note |
276 | | that the SRID and Z values are not included in this representation |
| 276 | that the SRID value is not included in this representation |
277 | 277 | because it is not a part of the OGC specification (use the |
278 | 278 | :attr:`GEOSGeometry.hexewkb` property instead). |
279 | 279 | |
| 280 | .. versionchanged:: 1.5 |
| 281 | |
| 282 | Prior to Django 1.5, the Z value of the geometry was dropped. |
| 283 | |
280 | 284 | .. attribute:: GEOSGeometry.hexewkb |
281 | 285 | |
282 | 286 | Returns the EWKB of this Geometry in hexadecimal form. This is an |
283 | | extension of the WKB specification that includes SRID and Z values |
| 287 | extension of the WKB specification that includes the SRID value |
284 | 288 | that are a part of this geometry. |
285 | 289 | |
286 | 290 | .. note:: |
… |
… |
correspondg to the GEOS geometry.
|
319 | 323 | .. attribute:: GEOSGeometry.wkb |
320 | 324 | |
321 | 325 | Returns the WKB (Well-Known Binary) representation of this Geometry |
322 | | as a Python buffer. SRID and Z values are not included, use the |
| 326 | as a Python buffer. SRID value is not included, use the |
323 | 327 | :attr:`GEOSGeometry.ewkb` property instead. |
324 | 328 | |
| 329 | .. versionchanged:: 1.5 |
| 330 | |
| 331 | Prior to Django 1.5, the Z value of the geometry was dropped. |
| 332 | |
325 | 333 | .. _ewkb: |
326 | 334 | |
327 | 335 | .. attribute:: GEOSGeometry.ewkb |
328 | 336 | |
329 | 337 | Return the EWKB representation of this Geometry as a Python buffer. |
330 | 338 | This is an extension of the WKB specification that includes any SRID |
331 | | and Z values that are a part of this geometry. |
| 339 | value that are a part of this geometry. |
332 | 340 | |
333 | 341 | .. note:: |
334 | 342 | |
… |
… |
Writer Objects
|
797 | 805 | All writer objects have a ``write(geom)`` method that returns either the |
798 | 806 | WKB or WKT of the given geometry. In addition, :class:`WKBWriter` objects |
799 | 807 | also have properties that may be used to change the byte order, and or |
800 | | include the SRID and 3D values (in other words, EWKB). |
| 808 | include the SRID value (in other words, EWKB). |
801 | 809 | |
802 | 810 | .. class:: WKBWriter |
803 | 811 | |
… |
… |
so that the Z value is included in the WKB.
|
859 | 867 | Outdim Value Description |
860 | 868 | ============ =========================== |
861 | 869 | 2 The default, output 2D WKB. |
862 | | 3 Output 3D EWKB. |
| 870 | 3 Output 3D WKB. |
863 | 871 | ============ =========================== |
864 | 872 | |
865 | 873 | Example:: |