Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

gis: gdal: added support exporting/creating geometries to/from WKB an…

…d HEX.

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@6464 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit ddc9361d93235602b97bd2fbf4dfbb31684161fd 1 parent ad3e9e9
Justin Bronn authored October 07, 2007
4  django/contrib/gis/gdal/feature.py
... ...
@@ -1,6 +1,6 @@
1 1
 # types and ctypes
2 2
 from types import StringType
3  
-from ctypes import c_char_p, c_int, string_at
  3
+from ctypes import c_char_p, c_int, c_void_p, string_at
4 4
 
5 5
 # The GDAL C library, OGR exception, and the Field object
6 6
 from django.contrib.gis.gdal.libgdal import lgdal
@@ -98,7 +98,7 @@ def geom(self):
98 98
             srs = None
99 99
 
100 100
         # Geometry is cloned so the feature isn't invalidated.
101  
-        return OGRGeometry(lgdal.OGR_G_Clone(geom_ptr), srs)
  101
+        return OGRGeometry(c_void_p(lgdal.OGR_G_Clone(geom_ptr)), srs)
102 102
 
103 103
     @property
104 104
     def geom_type(self):
117  django/contrib/gis/gdal/geometries.py
@@ -38,9 +38,11 @@
38 38
     >>> print gt1 == 3, gt1 == 'Polygon' # Equivalence works w/non-OGRGeomType objects
39 39
     True
