mirror of
https://github.com/django/django.git
synced 2025-07-04 01:39:20 +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:
parent
21a019681c
commit
d88c9ac644
@ -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
|
||||
|
||||
# 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')
|
||||
str_instance = isinstance(geom_input, basestring)
|
||||
|
||||
# If HEX, unpack input to to a binary buffer.
|
||||
if isinstance(geom_input, StringType) and hex_regex.match(geom_input):
|
||||
if str_instance and hex_regex.match(geom_input):
|
||||
geom_input = buffer(a2b_hex(geom_input.upper()))
|
||||
str_instance = False
|
||||
|
||||
if isinstance(geom_input, StringType):
|
||||
m = wkt_regex.match(geom_input)
|
||||
if m:
|
||||
if m.group('type').upper() == 'LINEARRING':
|
||||
# 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')
|
||||
|
||||
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:
|
||||
|
@ -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')
|
||||
|
@ -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)
|
||||
|
@ -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 ] ] ] ] }'),
|
||||
)
|
||||
|
@ -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."
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user