Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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
@jbronn jbronn authored
View
4 django/contrib/gis/gdal/feature.py
@@ -1,6 +1,6 @@
# types and ctypes
from types import StringType
-from ctypes import c_char_p, c_int, string_at
+from ctypes import c_char_p, c_int, c_void_p, string_at
# The GDAL C library, OGR exception, and the Field object
from django.contrib.gis.gdal.libgdal import lgdal
@@ -98,7 +98,7 @@ def geom(self):
srs = None
# Geometry is cloned so the feature isn't invalidated.
- return OGRGeometry(lgdal.OGR_G_Clone(geom_ptr), srs)
+ return OGRGeometry(c_void_p(lgdal.OGR_G_Clone(geom_ptr)), srs)
@property
def geom_type(self):
View
117 django/contrib/gis/gdal/geometries.py
@@ -38,9 +38,11 @@
>>> print gt1 == 3, gt1 == 'Polygon' # Equivalence works w/non-OGRGeomType objects
True
"""
-# types & ctypes
-from types import IntType, StringType, UnicodeType
-from ctypes import byref, string_at, c_char_p, c_double, c_int, c_void_p
+# Python library imports
+import re, sys
+from binascii import a2b_hex, b2a_hex
+from ctypes import byref, create_string_buffer, string_at, c_char_p, c_double, c_int, c_void_p
+from types import BufferType, IntType, StringType, UnicodeType
# Getting GDAL prerequisites
from django.contrib.gis.gdal.libgdal import lgdal
@@ -70,6 +72,9 @@ def pnt_func(f):
get_area.restype = c_double
get_area.argtypes = [c_void_p]
+# Regular expression for determining whether the input is HEXEWKB.
+hex_regex = re.compile(r'^[0-9A-F]+$', re.I)
+
#### OGRGeometry Class ####
class OGRGeometry(object):
"Generally encapsulates an OGR geometry."
@@ -77,7 +82,16 @@ class OGRGeometry(object):
def __init__(self, geom_input, srs=None):
"Initializes Geometry on either WKT or an OGR pointer as input."
- self._g = 0 # Initially NULL
+ self._g = c_void_p(None) # Initially NULL
+
+ # Checking if unicode
+ if isinstance(geom_input, UnicodeType):
+ # Encoding to ASCII, WKT or HEX doesn't need any more.
+ geo_input = geo_input.encode('ascii')
+
+ # If HEX, unpack input to to a binary buffer.
+ if isinstance(geom_input, StringType) and hex_regex.match(geom_input):
+ geom_input = buffer(a2b_hex(geom_input.upper()))
if isinstance(geom_input, StringType):
# First, trying the input as WKT
@@ -93,10 +107,15 @@ def __init__(self, geom_input, srs=None):
g = lgdal.OGR_G_CreateGeometry(ogr_t.num)
except:
raise OGRException('Could not initialize OGR Geometry from: %s' % geom_input)
+ elif isinstance(geom_input, BufferType):
+ # WKB was passed in
+ g = c_void_p()
+ check_err(lgdal.OGR_G_CreateFromWkb(c_char_p(str(geom_input)), c_void_p(), byref(g), len(geom_input)))
elif isinstance(geom_input, OGRGeomType):
+ # OGRGeomType was passed in, an empty geometry will be created.
g = lgdal.OGR_G_CreateGeometry(geom_input.num)
- elif isinstance(geom_input, IntType):
- # OGR Pointer (integer) was the input
+ elif isinstance(geom_input, c_void_p):
+ # OGR pointer (c_void_p) was the input.
g = geom_input
else:
raise OGRException('Type of input cannot be determined!')
@@ -181,6 +200,30 @@ def num_coords(self):
"Returns the number of Points in this Geometry."
return self.point_count
+ @property
+ def geom_type(self):
+ "Returns the Type for this Geometry."
+ return OGRGeomType(lgdal.OGR_G_GetGeometryType(self._g))
+
+ @property
+ def geom_name(self):
+ "Returns the Name of this Geometry."
+ return string_at(lgdal.OGR_G_GetGeometryName(self._g))
+
+ @property
+ def area(self):
+ "Returns the area for a LinearRing, Polygon, or MultiPolygon; 0 otherwise."
+ return get_area(self._g)
+
+ @property
+ def envelope(self):
+ "Returns the envelope for this Geometry."
+ env = OGREnvelope()
+ lgdal.OGR_G_GetEnvelope(self._g, byref(env))
+ return Envelope(env)
+
+ #### SpatialReference-related Properties ####
+
# The SRS property
def get_srs(self):
"Returns the Spatial Reference for this Geometry."
@@ -216,28 +259,6 @@ def set_srid(self, srid):
srid = property(get_srid, set_srid)
- @property
- def geom_type(self):
- "Returns the Type for this Geometry."
- return OGRGeomType(lgdal.OGR_G_GetGeometryType(self._g))
-
- @property
- def geom_name(self):
- "Returns the Name of this Geometry."
- return string_at(lgdal.OGR_G_GetGeometryName(self._g))
-
- @property
- def area(self):
- "Returns the area for a LinearRing, Polygon, or MultiPolygon; 0 otherwise."
- return get_area(self._g)
-
- @property
- def envelope(self):
- "Returns the envelope for this Geometry."
- env = OGREnvelope()
- lgdal.OGR_G_GetEnvelope(self._g, byref(env))
- return Envelope(env)
-
#### Output Methods ####
@property
def gml(self):
@@ -247,6 +268,30 @@ def gml(self):
else: return None
@property
+ def hex(self):
+ "Returns the hexadecimal representation of the WKB (a string)."
+ return b2a_hex(self.wkb).upper()
+
+ @property
+ def wkb_size(self):
+ "Returns the size of the WKB buffer."
+ return lgdal.OGR_G_WkbSize(self._g)
+
+ @property
+ def wkb(self):
+ "Returns the WKB representation of the Geometry."
+ if sys.byteorder == 'little':
+ byteorder = c_int(1) # wkbNDR (from ogr_core.h)
+ else:
+ byteorder = c_int(0) # wkbXDR (from ogr_core.h)
+ # Creating a mutable string buffer of the given size, exporting
+ # to WKB, and returning a Python buffer of the WKB.
+ sz = self.wkb_size
+ wkb = create_string_buffer(sz)
+ check_err(lgdal.OGR_G_ExportToWkb(self._g, byteorder, byref(wkb)))
+ return buffer(string_at(wkb, sz))
+
+ @property
def wkt(self):
"Returns the WKT representation of the Geometry."
buf = c_char_p()
@@ -256,7 +301,7 @@ def wkt(self):
#### Geometry Methods ####
def clone(self):
"Clones this OGR Geometry."
- return OGRGeometry(lgdal.OGR_G_Clone(self._g))
+ return OGRGeometry(c_void_p(lgdal.OGR_G_Clone(self._g)))
def close_rings(self):
"""If there are any rings within this geometry that have not been
@@ -327,9 +372,9 @@ def overlaps(self, other):
def _geomgen(self, gen_func, other=None):
"A helper routine for the OGR routines that generate geometries."
if isinstance(other, OGRGeometry):
- return OGRGeometry(gen_func(self._g, other._g))
+ return OGRGeometry(c_void_p(gen_func(self._g, other._g)))
else:
- return OGRGeometry(gen_func(self._g))
+ return OGRGeometry(c_void_p(gen_func(self._g)))
@property
def boundary(self):
@@ -382,9 +427,7 @@ def z(self):
@property
def tuple(self):
"Returns the tuple of this point."
- if self.coord_dim == 1:
- return (self.x,)
- elif self.coord_dim == 2:
+ if self.coord_dim == 2:
return (self.x, self.y)
elif self.coord_dim == 3:
return (self.x, self.y, self.z)
@@ -441,7 +484,7 @@ def __getitem__(self, index):
if index < 0 or index >= self.geom_count:
raise OGRIndexError('index out of range: %s' % str(index))
else:
- return OGRGeometry(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index))), self.srs)
+ return OGRGeometry(c_void_p(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index)))), self.srs)
# Polygon Properties
@property
@@ -477,7 +520,7 @@ def __getitem__(self, index):
if index < 0 or index >= self.geom_count:
raise OGRIndexError('index out of range: %s' % str(index))
else:
- return OGRGeometry(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index))), self.srs)
+ return OGRGeometry(c_void_p(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index)))), self.srs)
def __iter__(self):
"Iterates over each Geometry."
@@ -492,7 +535,7 @@ def add(self, geom):
"Add the geometry to this Geometry Collection."
if isinstance(geom, OGRGeometry):
ptr = geom._g
- elif isinstance(geom, StringType):
+ elif isinstance(geom, (StringType, UnicodeType)):
tmp = OGRGeometry(geom)
ptr = tmp._g
else:
View
22 django/contrib/gis/tests/test_gdal_geom.py
@@ -1,6 +1,6 @@
import unittest
from django.contrib.gis.gdal import OGRGeometry, OGRGeomType, OGRException, SpatialReference
-from geometries import *
+from django.contrib.gis.tests.geometries import *
class OGRGeomTest(unittest.TestCase):
"This tests the OGR Geometry."
@@ -42,6 +42,26 @@ def test01b_gml(self):
geom = OGRGeometry(g.wkt)
self.assertEqual(g.gml, geom.gml)
+ def test01c_hex(self):
+ "Testing HEX input/output."
+ for g in hex_wkt:
+ geom1 = OGRGeometry(g.wkt)
+ self.assertEqual(g.hex, geom1.hex)
+ # Constructing w/HEX
+ geom2 = OGRGeometry(g.hex)
+ self.assertEqual(geom1, geom2)
+
+ def test01d_wkb(self):
+ "Testing WKB input/output."
+ from binascii import b2a_hex
+ for g in hex_wkt:
+ geom1 = OGRGeometry(g.wkt)
+ wkb = geom1.wkb
+ self.assertEqual(b2a_hex(wkb).upper(), g.hex)
+ # Constructing w/WKB.
+ geom2 = OGRGeometry(wkb)
+ self.assertEqual(geom1, geom2)
+
def test02_points(self):
"Testing Point objects."
Please sign in to comment.
Something went wrong with that request. Please try again.