40 40
 """
41  
-# types & ctypes
42  
-from types import IntType, StringType, UnicodeType
43  
-from ctypes import byref, string_at, c_char_p, c_double, c_int, c_void_p
  41
+# Python library imports
  42
+import re, sys
  43
+from binascii import a2b_hex, b2a_hex
  44
+from ctypes import byref, create_string_buffer, string_at, c_char_p, c_double, c_int, c_void_p
  45
+from types import BufferType, IntType, StringType, UnicodeType
44 46
 
45 47
 # Getting GDAL prerequisites
46 48
 from django.contrib.gis.gdal.libgdal import lgdal
@@ -70,6 +72,9 @@ def pnt_func(f):
70 72
 get_area.restype = c_double
71 73
 get_area.argtypes = [c_void_p]
72 74
 
  75
+# Regular expression for determining whether the input is HEXEWKB.
  76
+hex_regex = re.compile(r'^[0-9A-F]+$', re.I)
  77
+
73 78
 #### OGRGeometry Class ####
74 79
 class OGRGeometry(object):
75 80
     "Generally encapsulates an OGR geometry."
@@ -77,7 +82,16 @@ class OGRGeometry(object):
77 82
     def __init__(self, geom_input, srs=None):
78 83
         "Initializes Geometry on either WKT or an OGR pointer as input."
79 84
 
80  
-        self._g = 0 # Initially NULL
  85
+        self._g = c_void_p(None) # Initially NULL
  86
+
  87
+        # Checking if unicode
  88
+        if isinstance(geom_input, UnicodeType):
  89
+            # Encoding to ASCII, WKT or HEX doesn't need any more.
  90
+            geo_input = geo_input.encode('ascii')
  91
+
  92
+        # If HEX, unpack input to to a binary buffer.
  93
+        if isinstance(geom_input, StringType) and hex_regex.match(geom_input):
  94
+            geom_input = buffer(a2b_hex(geom_input.upper()))
81 95
 
82 96
         if isinstance(geom_input, StringType):
83 97
             # First, trying the input as WKT
@@ -93,10 +107,15 @@ def __init__(self, geom_input, srs=None):
93 107
                     g = lgdal.OGR_G_CreateGeometry(ogr_t.num)
94 108
                 except:
95 109
                     raise OGRException('Could not initialize OGR Geometry from: %s' % geom_input)
  110
+        elif isinstance(geom_input, BufferType):
  111
+            # WKB was passed in
  112
+            g = c_void_p()
  113
+            check_err(lgdal.OGR_G_CreateFromWkb(c_char_p(str(geom_input)), c_void_p(), byref(g), len(geom_input)))
96 114
         elif isinstance(geom_input, OGRGeomType):
  115
+            # OGRGeomType was passed in, an empty geometry will be created.
97 116
             g = lgdal.OGR_G_CreateGeometry(geom_input.num)
98  
-        elif isinstance(geom_input, IntType):
99  
-            # OGR Pointer (integer) was the input
  117
+        elif isinstance(geom_input, c_void_p):
  118
+            # OGR pointer (c_void_p) was the input.
100 119
             g = geom_input
101 120
         else:
102 121
             raise OGRException('Type of input cannot be determined!')
@@ -181,6 +200,30 @@ def num_coords(self):
181 200
         "Returns the number of Points in this Geometry."
182 201
         return self.point_count
183 202
 
  203
+    @property
  204
+    def geom_type(self):
  205
+        "Returns the Type for this Geometry."
  206
+        return OGRGeomType(lgdal.OGR_G_GetGeometryType(self._g))
  207
+
  208
+    @property
  209
+    def geom_name(self):
  210
+        "Returns the Name of this Geometry."
  211
+        return string_at(lgdal.OGR_G_GetGeometryName(self._g))
  212
+
  213
+    @property
  214
+    def area(self):
  215
+        "Returns the area for a LinearRing, Polygon, or MultiPolygon; 0 otherwise."
  216
+        return get_area(self._g)
  217
+
  218
+    @property
  219
+    def envelope(self):
  220
+        "Returns the envelope for this Geometry."
  221
+        env = OGREnvelope()
  222
+        lgdal.OGR_G_GetEnvelope(self._g, byref(env))
  223
+        return Envelope(env)
  224
+
  225
+    #### SpatialReference-related Properties ####
  226
+    
184 227
     # The SRS property
185 228
     def get_srs(self):
186 229
         "Returns the Spatial Reference for this Geometry."
@@ -216,28 +259,6 @@ def set_srid(self, srid):
216 259
 
217 260
     srid = property(get_srid, set_srid)
218 261
 
219  
-    @property
220  
-    def geom_type(self):
221  
-        "Returns the Type for this Geometry."
222  
-        return OGRGeomType(lgdal.OGR_G_GetGeometryType(self._g))
223  
-
224  
-    @property
225  
-    def geom_name(self):
226  
-        "Returns the Name of this Geometry."
227  
-        return string_at(lgdal.OGR_G_GetGeometryName(self._g))
228  
-
229  
-    @property
230  
-    def area(self):
231  
-        "Returns the area for a LinearRing, Polygon, or MultiPolygon; 0 otherwise."
232  
-        return get_area(self._g)
233  
-
234  
-    @property
235  
-    def envelope(self):
236  
-        "Returns the envelope for this Geometry."
237  
-        env = OGREnvelope()
238  
-        lgdal.OGR_G_GetEnvelope(self._g, byref(env))
239  
-        return Envelope(env)
240  
-
241 262
     #### Output Methods ####
242 263
     @property
243 264
     def gml(self):
@@ -247,6 +268,30 @@ def gml(self):
247 268
         else: return None
248 269
 
249 270
     @property
  271
+    def hex(self):
  272
+        "Returns the hexadecimal representation of the WKB (a string)."
  273
+        return b2a_hex(self.wkb).upper()
  274
+
  275
+    @property
  276
+    def wkb_size(self):
  277
+        "Returns the size of the WKB buffer."
  278
+        return lgdal.OGR_G_WkbSize(self._g)
  279
+
  280
+    @property
  281
+    def wkb(self):
  282
+        "Returns the WKB representation of the Geometry."
  283
+        if sys.byteorder == 'little':
  284
+            byteorder = c_int(1) # wkbNDR (from ogr_core.h)
  285
+        else:
  286
+            byteorder = c_int(0) # wkbXDR (from ogr_core.h)
  287
+        # Creating a mutable string buffer of the given size, exporting
  288
+        # to WKB, and returning a Python buffer of the WKB.
  289
+        sz = self.wkb_size
  290
+        wkb = create_string_buffer(sz)
  291
+        check_err(lgdal.OGR_G_ExportToWkb(self._g, byteorder, byref(wkb)))
  292
+        return buffer(string_at(wkb, sz))
  293
+
  294
+    @property
250 295
     def wkt(self):
251 296
         "Returns the WKT representation of the Geometry."
252 297
         buf = c_char_p()
@@ -256,7 +301,7 @@ def wkt(self):
256 301
     #### Geometry Methods ####
257 302
     def clone(self):
258 303
         "Clones this OGR Geometry."
259  
-        return OGRGeometry(lgdal.OGR_G_Clone(self._g))
  304
+        return OGRGeometry(c_void_p(lgdal.OGR_G_Clone(self._g)))
260 305
 
261 306
     def close_rings(self):
262 307
         """If there are any rings within this geometry that have not been
