1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

gis: gdal: Added support for GeoJSON input/output in OGRGeometry.

git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@7107 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Justin Bronn 2008-02-13 00:38:36 +00:00
parent 21a019681c
commit d88c9ac644
5 changed files with 73 additions and 25 deletions

View File

@ -42,7 +42,7 @@
import re, sys
from binascii import a2b_hex
from ctypes import byref, string_at, c_char_p, c_double, c_ubyte, c_void_p
from types import BufferType, IntType, StringType, UnicodeType
from types import UnicodeType
# Getting GDAL prerequisites
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
@ -62,6 +62,7 @@ from django.contrib.gis.gdal.prototypes.srs import clone_srs
# Regular expressions for recognizing HEXEWKB and WKT.
hex_regex = re.compile(r'^[0-9A-F]+$', re.I)
wkt_regex = re.compile(r'^(?P<type>POINT|LINESTRING|LINEARRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)[ACEGIMLONPSRUTY\d,\.\-\(\) ]+$', re.I)
json_regex = re.compile(r'^\{.+\}$')
#### OGRGeometry Class ####
class OGRGeometry(object):
@ -71,32 +72,41 @@ class OGRGeometry(object):
"Initializes Geometry on either WKT or an OGR pointer as input."
self._ptr = c_void_p(None) # Initially NULL
str_instance = isinstance(geom_input, basestring)
# If HEX, unpack input to to a binary buffer.
if str_instance and hex_regex.match(geom_input):
geom_input = buffer(a2b_hex(geom_input.upper()))
str_instance = False
# Constructing the geometry,
if str_instance:
# 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):
m = wkt_regex.match(geom_input)
if m:
if m.group('type').upper() == 'LINEARRING':
wkt_m = wkt_regex.match(geom_input)
json_m = json_regex.match(geom_input)
if wkt_m:
if wkt_m.group('type').upper() == 'LINEARRING':
# OGR_G_CreateFromWkt doesn't work with LINEARRING WKT.
# See http://trac.osgeo.org/gdal/ticket/1992.
g = create_geom(OGRGeomType(m.group('type')).num)
g = create_geom(OGRGeomType(wkt_m.group('type')).num)
import_wkt(g, byref(c_char_p(geom_input)))
else:
g = from_wkt(byref(c_char_p(geom_input)), None, byref(c_void_p()))
elif json_m:
if GEOJSON:
g = from_json(geom_input)
else:
raise NotImplementedError('GeoJSON input only supported on GDAL 1.5+.')
else:
# Seeing if the input is a valid short-hand string
# (e.g., 'Point', 'POLYGON').
ogr_t = OGRGeomType(geom_input)
g = create_geom(OGRGeomType(geom_input).num)
elif isinstance(geom_input, BufferType):
elif isinstance(geom_input, buffer):
# WKB was passed in
g = from_wkb(str(geom_input), None, byref(c_void_p()), len(geom_input))
elif isinstance(geom_input, OGRGeomType):
@ -223,7 +233,7 @@ class OGRGeometry(object):
"Sets the SpatialReference for this geometry."
if isinstance(srs, SpatialReference):
srs_ptr = clone_srs(srs._ptr)
elif isinstance(srs, (StringType, UnicodeType, IntType)):
elif isinstance(srs, (int, long, basestring)):
sr = SpatialReference(srs)
srs_ptr = clone_srs(sr._ptr)
else:
@ -238,7 +248,7 @@ class OGRGeometry(object):
else: return None
def set_srid(self, srid):
if isinstance(srid, IntType):
if isinstance(srid, (int, long)):
self.srs = srid
else:
raise TypeError('SRID must be set with an integer.')
@ -263,6 +273,14 @@ class OGRGeometry(object):
return str(self.wkb).encode('hex').upper()
#return b2a_hex(self.wkb).upper()
@property
def json(self):
if GEOJSON:
return to_json(self._ptr)
else:
raise NotImplementedError('GeoJSON output only supported on GDAL 1.5+.')
geojson = json
@property
def wkb_size(self):
"Returns the size of the WKB buffer."
@ -310,7 +328,7 @@ class OGRGeometry(object):
geom_transform(self._ptr, coord_trans._ptr)
elif isinstance(coord_trans, SpatialReference):
geom_transform_to(self._ptr, coord_trans._ptr)
elif isinstance(coord_trans, (int, basestring)):
elif isinstance(coord_trans, (int, long, basestring)):
sr = SpatialReference(coord_trans)
geom_transform_to(self._ptr, sr._ptr)
else:
@ -542,7 +560,7 @@ class GeometryCollection(OGRGeometry):
for g in geom: add_geom(self._ptr, g._ptr)
else:
add_geom(self._ptr, geom._ptr)
elif isinstance(geom, (StringType, UnicodeType)):
elif isinstance(geom, basestring):
tmp = OGRGeometry(geom)
add_geom(self._ptr, tmp._ptr)
else:

View File

@ -1,5 +1,5 @@
import os, sys
from ctypes import CDLL, string_at
from ctypes import c_char_p, CDLL
from ctypes.util import find_library
from django.contrib.gis.gdal.error import OGRException
@ -48,10 +48,11 @@ def std_call(func):
return lgdal[func]
#### Version-information functions. ####
def _version_info(key):
"Returns GDAL library version information with the given key."
buf = lgdal.GDALVersionInfo(key)
if buf: return string_at(buf)
# Returns GDAL library version information with the given key.
_version_info = lgdal.GDALVersionInfo
_version_info.argtypes = [c_char_p]
_version_info.restype = c_char_p
def gdal_version():
"Returns only the GDAL version number information."
@ -67,9 +68,9 @@ def gdal_release_date(date=False):
If the date keyword argument is set to True, a Python datetime object
will be returned instead.
"""
from datetime import datetime
from datetime import date as date_type
rel = _version_info('RELEASE_DATE')
yy, mm, dd = map(int, (rel[0:4], rel[4:6], rel[6:8]))
d = datetime(yy, mm, dd)
d = date_type(yy, mm, dd)
if date: return d
else: return d.strftime('%Y/%m/%d')

View File

@ -1,11 +1,19 @@
from datetime import date
from ctypes import c_char, c_char_p, c_double, c_int, c_ubyte, c_void_p, POINTER
from django.contrib.gis.gdal.envelope import OGREnvelope
from django.contrib.gis.gdal.libgdal import lgdal
from django.contrib.gis.gdal.libgdal import lgdal, gdal_version
from django.contrib.gis.gdal.prototypes.errcheck import check_bool, check_envelope
from django.contrib.gis.gdal.prototypes.generation import \
const_string_output, double_output, geom_output, int_output, \
srs_output, string_output, void_output
# Some prototypes need to be aware of what version GDAL we have.
major, minor1, minor2 = map(int, gdal_version().split('.'))
if major <= 1 and minor1 <= 4:
GEOJSON = False
else:
GEOJSON = True
### Generation routines specific to this module ###
def env_func(f, argtypes):
"For getting OGREnvelopes."
@ -26,6 +34,14 @@ def topology_func(f):
### OGR_G ctypes function prototypes ###
# GeoJSON routines, if supported.
if GEOJSON:
from_json = geom_output(lgdal.OGR_G_CreateGeometryFromJson, [c_char_p])
to_json = string_output(lgdal.OGR_G_ExportToJson, [c_void_p], str_result=True)
else:
from_json = False
to_json = False
# GetX, GetY, GetZ all return doubles.
getx = pnt_func(lgdal.OGR_G_GetX)
gety = pnt_func(lgdal.OGR_G_GetY)

View File

@ -151,3 +151,6 @@ buffer_geoms = ( (TestGeom('POINT(0 0)'),
2.0, 8),
)
json_geoms = (TestGeom('POINT(100 0)', json='{ "type": "Point", "coordinates": [ 100.000000, 0.000000 ] }'),
TestGeom('MULTIPOLYGON(((102 2, 103 2, 103 3, 102 3, 102 2)), ((100.0 0.0, 101.0 0.0, 101.0 1.0, 100.0 1.0, 100.0 0.0), (100.2 0.2, 100.8 0.2, 100.8 0.8, 100.2 0.8, 100.2 0.2)))', json='{ "type": "MultiPolygon", "coordinates": [ [ [ [ 102.000000, 2.000000 ], [ 103.000000, 2.000000 ], [ 103.000000, 3.000000 ], [ 102.000000, 3.000000 ], [ 102.000000, 2.000000 ] ] ], [ [ [ 100.000000, 0.000000 ], [ 101.000000, 0.000000 ], [ 101.000000, 1.000000 ], [ 100.000000, 1.000000 ], [ 100.000000, 0.000000 ] ], [ [ 100.200000, 0.200000 ], [ 100.800000, 0.200000 ], [ 100.800000, 0.800000 ], [ 100.200000, 0.800000 ], [ 100.200000, 0.200000 ] ] ] ] }'),
)

View File

@ -63,6 +63,16 @@ class OGRGeomTest(unittest.TestCase):
geom2 = OGRGeometry(wkb)
self.assertEqual(geom1, geom2)
def test01e_json(self):
"Testing GeoJSON input/output."
from django.contrib.gis.gdal.prototypes.geom import GEOJSON
if not GEOJSON: return
for g in json_geoms:
geom = OGRGeometry(g.wkt)
self.assertEqual(g.json, geom.json)
self.assertEqual(g.json, geom.geojson)
self.assertEqual(OGRGeometry(g.wkt), OGRGeometry(geom.json))
def test02_points(self):
"Testing Point objects."