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:
parent
21a019681c
commit
d88c9ac644
@ -42,7 +42,7 @@
|
|||||||
import re, sys
|
import re, sys
|
||||||
from binascii import a2b_hex
|
from binascii import a2b_hex
|
||||||
from ctypes import byref, string_at, c_char_p, c_double, c_ubyte, c_void_p
|
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
|
# Getting GDAL prerequisites
|
||||||
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
|
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.
|
# Regular expressions for recognizing HEXEWKB and WKT.
|
||||||
hex_regex = re.compile(r'^[0-9A-F]+$', re.I)
|
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)
|
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 ####
|
#### OGRGeometry Class ####
|
||||||
class OGRGeometry(object):
|
class OGRGeometry(object):
|
||||||
@ -71,32 +72,41 @@ class OGRGeometry(object):
|
|||||||
"Initializes Geometry on either WKT or an OGR pointer as input."
|
"Initializes Geometry on either WKT or an OGR pointer as input."
|
||||||
|
|
||||||
self._ptr = c_void_p(None) # Initially NULL
|
self._ptr = c_void_p(None) # Initially NULL
|
||||||
|
str_instance = isinstance(geom_input, basestring)
|
||||||
# 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 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()))
|
geom_input = buffer(a2b_hex(geom_input.upper()))
|
||||||
|
str_instance = False
|
||||||
|
|
||||||
if isinstance(geom_input, StringType):
|
# Constructing the geometry,
|
||||||
m = wkt_regex.match(geom_input)
|
if str_instance:
|
||||||
if m:
|
# Checking if unicode
|
||||||
if m.group('type').upper() == 'LINEARRING':
|
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.
|
# OGR_G_CreateFromWkt doesn't work with LINEARRING WKT.
|
||||||
# See http://trac.osgeo.org/gdal/ticket/1992.
|
# 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)))
|
import_wkt(g, byref(c_char_p(geom_input)))
|
||||||
else:
|
else:
|
||||||
g = from_wkt(byref(c_char_p(geom_input)), None, byref(c_void_p()))
|
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:
|
else:
|
||||||
# Seeing if the input is a valid short-hand string
|
# Seeing if the input is a valid short-hand string
|
||||||
# (e.g., 'Point', 'POLYGON').
|
# (e.g., 'Point', 'POLYGON').
|
||||||
ogr_t = OGRGeomType(geom_input)
|
ogr_t = OGRGeomType(geom_input)
|
||||||
g = create_geom(OGRGeomType(geom_input).num)
|
g = create_geom(OGRGeomType(geom_input).num)
|
||||||
elif isinstance(geom_input, BufferType):
|
elif isinstance(geom_input, buffer):
|
||||||
# WKB was passed in
|
# WKB was passed in
|
||||||
g = from_wkb(str(geom_input), None, byref(c_void_p()), len(geom_input))
|
g = from_wkb(str(geom_input), None, byref(c_void_p()), len(geom_input))
|
||||||
elif isinstance(geom_input, OGRGeomType):
|
elif isinstance(geom_input, OGRGeomType):
|
||||||
@ -223,7 +233,7 @@ class OGRGeometry(object):
|
|||||||
"Sets the SpatialReference for this geometry."
|
"Sets the SpatialReference for this geometry."
|
||||||
if isinstance(srs, SpatialReference):
|
if isinstance(srs, SpatialReference):
|
||||||
srs_ptr = clone_srs(srs._ptr)
|
srs_ptr = clone_srs(srs._ptr)
|
||||||
elif isinstance(srs, (StringType, UnicodeType, IntType)):
|
elif isinstance(srs, (int, long, basestring)):
|
||||||
sr = SpatialReference(srs)
|
sr = SpatialReference(srs)
|
||||||
srs_ptr = clone_srs(sr._ptr)
|
srs_ptr = clone_srs(sr._ptr)
|
||||||
else:
|
else:
|
||||||
@ -238,7 +248,7 @@ class OGRGeometry(object):
|
|||||||
else: return None
|
else: return None
|
||||||
|
|
||||||
def set_srid(self, srid):
|
def set_srid(self, srid):
|
||||||
if isinstance(srid, IntType):
|
if isinstance(srid, (int, long)):
|
||||||
self.srs = srid
|
self.srs = srid
|
||||||
else:
|
else:
|
||||||
raise TypeError('SRID must be set with an integer.')
|
raise TypeError('SRID must be set with an integer.')
|
||||||
@ -263,6 +273,14 @@ class OGRGeometry(object):
|
|||||||
return str(self.wkb).encode('hex').upper()
|
return str(self.wkb).encode('hex').upper()
|
||||||
#return b2a_hex(self.wkb).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
|
@property
|
||||||
def wkb_size(self):
|
def wkb_size(self):
|
||||||
"Returns the size of the WKB buffer."
|
"Returns the size of the WKB buffer."
|
||||||
@ -310,7 +328,7 @@ class OGRGeometry(object):
|
|||||||
geom_transform(self._ptr, coord_trans._ptr)
|
geom_transform(self._ptr, coord_trans._ptr)
|
||||||
elif isinstance(coord_trans, SpatialReference):
|
elif isinstance(coord_trans, SpatialReference):
|
||||||
geom_transform_to(self._ptr, coord_trans._ptr)
|
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)
|
sr = SpatialReference(coord_trans)
|
||||||
geom_transform_to(self._ptr, sr._ptr)
|
geom_transform_to(self._ptr, sr._ptr)
|
||||||
else:
|
else:
|
||||||
@ -542,7 +560,7 @@ class GeometryCollection(OGRGeometry):
|
|||||||
for g in geom: add_geom(self._ptr, g._ptr)
|
for g in geom: add_geom(self._ptr, g._ptr)
|
||||||
else:
|
else:
|
||||||
add_geom(self._ptr, geom._ptr)
|
add_geom(self._ptr, geom._ptr)
|
||||||
elif isinstance(geom, (StringType, UnicodeType)):
|
elif isinstance(geom, basestring):
|
||||||
tmp = OGRGeometry(geom)
|
tmp = OGRGeometry(geom)
|
||||||
add_geom(self._ptr, tmp._ptr)
|
add_geom(self._ptr, tmp._ptr)
|
||||||
else:
|
else:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import os, sys
|
import os, sys
|
||||||
from ctypes import CDLL, string_at
|
from ctypes import c_char_p, CDLL
|
||||||
from ctypes.util import find_library
|
from ctypes.util import find_library
|
||||||
from django.contrib.gis.gdal.error import OGRException
|
from django.contrib.gis.gdal.error import OGRException
|
||||||
|
|
||||||
@ -48,10 +48,11 @@ def std_call(func):
|
|||||||
return lgdal[func]
|
return lgdal[func]
|
||||||
|
|
||||||
#### Version-information functions. ####
|
#### Version-information functions. ####
|
||||||
def _version_info(key):
|
|
||||||
"Returns GDAL library version information with the given key."
|
# Returns GDAL library version information with the given key.
|
||||||
buf = lgdal.GDALVersionInfo(key)
|
_version_info = lgdal.GDALVersionInfo
|
||||||
if buf: return string_at(buf)
|
_version_info.argtypes = [c_char_p]
|
||||||
|
_version_info.restype = c_char_p
|
||||||
|
|
||||||
def gdal_version():
|
def gdal_version():
|
||||||
"Returns only the GDAL version number information."
|
"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
|
If the date keyword argument is set to True, a Python datetime object
|
||||||
will be returned instead.
|
will be returned instead.
|
||||||
"""
|
"""
|
||||||
from datetime import datetime
|
from datetime import date as date_type
|
||||||
rel = _version_info('RELEASE_DATE')
|
rel = _version_info('RELEASE_DATE')
|
||||||
yy, mm, dd = map(int, (rel[0:4], rel[4:6], rel[6:8]))
|
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
|
if date: return d
|
||||||
else: return d.strftime('%Y/%m/%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 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.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.errcheck import check_bool, check_envelope
|
||||||
from django.contrib.gis.gdal.prototypes.generation import \
|
from django.contrib.gis.gdal.prototypes.generation import \
|
||||||
const_string_output, double_output, geom_output, int_output, \
|
const_string_output, double_output, geom_output, int_output, \
|
||||||
srs_output, string_output, void_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 ###
|
### Generation routines specific to this module ###
|
||||||
def env_func(f, argtypes):
|
def env_func(f, argtypes):
|
||||||
"For getting OGREnvelopes."
|
"For getting OGREnvelopes."
|
||||||
@ -26,6 +34,14 @@ def topology_func(f):
|
|||||||
|
|
||||||
### OGR_G ctypes function prototypes ###
|
### 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, GetY, GetZ all return doubles.
|
||||||
getx = pnt_func(lgdal.OGR_G_GetX)
|
getx = pnt_func(lgdal.OGR_G_GetX)
|
||||||
gety = pnt_func(lgdal.OGR_G_GetY)
|
gety = pnt_func(lgdal.OGR_G_GetY)
|
||||||
|
@ -151,3 +151,6 @@ buffer_geoms = ( (TestGeom('POINT(0 0)'),
|
|||||||
2.0, 8),
|
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)
|
geom2 = OGRGeometry(wkb)
|
||||||
self.assertEqual(geom1, geom2)
|
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):
|
def test02_points(self):
|
||||||
"Testing Point objects."
|
"Testing Point objects."
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user