@@ -327,9 +372,9 @@ def overlaps(self, other):
327 372
     def _geomgen(self, gen_func, other=None):
328 373
         "A helper routine for the OGR routines that generate geometries."
329 374
         if isinstance(other, OGRGeometry):
330  
-            return OGRGeometry(gen_func(self._g, other._g))
  375
+            return OGRGeometry(c_void_p(gen_func(self._g, other._g)))
331 376
         else:
332  
-            return OGRGeometry(gen_func(self._g))
  377
+            return OGRGeometry(c_void_p(gen_func(self._g)))
333 378
 
334 379
     @property
335 380
     def boundary(self):
@@ -382,9 +427,7 @@ def z(self):
382 427
     @property
383 428
     def tuple(self):
384 429
         "Returns the tuple of this point."
385  
-        if self.coord_dim == 1:
386  
-            return (self.x,)
387  
-        elif self.coord_dim == 2:
  430
+        if self.coord_dim == 2:
388 431
             return (self.x, self.y)
389 432
         elif self.coord_dim == 3:
390 433
             return (self.x, self.y, self.z)
@@ -441,7 +484,7 @@ def __getitem__(self, index):
441 484
         if index < 0 or index >= self.geom_count:
442 485
             raise OGRIndexError('index out of range: %s' % str(index))
443 486
         else:
444  
-            return OGRGeometry(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index))), self.srs)
  487
+            return OGRGeometry(c_void_p(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index)))), self.srs)
445 488
 
446 489
     # Polygon Properties
447 490
     @property
@@ -477,7 +520,7 @@ def __getitem__(self, index):
477 520
         if index < 0 or index >= self.geom_count:
478 521
             raise OGRIndexError('index out of range: %s' % str(index))
479 522
         else:
480  
-            return OGRGeometry(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index))), self.srs)
  523
+            return OGRGeometry(c_void_p(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index)))), self.srs)
481 524
         
482 525
     def __iter__(self):
483 526
         "Iterates over each Geometry."
@@ -492,7 +535,7 @@ def add(self, geom):
492 535
         "Add the geometry to this Geometry Collection."
493 536
         if isinstance(geom, OGRGeometry):
494 537
             ptr = geom._g
495  
-        elif isinstance(geom, StringType):
  538
+        elif isinstance(geom, (StringType, UnicodeType)):
496 539
             tmp = OGRGeometry(geom)
497 540
             ptr = tmp._g
498 541
         else:
22  django/contrib/gis/tests/test_gdal_geom.py
... ...
@@ -1,6 +1,6 @@
1 1
 import unittest
2 2
 from django.contrib.gis.gdal import OGRGeometry, OGRGeomType, OGRException, SpatialReference
3  
-from geometries import *
  3
+from django.contrib.gis.tests.geometries import *
4 4
 
5 5
 class OGRGeomTest(unittest.TestCase):
6 6
     "This tests the OGR Geometry."
@@ -42,6 +42,26 @@ def test01b_gml(self):
42 42
             geom = OGRGeometry(g.wkt)
43 43
             self.assertEqual(g.gml, geom.gml)
44 44
 
  45
+    def test01c_hex(self):
  46
+        "Testing HEX input/output."
  47
+        for g in hex_wkt:
  48
+            geom1 = OGRGeometry(g.wkt)
  49
+            self.assertEqual(g.hex, geom1.hex)
  50
+            # Constructing w/HEX
  51
+            geom2 = OGRGeometry(g.hex)
  52
+            self.assertEqual(geom1, geom2)
  53
+
  54
+    def test01d_wkb(self):
  55
+        "Testing WKB input/output."
  56
+        from binascii import b2a_hex
  57
+        for g in hex_wkt:
  58
+            geom1 = OGRGeometry(g.wkt)
  59
+            wkb = geom1.wkb
  60
+            self.assertEqual(b2a_hex(wkb).upper(), g.hex)
  61
+            # Constructing w/WKB.
  62
+            geom2 = OGRGeometry(wkb)
  63
+            self.assertEqual(geom1, geom2)
  64
+
45 65
     def test02_points(self):
46 66
         "Testing Point objects."
47 67
 

0 notes on commit ddc9361

Please sign in to comment.
Something went wrong with that request. Please try again.