mirror of
https://github.com/django/django.git
synced 2025-07-04 09:49:12 +00:00
gis: gdal: refactor of the GDAL ctypes interface
(1) All interactions with the GDAL library take place through predefined ctypes prototypes, abstracting away error-checking. (2) Fixed memory leaks by properly freeing pointers allocated w/in GDAL. (3) Improved OFTField support, and added support for the OGR date/time fields. (4) Significantly improved the OGRGeometry tests. git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@6686 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
f66821deae
commit
ef32f913a0
@ -1,13 +1,3 @@
|
|||||||
# types and ctypes
|
|
||||||
from types import StringType
|
|
||||||
from ctypes import c_char_p, c_int, c_void_p, byref, string_at
|
|
||||||
|
|
||||||
# The GDAL C library, OGR exceptions, and the Layer object.
|
|
||||||
from django.contrib.gis.gdal.libgdal import lgdal
|
|
||||||
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, check_err
|
|
||||||
from django.contrib.gis.gdal.layer import Layer
|
|
||||||
from django.contrib.gis.gdal.driver import Driver
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
DataSource is a wrapper for the OGR Data Source object, which provides
|
DataSource is a wrapper for the OGR Data Source object, which provides
|
||||||
an interface for reading vector geometry data from many different file
|
an interface for reading vector geometry data from many different file
|
||||||
@ -43,63 +33,81 @@ from django.contrib.gis.gdal.driver import Driver
|
|||||||
# OFTReal returns floats, all else returns string.
|
# OFTReal returns floats, all else returns string.
|
||||||
val = field.value
|
val = field.value
|
||||||
"""
|
"""
|
||||||
|
# ctypes prerequisites.
|
||||||
|
from ctypes import byref, c_void_p
|
||||||
|
|
||||||
|
# The GDAL C library, OGR exceptions, and the Layer object.
|
||||||
|
from django.contrib.gis.gdal.driver import Driver
|
||||||
|
from django.contrib.gis.gdal.error import OGRException, OGRIndexError
|
||||||
|
from django.contrib.gis.gdal.layer import Layer
|
||||||
|
|
||||||
|
# Getting the ctypes prototypes for the DataSource.
|
||||||
|
from django.contrib.gis.gdal.prototypes.ds import \
|
||||||
|
destroy_ds, get_driver_count, register_all, open_ds, release_ds, \
|
||||||
|
get_ds_name, get_layer, get_layer_count, get_layer_by_name
|
||||||
|
|
||||||
# For more information, see the OGR C API source code:
|
# For more information, see the OGR C API source code:
|
||||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
# http://www.gdal.org/ogr/ogr__api_8h.html
|
||||||
#
|
#
|
||||||
# The OGR_DS_* routines are relevant here.
|
# The OGR_DS_* routines are relevant here.
|
||||||
|
|
||||||
class DataSource(object):
|
class DataSource(object):
|
||||||
"Wraps an OGR Data Source object."
|
"Wraps an OGR Data Source object."
|
||||||
|
|
||||||
#### Python 'magic' routines ####
|
#### Python 'magic' routines ####
|
||||||
def __init__(self, ds_input, ds_driver=False):
|
def __init__(self, ds_input, ds_driver=False, write=False):
|
||||||
|
|
||||||
self._ds = None # Initially NULL
|
# DataSource pointer is initially NULL.
|
||||||
|
self._ptr = None
|
||||||
|
|
||||||
|
# The write flag.
|
||||||
|
if write:
|
||||||
|
self._write = 1
|
||||||
|
else:
|
||||||
|
self._write = 0
|
||||||
|
|
||||||
# Registering all the drivers, this needs to be done
|
# Registering all the drivers, this needs to be done
|
||||||
# _before_ we try to open up a data source.
|
# _before_ we try to open up a data source.
|
||||||
if not lgdal.OGRGetDriverCount() and not lgdal.OGRRegisterAll():
|
if not get_driver_count() and not register_all():
|
||||||
raise OGRException('Could not register all the OGR data source drivers!')
|
raise OGRException('Could not register all the OGR data source drivers!')
|
||||||
|
|
||||||
if isinstance(ds_input, StringType):
|
if isinstance(ds_input, basestring):
|
||||||
|
|
||||||
# The data source driver is a void pointer.
|
# The data source driver is a void pointer.
|
||||||
ds_driver = c_void_p()
|
ds_driver = c_void_p()
|
||||||
|
|
||||||
# OGROpen will auto-detect the data source type.
|
# OGROpen will auto-detect the data source type.
|
||||||
ds = lgdal.OGROpen(c_char_p(ds_input), c_int(0), byref(ds_driver))
|
ds = open_ds(ds_input, self._write, byref(ds_driver))
|
||||||
elif isinstance(ds_input, c_void_p) and isinstance(ds_driver, c_void_p):
|
elif isinstance(ds_input, c_void_p) and isinstance(ds_driver, c_void_p):
|
||||||
ds = ds_input
|
ds = ds_input
|
||||||
else:
|
else:
|
||||||
raise OGRException('Invalid data source input type: %s' % str(type(ds_input)))
|
raise OGRException('Invalid data source input type: %s' % type(ds_input))
|
||||||
|
|
||||||
# Raise an exception if the returned pointer is NULL
|
if bool(ds):
|
||||||
if not ds:
|
self._ptr = ds
|
||||||
self._ds = False
|
|
||||||
raise OGRException('Invalid data source file "%s"' % ds_input)
|
|
||||||
else:
|
|
||||||
self._ds = ds
|
|
||||||
self._driver = Driver(ds_driver)
|
self._driver = Driver(ds_driver)
|
||||||
|
else:
|
||||||
|
# Raise an exception if the returned pointer is NULL
|
||||||
|
raise OGRException('Invalid data source file "%s"' % ds_input)
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
"This releases the reference to the data source (destroying it if it's the only one)."
|
"Destroys this DataStructure object."
|
||||||
if self._ds: lgdal.OGRReleaseDataSource(self._ds)
|
if self._ptr: destroy_ds(self._ptr)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
"Allows for iteration over the layers in a data source."
|
"Allows for iteration over the layers in a data source."
|
||||||
for i in xrange(self.layer_count):
|
for i in xrange(self.layer_count):
|
||||||
yield self.__getitem__(i)
|
yield self[i]
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
"Allows use of the index [] operator to get a layer at the index."
|
"Allows use of the index [] operator to get a layer at the index."
|
||||||
if isinstance(index, StringType):
|
if isinstance(index, basestring):
|
||||||
l = lgdal.OGR_DS_GetLayerByName(self._ds, c_char_p(index))
|
l = get_layer_by_name(self._ptr, index)
|
||||||
if not l: raise OGRIndexError('invalid OGR Layer name given: "%s"' % index)
|
if not l: raise OGRIndexError('invalid OGR Layer name given: "%s"' % index)
|
||||||
else:
|
elif isinstance(index, int):
|
||||||
if index < 0 or index >= self.layer_count:
|
if index < 0 or index >= self.layer_count:
|
||||||
raise OGRIndexError('index out of range')
|
raise OGRIndexError('index out of range')
|
||||||
l = lgdal.OGR_DS_GetLayer(self._ds, c_int(index))
|
l = get_layer(self._ptr, index)
|
||||||
|
else:
|
||||||
|
raise TypeError('Invalid index type: %s' % type(index))
|
||||||
return Layer(l)
|
return Layer(l)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
@ -119,10 +127,9 @@ class DataSource(object):
|
|||||||
@property
|
@property
|
||||||
def layer_count(self):
|
def layer_count(self):
|
||||||
"Returns the number of layers in the data source."
|
"Returns the number of layers in the data source."
|
||||||
return lgdal.OGR_DS_GetLayerCount(self._ds)
|
return get_layer_count(self._ptr)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"Returns the name of the data source."
|
"Returns the name of the data source."
|
||||||
return string_at(lgdal.OGR_DS_GetName(self._ds))
|
return get_ds_name(self._ptr)
|
||||||
|
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
# types and ctypes
|
# prerequisites imports
|
||||||
from types import StringType
|
from ctypes import c_void_p
|
||||||
from ctypes import c_char_p, c_int, c_void_p, byref, string_at
|
|
||||||
|
|
||||||
# The GDAL C library, OGR exceptions, and the Layer object.
|
|
||||||
from django.contrib.gis.gdal.libgdal import lgdal
|
|
||||||
from django.contrib.gis.gdal.error import OGRException
|
from django.contrib.gis.gdal.error import OGRException
|
||||||
|
from django.contrib.gis.gdal.prototypes.ds import \
|
||||||
|
get_driver, get_driver_by_name, get_driver_count, get_driver_name, register_all
|
||||||
|
|
||||||
# For more information, see the OGR C API source code:
|
# For more information, see the OGR C API source code:
|
||||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
# http://www.gdal.org/ogr/ogr__api_8h.html
|
||||||
#
|
#
|
||||||
# The OGR_Dr_* routines are relevant here.
|
# The OGR_Dr_* routines are relevant here.
|
||||||
|
|
||||||
class Driver(object):
|
class Driver(object):
|
||||||
"Wraps an OGR Data Source Driver."
|
"Wraps an OGR Data Source Driver."
|
||||||
|
|
||||||
@ -22,64 +19,49 @@ class Driver(object):
|
|||||||
'tiger/line' : 'TIGER',
|
'tiger/line' : 'TIGER',
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, input, ptr=False):
|
def __init__(self, dr_input):
|
||||||
"Initializes an OGR driver on either a string or integer input."
|
"Initializes an OGR driver on either a string or integer input."
|
||||||
|
|
||||||
if isinstance(input, StringType):
|
if isinstance(dr_input, basestring):
|
||||||
# If a string name of the driver was passed in
|
# If a string name of the driver was passed in
|
||||||
self._dr = None # Initially NULL
|
self._ptr = None # Initially NULL
|
||||||
self._register()
|
self._register()
|
||||||
|
|
||||||
# Checking the alias dictionary (case-insensitive) to see if an alias
|
# Checking the alias dictionary (case-insensitive) to see if an alias
|
||||||
# exists for the given driver.
|
# exists for the given driver.
|
||||||
if input.lower() in self._alias:
|
if dr_input.lower() in self._alias:
|
||||||
name = c_char_p(self._alias[input.lower()])
|
name = self._alias[dr_input.lower()]
|
||||||
else:
|
else:
|
||||||
name = c_char_p(input)
|
name = dr_input
|
||||||
|
|
||||||
# Attempting to get the OGR driver by the string name.
|
# Attempting to get the OGR driver by the string name.
|
||||||
dr = lgdal.OGRGetDriverByName(name)
|
dr = get_driver_by_name(name)
|
||||||
elif isinstance(input, int):
|
elif isinstance(dr_input, int):
|
||||||
self._register()
|
self._register()
|
||||||
dr = lgdal.OGRGetDriver(c_int(input))
|
dr = get_driver(dr_input)
|
||||||
elif isinstance(input, c_void_p):
|
elif isinstance(dr_input, c_void_p):
|
||||||
dr = input
|
dr = dr_input
|
||||||
else:
|
else:
|
||||||
raise OGRException('Unrecognized input type for OGR Driver: %s' % str(type(input)))
|
raise OGRException('Unrecognized input type for OGR Driver: %s' % str(type(dr_input)))
|
||||||
|
|
||||||
# Making sure we get a valid pointer to the OGR Driver
|
# Making sure we get a valid pointer to the OGR Driver
|
||||||
if not dr:
|
if not dr:
|
||||||
raise OGRException('Could not initialize OGR Driver on input: %s' % str(input))
|
raise OGRException('Could not initialize OGR Driver on input: %s' % str(dr_input))
|
||||||
self._dr = dr
|
self._ptr = dr
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"Returns the string name of the OGR Driver."
|
"Returns the string name of the OGR Driver."
|
||||||
return string_at(lgdal.OGR_Dr_GetName(self._dr))
|
return get_driver_name(self._ptr)
|
||||||
|
|
||||||
def _register(self):
|
def _register(self):
|
||||||
"Attempts to register all the data source drivers."
|
"Attempts to register all the data source drivers."
|
||||||
# Only register all if the driver count is 0 (or else all drivers
|
# Only register all if the driver count is 0 (or else all drivers
|
||||||
# will be registered over and over again)
|
# will be registered over and over again)
|
||||||
if not self.driver_count and not lgdal.OGRRegisterAll():
|
if not self.driver_count and not register_all():
|
||||||
raise OGRException('Could not register all the OGR data source drivers!')
|
raise OGRException('Could not register all the OGR data source drivers!')
|
||||||
|
|
||||||
# Driver properties
|
# Driver properties
|
||||||
@property
|
@property
|
||||||
def driver_count(self):
|
def driver_count(self):
|
||||||
"Returns the number of OGR data source drivers registered."
|
"Returns the number of OGR data source drivers registered."
|
||||||
return lgdal.OGRGetDriverCount()
|
return get_driver_count()
|
||||||
|
|
||||||
def create_ds(self, **kwargs):
|
|
||||||
"Creates a data source using the keyword args as name value options."
|
|
||||||
raise NotImplementedError
|
|
||||||
# Getting the options string
|
|
||||||
#options = ''
|
|
||||||
#n_opts = len(kwargs)
|
|
||||||
#for i in xrange(n_opts):
|
|
||||||
# options += '%s=%s' % (str(k), str(v))
|
|
||||||
# if i < n_opts-1: options += ','
|
|
||||||
#opts = c_char_p(options)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
| |
|
| |
|
||||||
| |
|
| |
|
||||||
Lower left (min_x, min_y) o----------+
|
Lower left (min_x, min_y) o----------+
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from ctypes import Structure, c_double
|
from ctypes import Structure, c_double
|
||||||
from types import TupleType, ListType
|
from types import TupleType, ListType
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
check_err() routine which checks the status code returned by
|
check_err() routine which checks the status code returned by
|
||||||
OGR methods.
|
OGR methods.
|
||||||
"""
|
"""
|
||||||
|
#### OGR & SRS Exceptions ####
|
||||||
# OGR & SRS Exceptions
|
|
||||||
class OGRException(Exception): pass
|
class OGRException(Exception): pass
|
||||||
class SRSException(Exception): pass
|
class SRSException(Exception): pass
|
||||||
class OGRIndexError(OGRException, KeyError):
|
class OGRIndexError(OGRException, KeyError):
|
||||||
@ -16,6 +15,8 @@ class OGRIndexError(OGRException, KeyError):
|
|||||||
"""
|
"""
|
||||||
silent_variable_failure = True
|
silent_variable_failure = True
|
||||||
|
|
||||||
|
#### OGR error checking codes and routine ####
|
||||||
|
|
||||||
# OGR Error Codes
|
# OGR Error Codes
|
||||||
OGRERR_DICT = { 1 : (OGRException, 'Not enough data.'),
|
OGRERR_DICT = { 1 : (OGRException, 'Not enough data.'),
|
||||||
2 : (OGRException, 'Not enough memory.'),
|
2 : (OGRException, 'Not enough memory.'),
|
||||||
@ -36,4 +37,4 @@ def check_err(code):
|
|||||||
e, msg = OGRERR_DICT[code]
|
e, msg = OGRERR_DICT[code]
|
||||||
raise e, msg
|
raise e, msg
|
||||||
else:
|
else:
|
||||||
raise OGRException, 'Unknown error code: "%s"' % code
|
raise OGRException('Unknown error code: "%s"' % code)
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
# types and ctypes
|
|
||||||
from types import StringType
|
|
||||||
from ctypes import c_char_p, c_int, c_void_p, string_at
|
|
||||||
|
|
||||||
# The GDAL C library, OGR exception, and the Field object
|
# The GDAL C library, OGR exception, and the Field object
|
||||||
from django.contrib.gis.gdal.libgdal import lgdal
|
|
||||||
from django.contrib.gis.gdal.error import OGRException, OGRIndexError
|
from django.contrib.gis.gdal.error import OGRException, OGRIndexError
|
||||||
from django.contrib.gis.gdal.field import Field
|
from django.contrib.gis.gdal.field import Field
|
||||||
from django.contrib.gis.gdal.geometries import OGRGeometry, OGRGeomType
|
from django.contrib.gis.gdal.geometries import OGRGeometry, OGRGeomType
|
||||||
from django.contrib.gis.gdal.srs import SpatialReference
|
from django.contrib.gis.gdal.srs import SpatialReference
|
||||||
|
|
||||||
|
# ctypes function prototypes
|
||||||
|
from django.contrib.gis.gdal.prototypes.ds import \
|
||||||
|
destroy_feature, feature_equal, get_fd_geom_type, get_feat_geom_ref, \
|
||||||
|
get_feat_name, get_feat_field_count, get_fid, get_field_defn, \
|
||||||
|
get_field_index
|
||||||
|
from django.contrib.gis.gdal.prototypes.geom import clone_geom, get_geom_srs
|
||||||
|
from django.contrib.gis.gdal.prototypes.srs import clone_srs
|
||||||
|
|
||||||
# For more information, see the OGR C API source code:
|
# For more information, see the OGR C API source code:
|
||||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
# http://www.gdal.org/ogr/ogr__api_8h.html
|
||||||
#
|
#
|
||||||
@ -18,33 +21,31 @@ class Feature(object):
|
|||||||
|
|
||||||
#### Python 'magic' routines ####
|
#### Python 'magic' routines ####
|
||||||
def __init__(self, feat, fdefn):
|
def __init__(self, feat, fdefn):
|
||||||
"Needs a C pointer (Python integer in ctypes) in order to initialize."
|
"Initializes on the pointers for the feature and the layer definition."
|
||||||
self._feat = None # Initially NULL
|
self._ptr = None # Initially NULL
|
||||||
self._fdefn = None
|
|
||||||
if not feat or not fdefn:
|
if not feat or not fdefn:
|
||||||
raise OGRException('Cannot create OGR Feature, invalid pointer given.')
|
raise OGRException('Cannot create OGR Feature, invalid pointer given.')
|
||||||
self._feat = feat
|
self._ptr = feat
|
||||||
self._fdefn = fdefn
|
self._fdefn = fdefn
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
"Releases a reference to this object."
|
"Releases a reference to this object."
|
||||||
if self._feat: lgdal.OGR_F_Destroy(self._feat)
|
if self._ptr: destroy_feature(self._ptr)
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
"Gets the Field at the specified index."
|
"Gets the Field at the specified index."
|
||||||
if isinstance(index, StringType):
|
if isinstance(index, basestring):
|
||||||
i = self.index(index)
|
i = self.index(index)
|
||||||
else:
|
else:
|
||||||
if index < 0 or index > self.num_fields:
|
if index < 0 or index > self.num_fields:
|
||||||
raise OGRIndexError('index out of range')
|
raise OGRIndexError('index out of range')
|
||||||
i = index
|
i = index
|
||||||
return Field(lgdal.OGR_F_GetFieldDefnRef(self._feat, c_int(i)),
|
return Field(self._ptr, i)
|
||||||
string_at(lgdal.OGR_F_GetFieldAsString(self._feat, c_int(i))))
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
"Iterates over each field in the Feature."
|
"Iterates over each field in the Feature."
|
||||||
for i in xrange(self.num_fields):
|
for i in xrange(self.num_fields):
|
||||||
yield self.__getitem__(i)
|
yield self[i]
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
"Returns the count of fields in this feature."
|
"Returns the count of fields in this feature."
|
||||||
@ -56,54 +57,49 @@ class Feature(object):
|
|||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
"Does equivalence testing on the features."
|
"Does equivalence testing on the features."
|
||||||
if lgdal.OGR_F_Equal(self._feat, other._feat):
|
return bool(feature_equal(self._ptr, other._ptr))
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
#### Feature Properties ####
|
#### Feature Properties ####
|
||||||
@property
|
@property
|
||||||
def fid(self):
|
def fid(self):
|
||||||
"Returns the feature identifier."
|
"Returns the feature identifier."
|
||||||
return lgdal.OGR_F_GetFID(self._feat)
|
return get_fid(self._ptr)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def layer_name(self):
|
def layer_name(self):
|
||||||
"Returns the name of the layer for the feature."
|
"Returns the name of the layer for the feature."
|
||||||
return string_at(lgdal.OGR_FD_GetName(self._fdefn))
|
return get_feat_name(self._fdefn)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def num_fields(self):
|
def num_fields(self):
|
||||||
"Returns the number of fields in the Feature."
|
"Returns the number of fields in the Feature."
|
||||||
return lgdal.OGR_F_GetFieldCount(self._feat)
|
return get_feat_field_count(self._ptr)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fields(self):
|
def fields(self):
|
||||||
"Returns a list of fields in the Feature."
|
"Returns a list of fields in the Feature."
|
||||||
return [ string_at(lgdal.OGR_Fld_GetNameRef(lgdal.OGR_FD_GetFieldDefn(self._fdefn, i)))
|
return [get_field_name(get_field_defn(self._fdefn, i))
|
||||||
for i in xrange(self.num_fields)]
|
for i in xrange(self.num_fields)]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def geom(self):
|
def geom(self):
|
||||||
"Returns the OGR Geometry for this Feature."
|
"Returns the OGR Geometry for this Feature."
|
||||||
# Retrieving the geometry pointer for the feature.
|
# Retrieving the geometry pointer for the feature.
|
||||||
geom_ptr = lgdal.OGR_F_GetGeometryRef(self._feat)
|
geom_ptr = get_feat_geom_ref(self._ptr)
|
||||||
if not geom_ptr:
|
|
||||||
raise OGRException('Cannot retrieve Geometry from the feature.')
|
|
||||||
|
|
||||||
# Attempting to retrieve the Spatial Reference for the geometry.
|
# Attempting to retrieve the Spatial Reference for the geometry.
|
||||||
srs_ptr = lgdal.OSRClone(lgdal.OGR_G_GetSpatialReference(geom_ptr))
|
try:
|
||||||
if srs_ptr:
|
srs_ptr = get_geom_srs(geom_ptr)
|
||||||
srs = SpatialReference(srs_ptr, 'ogr')
|
srs = SpatialReference(clone_srs(srs_ptr))
|
||||||
else:
|
except OGRException:
|
||||||
srs = None
|
srs = None
|
||||||
|
|
||||||
# Geometry is cloned so the feature isn't invalidated.
|
# Geometry is cloned so the feature isn't invalidated.
|
||||||
return OGRGeometry(c_void_p(lgdal.OGR_G_Clone(geom_ptr)), srs)
|
return OGRGeometry(clone_geom(geom_ptr), srs)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def geom_type(self):
|
def geom_type(self):
|
||||||
"Returns the OGR Geometry Type for this Feture."
|
"Returns the OGR Geometry Type for this Feture."
|
||||||
return OGRGeomType(lgdal.OGR_FD_GetGeomType(self._fdefn))
|
return OGRGeomType(get_fd_geom_type(self._fdefn))
|
||||||
|
|
||||||
#### Feature Methods ####
|
#### Feature Methods ####
|
||||||
def get(self, field):
|
def get(self, field):
|
||||||
@ -113,14 +109,10 @@ class Feature(object):
|
|||||||
parameters.
|
parameters.
|
||||||
"""
|
"""
|
||||||
field_name = getattr(field, 'name', field)
|
field_name = getattr(field, 'name', field)
|
||||||
return self.__getitem__(field_name).value
|
return self[field_name].value
|
||||||
|
|
||||||
def index(self, field_name):
|
def index(self, field_name):
|
||||||
"Returns the index of the given field name."
|
"Returns the index of the given field name."
|
||||||
i = lgdal.OGR_F_GetFieldIndex(self._feat, c_char_p(field_name))
|
i = get_field_index(self._ptr, field_name)
|
||||||
if i < 0: raise OGRIndexError('invalid OFT field name given: "%s"' % field_name)
|
if i < 0: raise OGRIndexError('invalid OFT field name given: "%s"' % field_name)
|
||||||
return i
|
return i
|
||||||
|
|
||||||
def clone(self):
|
|
||||||
"Clones this Feature."
|
|
||||||
return Feature(lgdal.OGR_F_Clone(self._feat))
|
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
from ctypes import string_at
|
from ctypes import byref, c_int
|
||||||
from django.contrib.gis.gdal.libgdal import lgdal
|
from datetime import date, datetime, time
|
||||||
from django.contrib.gis.gdal.error import OGRException
|
from django.contrib.gis.gdal.error import OGRException
|
||||||
|
from django.contrib.gis.gdal.prototypes.ds import \
|
||||||
|
get_feat_field_defn, get_field_as_datetime, get_field_as_double, \
|
||||||
|
get_field_as_integer, get_field_as_string, get_field_name, get_field_precision, \
|
||||||
|
get_field_type, get_field_type_name, get_field_width
|
||||||
|
|
||||||
# For more information, see the OGR C API source code:
|
# For more information, see the OGR C API source code:
|
||||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
# http://www.gdal.org/ogr/ogr__api_8h.html
|
||||||
@ -10,70 +14,145 @@ class Field(object):
|
|||||||
"A class that wraps an OGR Field, needs to be instantiated from a Feature object."
|
"A class that wraps an OGR Field, needs to be instantiated from a Feature object."
|
||||||
|
|
||||||
#### Python 'magic' routines ####
|
#### Python 'magic' routines ####
|
||||||
def __init__(self, fld, val=''):
|
def __init__(self, feat, index):
|
||||||
"Needs a C pointer (Python integer in ctypes) in order to initialize."
|
"""
|
||||||
self._fld = None # Initially NULL
|
Initializes on the feature pointer and the integer index of
|
||||||
|
the field within the feature.
|
||||||
|
"""
|
||||||
|
# Setting the feature pointer and index.
|
||||||
|
self._feat = feat
|
||||||
|
self._index = index
|
||||||
|
|
||||||
|
# Getting the pointer for this field.
|
||||||
|
fld = get_feat_field_defn(feat, index)
|
||||||
if not fld:
|
if not fld:
|
||||||
raise OGRException('Cannot create OGR Field, invalid pointer given.')
|
raise OGRException('Cannot create OGR Field, invalid pointer given.')
|
||||||
self._fld = fld
|
self._ptr = fld
|
||||||
self._val = val
|
|
||||||
|
|
||||||
# Setting the class depending upon the OGR Field Type (OFT)
|
# Setting the class depending upon the OGR Field Type (OFT)
|
||||||
self.__class__ = FIELD_CLASSES[self.type]
|
self.__class__ = FIELD_CLASSES[self.type]
|
||||||
|
|
||||||
|
# OFTReal with no precision should be an OFTInteger.
|
||||||
|
if isinstance(self, OFTReal) and self.precision == 0:
|
||||||
|
self.__class__ = OFTInteger
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"Returns the string representation of the Field."
|
"Returns the string representation of the Field."
|
||||||
return '%s (%s)' % (self.name, self.value)
|
return str(self.value).strip()
|
||||||
|
|
||||||
|
#### Field Methods ####
|
||||||
|
def as_double(self):
|
||||||
|
"Retrieves the Field's value as a double (float)."
|
||||||
|
return get_field_as_double(self._feat, self._index)
|
||||||
|
|
||||||
|
def as_int(self):
|
||||||
|
"Retrieves the Field's value as an integer."
|
||||||
|
return get_field_as_integer(self._feat, self._index)
|
||||||
|
|
||||||
|
def as_string(self):
|
||||||
|
"Retrieves the Field's value as a string."
|
||||||
|
return get_field_as_string(self._feat, self._index)
|
||||||
|
|
||||||
|
def as_datetime(self):
|
||||||
|
"Retrieves the Field's value as a tuple of date & time components."
|
||||||
|
yy, mm, dd, hh, mn, ss, tz = [c_int() for i in range(7)]
|
||||||
|
status = get_field_as_datetime(self._feat, self._index, byref(yy), byref(mm), byref(dd),
|
||||||
|
byref(hh), byref(mn), byref(ss), byref(tz))
|
||||||
|
if status:
|
||||||
|
return (yy, mm, dd, hh, mn, ss, tz)
|
||||||
|
else:
|
||||||
|
raise OGRException('Unable to retrieve date & time information from the field.')
|
||||||
|
|
||||||
#### Field Properties ####
|
#### Field Properties ####
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"Returns the name of the field."
|
"Returns the name of this Field."
|
||||||
return string_at(lgdal.OGR_Fld_GetNameRef(self._fld))
|
return get_field_name(self._ptr)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def precision(self):
|
||||||
|
"Returns the precision of this Field."
|
||||||
|
return get_field_precision(self._ptr)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
"Returns the type of this field."
|
"Returns the OGR type of this Field."
|
||||||
return lgdal.OGR_Fld_GetType(self._fld)
|
return get_field_type(self._ptr)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type_name(self):
|
||||||
|
"Return the OGR field type name for this Field."
|
||||||
|
return get_field_type_name(self.type)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def value(self):
|
||||||
"Returns the value of this type of field."
|
"Returns the value of this Field."
|
||||||
return self._val
|
# Default is to get the field as a string.
|
||||||
|
return self.as_string()
|
||||||
|
|
||||||
# The Field sub-classes for each OGR Field type.
|
@property
|
||||||
|
def width(self):
|
||||||
|
"Returns the width of this Field."
|
||||||
|
return get_field_width(self._ptr)
|
||||||
|
|
||||||
|
### The Field sub-classes for each OGR Field type. ###
|
||||||
class OFTInteger(Field):
|
class OFTInteger(Field):
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def value(self):
|
||||||
"Returns an integer contained in this field."
|
"Returns an integer contained in this field."
|
||||||
try:
|
return self.as_int()
|
||||||
return int(self._val)
|
|
||||||
except ValueError:
|
@property
|
||||||
return None
|
def type(self):
|
||||||
class OFTIntegerList(Field): pass
|
"""
|
||||||
|
GDAL uses OFTReals to represent OFTIntegers in created
|
||||||
|
shapefiles -- forcing the type here since the underlying field
|
||||||
|
type may actually be OFTReal.
|
||||||
|
"""
|
||||||
|
return 0
|
||||||
|
|
||||||
class OFTReal(Field):
|
class OFTReal(Field):
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def value(self):
|
||||||
"Returns a float contained in this field."
|
"Returns a float contained in this field."
|
||||||
try:
|
return self.as_double()
|
||||||
return float(self._val)
|
|
||||||
except ValueError:
|
|
||||||
return None
|
|
||||||
class OFTRealList(Field): pass
|
|
||||||
|
|
||||||
class OFTString(Field):
|
# String & Binary fields, just subclasses
|
||||||
def __str__(self):
|
class OFTString(Field): pass
|
||||||
return '%s ("%s")' % (self.name, self.value)
|
|
||||||
|
|
||||||
class OFTStringList(Field): pass
|
|
||||||
class OFTWideString(Field): pass
|
class OFTWideString(Field): pass
|
||||||
class OFTWideStringList(Field): pass
|
|
||||||
class OFTBinary(Field): pass
|
class OFTBinary(Field): pass
|
||||||
class OFTDate(Field): pass
|
|
||||||
class OFTTime(Field): pass
|
# OFTDate, OFTTime, OFTDateTime fields.
|
||||||
class OFTDateTime(Field): pass
|
class OFTDate(Field):
|
||||||
|
@property
|
||||||
|
def value(self):
|
||||||
|
"Returns a Python `date` object for the OFTDate field."
|
||||||
|
yy, mm, dd, hh, mn, ss, tz = self.as_datetime()
|
||||||
|
return date(yy.value, mm.value, dd.value)
|
||||||
|
|
||||||
|
class OFTDateTime(Field):
|
||||||
|
@property
|
||||||
|
def value(self):
|
||||||
|
"Returns a Python `datetime` object for this OFTDateTime field."
|
||||||
|
yy, mm, dd, hh, mn, ss, tz = self.as_datetime()
|
||||||
|
# TODO: Adapt timezone information.
|
||||||
|
# See http://lists.maptools.org/pipermail/gdal-dev/2006-February/007990.html
|
||||||
|
# The `tz` variable has values of: 0=unknown, 1=localtime (ambiguous),
|
||||||
|
# 100=GMT, 104=GMT+1, 80=GMT-5, etc.
|
||||||
|
return datetime(yy.value, mm.value, dd.value, hh.value, mn.value, ss.value)
|
||||||
|
|
||||||
|
class OFTTime(Field):
|
||||||
|
@property
|
||||||
|
def value(self):
|
||||||
|
"Returns a Python `time` object for this OFTTime field."
|
||||||
|
yy, mm, dd, hh, mn, ss, tz = self.as_datetime()
|
||||||
|
return time(hh.value, mn.value, ss.value)
|
||||||
|
|
||||||
|
# List fields are also just subclasses
|
||||||
|
class OFTIntegerList(Field): pass
|
||||||
|
class OFTRealList(Field): pass
|
||||||
|
class OFTStringList(Field): pass
|
||||||
|
class OFTWideStringList(Field): pass
|
||||||
|
|
||||||
# Class mapping dictionary for OFT Types
|
# Class mapping dictionary for OFT Types
|
||||||
FIELD_CLASSES = { 0 : OFTInteger,
|
FIELD_CLASSES = { 0 : OFTInteger,
|
||||||
|
@ -38,42 +38,30 @@
|
|||||||
>>> print gt1 == 3, gt1 == 'Polygon' # Equivalence works w/non-OGRGeomType objects
|
>>> print gt1 == 3, gt1 == 'Polygon' # Equivalence works w/non-OGRGeomType objects
|
||||||
True
|
True
|
||||||
"""
|
"""
|
||||||
# Python library imports
|
# Python library requisites.
|
||||||
import re, sys
|
import re, sys
|
||||||
from binascii import a2b_hex, b2a_hex
|
from binascii import a2b_hex
|
||||||
from ctypes import byref, create_string_buffer, string_at, c_char_p, c_double, c_int, 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 BufferType, IntType, StringType, UnicodeType
|
||||||
|
|
||||||
# Getting GDAL prerequisites
|
# Getting GDAL prerequisites
|
||||||
from django.contrib.gis.gdal.libgdal import lgdal
|
|
||||||
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
|
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
|
||||||
from django.contrib.gis.gdal.error import check_err, OGRException, OGRIndexError
|
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException
|
||||||
from django.contrib.gis.gdal.geomtype import OGRGeomType
|
from django.contrib.gis.gdal.geomtype import OGRGeomType
|
||||||
from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform
|
from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform
|
||||||
|
|
||||||
|
# Getting the ctypes prototype functions that interface w/the GDAL C library.
|
||||||
|
from django.contrib.gis.gdal.prototypes.geom import *
|
||||||
|
from django.contrib.gis.gdal.prototypes.srs import clone_srs
|
||||||
|
|
||||||
# For more information, see the OGR C API source code:
|
# For more information, see the OGR C API source code:
|
||||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
# http://www.gdal.org/ogr/ogr__api_8h.html
|
||||||
#
|
#
|
||||||
# The OGR_G_* routines are relevant here.
|
# The OGR_G_* routines are relevant here.
|
||||||
|
|
||||||
#### ctypes prototypes for functions that return double values ####
|
# Regular expressions for recognizing HEXEWKB and WKT.
|
||||||
def pnt_func(f):
|
|
||||||
"For accessing point information."
|
|
||||||
f.restype = c_double
|
|
||||||
f.argtypes = [c_void_p, c_int]
|
|
||||||
return f
|
|
||||||
# GetX, GetY, GetZ all return doubles.
|
|
||||||
getx = pnt_func(lgdal.OGR_G_GetX)
|
|
||||||
gety = pnt_func(lgdal.OGR_G_GetY)
|
|
||||||
getz = pnt_func(lgdal.OGR_G_GetZ)
|
|
||||||
|
|
||||||
# GetArea returns a double.
|
|
||||||
get_area = lgdal.OGR_G_GetArea
|
|
||||||
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)
|
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)
|
||||||
|
|
||||||
#### OGRGeometry Class ####
|
#### OGRGeometry Class ####
|
||||||
class OGRGeometry(object):
|
class OGRGeometry(object):
|
||||||
@ -82,7 +70,7 @@ class OGRGeometry(object):
|
|||||||
def __init__(self, geom_input, srs=None):
|
def __init__(self, geom_input, srs=None):
|
||||||
"Initializes Geometry on either WKT or an OGR pointer as input."
|
"Initializes Geometry on either WKT or an OGR pointer as input."
|
||||||
|
|
||||||
self._g = c_void_p(None) # Initially NULL
|
self._ptr = c_void_p(None) # Initially NULL
|
||||||
|
|
||||||
# Checking if unicode
|
# Checking if unicode
|
||||||
if isinstance(geom_input, UnicodeType):
|
if isinstance(geom_input, UnicodeType):
|
||||||
@ -94,52 +82,47 @@ class OGRGeometry(object):
|
|||||||
geom_input = buffer(a2b_hex(geom_input.upper()))
|
geom_input = buffer(a2b_hex(geom_input.upper()))
|
||||||
|
|
||||||
if isinstance(geom_input, StringType):
|
if isinstance(geom_input, StringType):
|
||||||
# First, trying the input as WKT
|
m = wkt_regex.match(geom_input)
|
||||||
buf = c_char_p(geom_input)
|
if m:
|
||||||
g = c_void_p()
|
if m.group('type').upper() == 'LINEARRING':
|
||||||
|
# OGR_G_CreateFromWkt doesn't work with LINEARRING WKT.
|
||||||
try:
|
# See http://trac.osgeo.org/gdal/ticket/1992.
|
||||||
check_err(lgdal.OGR_G_CreateFromWkt(byref(buf), c_void_p(), byref(g)))
|
g = create_geom(OGRGeomType(m.group('type')).num)
|
||||||
except OGRException:
|
import_wkt(g, byref(c_char_p(geom_input)))
|
||||||
try:
|
else:
|
||||||
|
g = from_wkt(byref(c_char_p(geom_input)), None, byref(c_void_p()))
|
||||||
|
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').
|
||||||
ogr_t = OGRGeomType(geom_input)
|
ogr_t = OGRGeomType(geom_input)
|
||||||
g = lgdal.OGR_G_CreateGeometry(ogr_t.num)
|
g = create_geom(OGRGeomType(geom_input).num)
|
||||||
except:
|
|
||||||
raise OGRException('Could not initialize OGR Geometry from: %s' % geom_input)
|
|
||||||
elif isinstance(geom_input, BufferType):
|
elif isinstance(geom_input, BufferType):
|
||||||
# WKB was passed in
|
# WKB was passed in
|
||||||
g = c_void_p()
|
g = from_wkb(str(geom_input), None, byref(c_void_p()), len(geom_input))
|
||||||
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):
|
elif isinstance(geom_input, OGRGeomType):
|
||||||
# OGRGeomType was passed in, an empty geometry will be created.
|
# OGRGeomType was passed in, an empty geometry will be created.
|
||||||
g = lgdal.OGR_G_CreateGeometry(geom_input.num)
|
g = create_geom(geom_input.num)
|
||||||
elif isinstance(geom_input, c_void_p):
|
elif isinstance(geom_input, c_void_p):
|
||||||
# OGR pointer (c_void_p) was the input.
|
# OGR pointer (c_void_p) was the input.
|
||||||
g = geom_input
|
g = geom_input
|
||||||
else:
|
else:
|
||||||
raise OGRException('Type of input cannot be determined!')
|
raise OGRException('Invalid input type for OGR Geometry construction: %s' % type(geom_input))
|
||||||
|
|
||||||
# Assigning the SpatialReference object to the geometry, if valid.
|
|
||||||
if bool(srs):
|
|
||||||
if isinstance(srs, SpatialReference):
|
|
||||||
srs_ptr = srs._srs
|
|
||||||
else:
|
|
||||||
sr = SpatialReference(srs)
|
|
||||||
srs_ptr = sr._srs
|
|
||||||
lgdal.OGR_G_AssignSpatialReference(g, srs_ptr)
|
|
||||||
|
|
||||||
# Now checking the Geometry pointer before finishing initialization
|
# Now checking the Geometry pointer before finishing initialization
|
||||||
|
# by setting the pointer for the object.
|
||||||
if not g:
|
if not g:
|
||||||
raise OGRException('Cannot create OGR Geometry from input: %s' % str(geom_input))
|
raise OGRException('Cannot create OGR Geometry from input: %s' % str(geom_input))
|
||||||
self._g = g
|
self._ptr = g
|
||||||
|
|
||||||
|
# Assigning the SpatialReference object to the geometry, if valid.
|
||||||
|
if bool(srs): self.srs = srs
|
||||||
|
|
||||||
# Setting the class depending upon the OGR Geometry Type
|
# Setting the class depending upon the OGR Geometry Type
|
||||||
self.__class__ = GEO_CLASSES[self.geom_type.num]
|
self.__class__ = GEO_CLASSES[self.geom_type.num]
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
"Deletes this Geometry."
|
"Deletes this Geometry."
|
||||||
if self._g: lgdal.OGR_G_DestroyGeometry(self._g)
|
if self._ptr: destroy_geom(self._ptr)
|
||||||
|
|
||||||
### Geometry set-like operations ###
|
### Geometry set-like operations ###
|
||||||
# g = g1 | g2
|
# g = g1 | g2
|
||||||
@ -178,71 +161,74 @@ class OGRGeometry(object):
|
|||||||
@property
|
@property
|
||||||
def dimension(self):
|
def dimension(self):
|
||||||
"Returns 0 for points, 1 for lines, and 2 for surfaces."
|
"Returns 0 for points, 1 for lines, and 2 for surfaces."
|
||||||
return lgdal.OGR_G_GetDimension(self._g)
|
return get_dims(self._ptr)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def coord_dim(self):
|
def coord_dim(self):
|
||||||
"Returns the coordinate dimension of the Geometry."
|
"Returns the coordinate dimension of the Geometry."
|
||||||
return lgdal.OGR_G_GetCoordinateDimension(self._g)
|
return get_coord_dims(self._ptr)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def geom_count(self):
|
def geom_count(self):
|
||||||
"The number of elements in this Geometry."
|
"The number of elements in this Geometry."
|
||||||
return lgdal.OGR_G_GetGeometryCount(self._g)
|
return get_geom_count(self._ptr)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def point_count(self):
|
def point_count(self):
|
||||||
"Returns the number of Points in this Geometry."
|
"Returns the number of Points in this Geometry."
|
||||||
return lgdal.OGR_G_GetPointCount(self._g)
|
return get_point_count(self._ptr)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def num_points(self):
|
||||||
|
"Alias for `point_count` (same name method in GEOS API.)"
|
||||||
|
return self.point_count
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def num_coords(self):
|
def num_coords(self):
|
||||||
"Returns the number of Points in this Geometry."
|
"Alais for `point_count`."
|
||||||
return self.point_count
|
return self.point_count
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def geom_type(self):
|
def geom_type(self):
|
||||||
"Returns the Type for this Geometry."
|
"Returns the Type for this Geometry."
|
||||||
return OGRGeomType(lgdal.OGR_G_GetGeometryType(self._g))
|
return OGRGeomType(get_geom_type(self._ptr))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def geom_name(self):
|
def geom_name(self):
|
||||||
"Returns the Name of this Geometry."
|
"Returns the Name of this Geometry."
|
||||||
return string_at(lgdal.OGR_G_GetGeometryName(self._g))
|
return get_geom_name(self._ptr)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def area(self):
|
def area(self):
|
||||||
"Returns the area for a LinearRing, Polygon, or MultiPolygon; 0 otherwise."
|
"Returns the area for a LinearRing, Polygon, or MultiPolygon; 0 otherwise."
|
||||||
return get_area(self._g)
|
return get_area(self._ptr)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def envelope(self):
|
def envelope(self):
|
||||||
"Returns the envelope for this Geometry."
|
"Returns the envelope for this Geometry."
|
||||||
env = OGREnvelope()
|
return Envelope(get_envelope(self._ptr, byref(OGREnvelope())))
|
||||||
lgdal.OGR_G_GetEnvelope(self._g, byref(env))
|
|
||||||
return Envelope(env)
|
|
||||||
|
|
||||||
#### SpatialReference-related Properties ####
|
#### SpatialReference-related Properties ####
|
||||||
|
|
||||||
# The SRS property
|
# The SRS property
|
||||||
def get_srs(self):
|
def get_srs(self):
|
||||||
"Returns the Spatial Reference for this Geometry."
|
"Returns the Spatial Reference for this Geometry."
|
||||||
srs_ptr = lgdal.OGR_G_GetSpatialReference(self._g)
|
try:
|
||||||
if srs_ptr:
|
srs_ptr = get_geom_srs(self._ptr)
|
||||||
return SpatialReference(lgdal.OSRClone(srs_ptr), 'ogr')
|
return SpatialReference(clone_srs(srs_ptr))
|
||||||
else:
|
except SRSException:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def set_srs(self, srs):
|
def set_srs(self, srs):
|
||||||
"Sets the SpatialReference for this geometry."
|
"Sets the SpatialReference for this geometry."
|
||||||
if isinstance(srs, SpatialReference):
|
if isinstance(srs, SpatialReference):
|
||||||
srs_ptr = lgdal.OSRClone(srs._srs)
|
srs_ptr = clone_srs(srs._ptr)
|
||||||
elif isinstance(srs, (StringType, UnicodeType, IntType)):
|
elif isinstance(srs, (StringType, UnicodeType, IntType)):
|
||||||
sr = SpatialReference(srs)
|
sr = SpatialReference(srs)
|
||||||
srs_ptr = lgdal.OSRClone(sr._srs)
|
srs_ptr = clone_srs(sr._ptr)
|
||||||
else:
|
else:
|
||||||
raise TypeError('Cannot assign spatial reference with object of type: %s' % type(srs))
|
raise TypeError('Cannot assign spatial reference with object of type: %s' % type(srs))
|
||||||
lgdal.OGR_G_AssignSpatialReference(self._g, srs_ptr)
|
assign_srs(self._ptr, srs_ptr)
|
||||||
|
|
||||||
srs = property(get_srs, set_srs)
|
srs = property(get_srs, set_srs)
|
||||||
|
|
||||||
@ -260,151 +246,168 @@ class OGRGeometry(object):
|
|||||||
srid = property(get_srid, set_srid)
|
srid = property(get_srid, set_srid)
|
||||||
|
|
||||||
#### Output Methods ####
|
#### Output Methods ####
|
||||||
|
@property
|
||||||
|
def geos(self):
|
||||||
|
"Returns a GEOSGeometry object from this OGRGeometry."
|
||||||
|
from django.contrib.gis.geos import GEOSGeometry
|
||||||
|
return GEOSGeometry(self.wkb, self.srid)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def gml(self):
|
def gml(self):
|
||||||
"Returns the GML representation of the Geometry."
|
"Returns the GML representation of the Geometry."
|
||||||
buf = lgdal.OGR_G_ExportToGML(self._g)
|
return to_gml(self._ptr)
|
||||||
if buf: return string_at(buf)
|
|
||||||
else: return None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hex(self):
|
def hex(self):
|
||||||
"Returns the hexadecimal representation of the WKB (a string)."
|
"Returns the hexadecimal representation of the WKB (a string)."
|
||||||
return b2a_hex(self.wkb).upper()
|
return str(self.wkb).encode('hex').upper()
|
||||||
|
#return b2a_hex(self.wkb).upper()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def wkb_size(self):
|
def wkb_size(self):
|
||||||
"Returns the size of the WKB buffer."
|
"Returns the size of the WKB buffer."
|
||||||
return lgdal.OGR_G_WkbSize(self._g)
|
return get_wkbsize(self._ptr)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def wkb(self):
|
def wkb(self):
|
||||||
"Returns the WKB representation of the Geometry."
|
"Returns the WKB representation of the Geometry."
|
||||||
if sys.byteorder == 'little':
|
if sys.byteorder == 'little':
|
||||||
byteorder = c_int(1) # wkbNDR (from ogr_core.h)
|
byteorder = 1 # wkbNDR (from ogr_core.h)
|
||||||
else:
|
else:
|
||||||
byteorder = c_int(0) # wkbXDR (from ogr_core.h)
|
byteorder = 0 # wkbXDR
|
||||||
# Creating a mutable string buffer of the given size, exporting
|
|
||||||
# to WKB, and returning a Python buffer of the WKB.
|
|
||||||
sz = self.wkb_size
|
sz = self.wkb_size
|
||||||
wkb = create_string_buffer(sz)
|
# Creating the unsigned character buffer, and passing it in by reference.
|
||||||
check_err(lgdal.OGR_G_ExportToWkb(self._g, byteorder, byref(wkb)))
|
buf = (c_ubyte * sz)()
|
||||||
return buffer(string_at(wkb, sz))
|
wkb = to_wkb(self._ptr, byteorder, byref(buf))
|
||||||
|
# Returning a buffer of the string at the pointer.
|
||||||
|
return buffer(string_at(buf, sz))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def wkt(self):
|
def wkt(self):
|
||||||
"Returns the WKT representation of the Geometry."
|
"Returns the WKT representation of the Geometry."
|
||||||
buf = c_char_p()
|
return to_wkt(self._ptr, byref(c_char_p()))
|
||||||
check_err(lgdal.OGR_G_ExportToWkt(self._g, byref(buf)))
|
|
||||||
return string_at(buf)
|
|
||||||
|
|
||||||
#### Geometry Methods ####
|
#### Geometry Methods ####
|
||||||
def clone(self):
|
def clone(self):
|
||||||
"Clones this OGR Geometry."
|
"Clones this OGR Geometry."
|
||||||
return OGRGeometry(c_void_p(lgdal.OGR_G_Clone(self._g)))
|
return OGRGeometry(clone_geom(self._ptr), self.srs)
|
||||||
|
|
||||||
def close_rings(self):
|
def close_rings(self):
|
||||||
"""If there are any rings within this geometry that have not been
|
"""
|
||||||
|
If there are any rings within this geometry that have not been
|
||||||
closed, this routine will do so by adding the starting point at the
|
closed, this routine will do so by adding the starting point at the
|
||||||
end."""
|
end.
|
||||||
|
"""
|
||||||
# Closing the open rings.
|
# Closing the open rings.
|
||||||
lgdal.OGR_G_CloseRings(self._g)
|
geom_close_rings(self._ptr)
|
||||||
|
|
||||||
def transform(self, coord_trans):
|
def transform(self, coord_trans):
|
||||||
"Transforms this Geometry with the given CoordTransform object."
|
"""
|
||||||
if not isinstance(coord_trans, CoordTransform):
|
Transforms this geometry to a different spatial reference system. May take
|
||||||
raise OGRException('CoordTransform object required for transform.')
|
either a CoordTransform object or a SpatialReference object.
|
||||||
check_err(lgdal.OGR_G_Transform(self._g, coord_trans._ct))
|
"""
|
||||||
|
if isinstance(coord_trans, CoordTransform):
|
||||||
|
geom_transform(self._ptr, coord_trans._ptr)
|
||||||
|
elif isinstance(coord_trans, SpatialReference):
|
||||||
|
geom_transform_to(self._ptr, coord_trans._ptr)
|
||||||
|
else:
|
||||||
|
raise TypeError('Either a CoordTransform or a SpatialReference object required for transformation.')
|
||||||
|
|
||||||
def transform_to(self, srs):
|
def transform_to(self, srs):
|
||||||
"Transforms this Geometry with the given SpatialReference."
|
"For backwards-compatibility."
|
||||||
if not isinstance(srs, SpatialReference):
|
self.transform(srs)
|
||||||
raise OGRException('SpatialReference object required for transform_to.')
|
|
||||||
check_err(lgdal.OGR_G_TransformTo(self._g, srs._srs))
|
|
||||||
|
|
||||||
#### Topology Methods ####
|
#### Topology Methods ####
|
||||||
def _topology(self, topo_func, other):
|
def _topology(self, func, other):
|
||||||
"""A generalized function for topology operations, takes a GDAL function and
|
"""A generalized function for topology operations, takes a GDAL function and
|
||||||
the other geometry to perform the operation on."""
|
the other geometry to perform the operation on."""
|
||||||
if not isinstance(other, OGRGeometry):
|
if not isinstance(other, OGRGeometry):
|
||||||
raise OGRException('Must use another OGRGeometry object for topology operations!')
|
raise TypeError('Must use another OGRGeometry object for topology operations!')
|
||||||
|
|
||||||
# Calling the passed-in topology function with the other geometry
|
# Returning the output of the given function with the other geometry's
|
||||||
status = topo_func(self._g, other._g)
|
# pointer.
|
||||||
|
return func(self._ptr, other._ptr)
|
||||||
# Returning based on the status code (an integer)
|
|
||||||
if status: return True
|
|
||||||
else: return False
|
|
||||||
|
|
||||||
def intersects(self, other):
|
def intersects(self, other):
|
||||||
"Returns True if this geometry intersects with the other."
|
"Returns True if this geometry intersects with the other."
|
||||||
return self._topology(lgdal.OGR_G_Intersects, other)
|
return self._topology(ogr_intersects, other)
|
||||||
|
|
||||||
def equals(self, other):
|
def equals(self, other):
|
||||||
"Returns True if this geometry is equivalent to the other."
|
"Returns True if this geometry is equivalent to the other."
|
||||||
return self._topology(lgdal.OGR_G_Equals, other)
|
return self._topology(ogr_equals, other)
|
||||||
|
|
||||||
def disjoint(self, other):
|
def disjoint(self, other):
|
||||||
"Returns True if this geometry and the other are spatially disjoint."
|
"Returns True if this geometry and the other are spatially disjoint."
|
||||||
return self._topology(lgdal.OGR_G_Disjoint, other)
|
return self._topology(ogr_disjoint, other)
|
||||||
|
|
||||||
def touches(self, other):
|
def touches(self, other):
|
||||||
"Returns True if this geometry touches the other."
|
"Returns True if this geometry touches the other."
|
||||||
return self._topology(lgdal.OGR_G_Touches, other)
|
return self._topology(ogr_touches, other)
|
||||||
|
|
||||||
def crosses(self, other):
|
def crosses(self, other):
|
||||||
"Returns True if this geometry crosses the other."
|
"Returns True if this geometry crosses the other."
|
||||||
return self._topology(lgdal.OGR_G_Crosses, other)
|
return self._topology(ogr_crosses, other)
|
||||||
|
|
||||||
def within(self, other):
|
def within(self, other):
|
||||||
"Returns True if this geometry is within the other."
|
"Returns True if this geometry is within the other."
|
||||||
return self._topology(lgdal.OGR_G_Within, other)
|
return self._topology(ogr_within, other)
|
||||||
|
|
||||||
def contains(self, other):
|
def contains(self, other):
|
||||||
"Returns True if this geometry contains the other."
|
"Returns True if this geometry contains the other."
|
||||||
return self._topology(lgdal.OGR_G_Contains, other)
|
return self._topology(ogr_contains, other)
|
||||||
|
|
||||||
def overlaps(self, other):
|
def overlaps(self, other):
|
||||||
"Returns True if this geometry overlaps the other."
|
"Returns True if this geometry overlaps the other."
|
||||||
return self._topology(lgdal.OGR_G_Overlaps, other)
|
return self._topology(ogr_overlaps, other)
|
||||||
|
|
||||||
#### Geometry-generation Methods ####
|
#### Geometry-generation Methods ####
|
||||||
def _geomgen(self, gen_func, other=None):
|
def _geomgen(self, gen_func, other=None):
|
||||||
"A helper routine for the OGR routines that generate geometries."
|
"A helper routine for the OGR routines that generate geometries."
|
||||||
if isinstance(other, OGRGeometry):
|
if isinstance(other, OGRGeometry):
|
||||||
return OGRGeometry(c_void_p(gen_func(self._g, other._g)))
|
return OGRGeometry(gen_func(self._ptr, other._ptr), self.srs)
|
||||||
else:
|
else:
|
||||||
return OGRGeometry(c_void_p(gen_func(self._g)))
|
return OGRGeometry(gen_func(self._ptr), self.srs)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def boundary(self):
|
def boundary(self):
|
||||||
"Returns the boundary of this geometry."
|
"Returns the boundary of this geometry."
|
||||||
return self._geomgen(lgdal.OGR_G_GetBoundary)
|
return self._geomgen(get_boundary)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def convex_hull(self):
|
def convex_hull(self):
|
||||||
"Returns the smallest convex Polygon that contains all the points in the Geometry."
|
"""
|
||||||
return self._geomgen(lgdal.OGR_G_ConvexHull)
|
Returns the smallest convex Polygon that contains all the points in
|
||||||
|
this Geometry.
|
||||||
def union(self, other):
|
"""
|
||||||
"""Returns a new geometry consisting of the region which is the union of
|
return self._geomgen(geom_convex_hull)
|
||||||
this geometry and the other."""
|
|
||||||
return self._geomgen(lgdal.OGR_G_Union, other)
|
|
||||||
|
|
||||||
def difference(self, other):
|
def difference(self, other):
|
||||||
"""Returns a new geometry consisting of the region which is the difference
|
"""
|
||||||
of this geometry and the other."""
|
Returns a new geometry consisting of the region which is the difference
|
||||||
return self._geomgen(lgdal.OGR_G_Difference, other)
|
of this geometry and the other.
|
||||||
|
"""
|
||||||
def sym_difference(self, other):
|
return self._geomgen(geom_diff, other)
|
||||||
"""Returns a new geometry which is the symmetric difference of this
|
|
||||||
geometry and the other."""
|
|
||||||
return self._geomgen(lgdal.OGR_G_SymmetricDifference, other)
|
|
||||||
|
|
||||||
def intersection(self, other):
|
def intersection(self, other):
|
||||||
"""Returns a new geometry consisting of the region of intersection of this
|
"""
|
||||||
geometry and the other."""
|
Returns a new geometry consisting of the region of intersection of this
|
||||||
return self._geomgen(lgdal.OGR_G_Intersection, other)
|
geometry and the other.
|
||||||
|
"""
|
||||||
|
return self._geomgen(geom_intersection, other)
|
||||||
|
|
||||||
|
def sym_difference(self, other):
|
||||||
|
"""
|
||||||
|
Returns a new geometry which is the symmetric difference of this
|
||||||
|
geometry and the other.
|
||||||
|
"""
|
||||||
|
return self._geomgen(geom_sym_diff, other)
|
||||||
|
|
||||||
|
def union(self, other):
|
||||||
|
"""
|
||||||
|
Returns a new geometry consisting of the region which is the union of
|
||||||
|
this geometry and the other.
|
||||||
|
"""
|
||||||
|
return self._geomgen(geom_union, other)
|
||||||
|
|
||||||
# The subclasses for OGR Geometry.
|
# The subclasses for OGR Geometry.
|
||||||
class Point(OGRGeometry):
|
class Point(OGRGeometry):
|
||||||
@ -412,17 +415,17 @@ class Point(OGRGeometry):
|
|||||||
@property
|
@property
|
||||||
def x(self):
|
def x(self):
|
||||||
"Returns the X coordinate for this Point."
|
"Returns the X coordinate for this Point."
|
||||||
return getx(self._g, c_int(0))
|
return getx(self._ptr, 0)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def y(self):
|
def y(self):
|
||||||
"Returns the Y coordinate for this Point."
|
"Returns the Y coordinate for this Point."
|
||||||
return gety(self._g, c_int(0))
|
return gety(self._ptr, 0)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def z(self):
|
def z(self):
|
||||||
"Returns the Z coordinate for this Point."
|
"Returns the Z coordinate for this Point."
|
||||||
return getz(self._g, c_int(0))
|
return getz(self._ptr, 0)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tuple(self):
|
def tuple(self):
|
||||||
@ -436,17 +439,15 @@ class LineString(OGRGeometry):
|
|||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
"Returns the Point at the given index."
|
"Returns the Point at the given index."
|
||||||
if index > 0 or index < self.point_count:
|
if index >= 0 and index < self.point_count:
|
||||||
x = c_double()
|
x, y, z = c_double(), c_double(), c_double()
|
||||||
y = c_double()
|
get_point(self._ptr, index, byref(x), byref(y), byref(z))
|
||||||
z = c_double()
|
dim = self.coord_dim
|
||||||
lgdal.OGR_G_GetPoint(self._g, c_int(index),
|
if dim == 1:
|
||||||
byref(x), byref(y), byref(z))
|
|
||||||
if self.coord_dim == 1:
|
|
||||||
return (x.value,)
|
return (x.value,)
|
||||||
elif self.coord_dim == 2:
|
elif dim == 2:
|
||||||
return (x.value, y.value)
|
return (x.value, y.value)
|
||||||
elif self.coord_dim == 3:
|
elif dim == 3:
|
||||||
return (x.value, y.value, z.value)
|
return (x.value, y.value, z.value)
|
||||||
else:
|
else:
|
||||||
raise OGRIndexError('index out of range: %s' % str(index))
|
raise OGRIndexError('index out of range: %s' % str(index))
|
||||||
@ -454,16 +455,16 @@ class LineString(OGRGeometry):
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
"Iterates over each point in the LineString."
|
"Iterates over each point in the LineString."
|
||||||
for i in xrange(self.point_count):
|
for i in xrange(self.point_count):
|
||||||
yield self.__getitem__(i)
|
yield self[i]
|
||||||
|
|
||||||
def __len__(self, index):
|
def __len__(self):
|
||||||
"The length returns the number of points in the LineString."
|
"The length returns the number of points in the LineString."
|
||||||
return self.point_count
|
return self.point_count
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tuple(self):
|
def tuple(self):
|
||||||
"Returns the tuple representation of this LineString."
|
"Returns the tuple representation of this LineString."
|
||||||
return tuple(self.__getitem__(i) for i in xrange(self.point_count))
|
return tuple(self[i] for i in xrange(len(self)))
|
||||||
|
|
||||||
# LinearRings are used in Polygons.
|
# LinearRings are used in Polygons.
|
||||||
class LinearRing(LineString): pass
|
class LinearRing(LineString): pass
|
||||||
@ -477,38 +478,38 @@ class Polygon(OGRGeometry):
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
"Iterates through each ring in the Polygon."
|
"Iterates through each ring in the Polygon."
|
||||||
for i in xrange(self.geom_count):
|
for i in xrange(self.geom_count):
|
||||||
yield self.__getitem__(i)
|
yield self[i]
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
"Gets the ring at the specified index."
|
"Gets the ring at the specified index."
|
||||||
if index < 0 or index >= self.geom_count:
|
if index < 0 or index >= self.geom_count:
|
||||||
raise OGRIndexError('index out of range: %s' % str(index))
|
raise OGRIndexError('index out of range: %s' % index)
|
||||||
else:
|
else:
|
||||||
return OGRGeometry(c_void_p(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index)))), self.srs)
|
return OGRGeometry(clone_geom(get_geom_ref(self._ptr, index)), self.srs)
|
||||||
|
|
||||||
# Polygon Properties
|
# Polygon Properties
|
||||||
@property
|
@property
|
||||||
def shell(self):
|
def shell(self):
|
||||||
"Returns the shell of this Polygon."
|
"Returns the shell of this Polygon."
|
||||||
return self.__getitem__(0) # First ring is the shell
|
return self[0] # First ring is the shell
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tuple(self):
|
def tuple(self):
|
||||||
"Returns a tuple of LinearRing coordinate tuples."
|
"Returns a tuple of LinearRing coordinate tuples."
|
||||||
return tuple(self.__getitem__(i).tuple for i in xrange(self.geom_count))
|
return tuple(self[i].tuple for i in xrange(self.geom_count))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def point_count(self):
|
def point_count(self):
|
||||||
"The number of Points in this Polygon."
|
"The number of Points in this Polygon."
|
||||||
# Summing up the number of points in each ring of the Polygon.
|
# Summing up the number of points in each ring of the Polygon.
|
||||||
return sum([self.__getitem__(i).point_count for i in xrange(self.geom_count)])
|
return sum([self[i].point_count for i in xrange(self.geom_count)])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def centroid(self):
|
def centroid(self):
|
||||||
"Returns the centroid (a Point) of this Polygon."
|
"Returns the centroid (a Point) of this Polygon."
|
||||||
# The centroid is a Point, create a geometry for this.
|
# The centroid is a Point, create a geometry for this.
|
||||||
p = OGRGeometry(OGRGeomType('Point'))
|
p = OGRGeometry(OGRGeomType('Point'))
|
||||||
check_err(lgdal.OGR_G_Centroid(self._g, p._g))
|
get_centroid(self._ptr, p._ptr)
|
||||||
return p
|
return p
|
||||||
|
|
||||||
# Geometry Collection base class.
|
# Geometry Collection base class.
|
||||||
@ -518,14 +519,14 @@ class GeometryCollection(OGRGeometry):
|
|||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
"Gets the Geometry at the specified index."
|
"Gets the Geometry at the specified index."
|
||||||
if index < 0 or index >= self.geom_count:
|
if index < 0 or index >= self.geom_count:
|
||||||
raise OGRIndexError('index out of range: %s' % str(index))
|
raise OGRIndexError('index out of range: %s' % index)
|
||||||
else:
|
else:
|
||||||
return OGRGeometry(c_void_p(lgdal.OGR_G_Clone(lgdal.OGR_G_GetGeometryRef(self._g, c_int(index)))), self.srs)
|
return OGRGeometry(clone_geom(get_geom_ref(self._ptr, index)), self.srs)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
"Iterates over each Geometry."
|
"Iterates over each Geometry."
|
||||||
for i in xrange(self.geom_count):
|
for i in xrange(self.geom_count):
|
||||||
yield self.__getitem__(i)
|
yield self[i]
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
"The number of geometries in this Geometry Collection."
|
"The number of geometries in this Geometry Collection."
|
||||||
@ -534,24 +535,24 @@ class GeometryCollection(OGRGeometry):
|
|||||||
def add(self, geom):
|
def add(self, geom):
|
||||||
"Add the geometry to this Geometry Collection."
|
"Add the geometry to this Geometry Collection."
|
||||||
if isinstance(geom, OGRGeometry):
|
if isinstance(geom, OGRGeometry):
|
||||||
ptr = geom._g
|
ptr = geom._ptr
|
||||||
elif isinstance(geom, (StringType, UnicodeType)):
|
elif isinstance(geom, (StringType, UnicodeType)):
|
||||||
tmp = OGRGeometry(geom)
|
tmp = OGRGeometry(geom)
|
||||||
ptr = tmp._g
|
ptr = tmp._ptr
|
||||||
else:
|
else:
|
||||||
raise OGRException('Must add an OGRGeometry.')
|
raise OGRException('Must add an OGRGeometry.')
|
||||||
lgdal.OGR_G_AddGeometry(self._g, ptr)
|
add_geom(self._ptr, ptr)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def point_count(self):
|
def point_count(self):
|
||||||
"The number of Points in this Geometry Collection."
|
"The number of Points in this Geometry Collection."
|
||||||
# Summing up the number of points in each geometry in this collection
|
# Summing up the number of points in each geometry in this collection
|
||||||
return sum([self.__getitem__(i).point_count for i in xrange(self.geom_count)])
|
return sum([self[i].point_count for i in xrange(self.geom_count)])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tuple(self):
|
def tuple(self):
|
||||||
"Returns a tuple representation of this Geometry Collection."
|
"Returns a tuple representation of this Geometry Collection."
|
||||||
return tuple(self.__getitem__(i).tuple for i in xrange(self.geom_count))
|
return tuple(self[i].tuple for i in xrange(self.geom_count))
|
||||||
|
|
||||||
# Multiple Geometry types.
|
# Multiple Geometry types.
|
||||||
class MultiPoint(GeometryCollection): pass
|
class MultiPoint(GeometryCollection): pass
|
||||||
@ -566,4 +567,5 @@ GEO_CLASSES = {1 : Point,
|
|||||||
5 : MultiLineString,
|
5 : MultiLineString,
|
||||||
6 : MultiPolygon,
|
6 : MultiPolygon,
|
||||||
7 : GeometryCollection,
|
7 : GeometryCollection,
|
||||||
|
101: LinearRing,
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
from types import StringType
|
|
||||||
from django.contrib.gis.gdal.error import OGRException
|
from django.contrib.gis.gdal.error import OGRException
|
||||||
|
|
||||||
#### OGRGeomType ####
|
#### OGRGeomType ####
|
||||||
@ -15,7 +14,7 @@ class OGRGeomType(object):
|
|||||||
"Figures out the correct OGR Type based upon the input."
|
"Figures out the correct OGR Type based upon the input."
|
||||||
if isinstance(type_input, OGRGeomType):
|
if isinstance(type_input, OGRGeomType):
|
||||||
self._index = type_input._index
|
self._index = type_input._index
|
||||||
elif isinstance(type_input, StringType):
|
elif isinstance(type_input, basestring):
|
||||||
idx = self._has_str(self.__ogr_str, type_input)
|
idx = self._has_str(self.__ogr_str, type_input)
|
||||||
if idx == None:
|
if idx == None:
|
||||||
raise OGRException('Invalid OGR String Type "%s"' % type_input)
|
raise OGRException('Invalid OGR String Type "%s"' % type_input)
|
||||||
@ -25,18 +24,20 @@ class OGRGeomType(object):
|
|||||||
raise OGRException('Invalid OGR Integer Type: %d' % type_input)
|
raise OGRException('Invalid OGR Integer Type: %d' % type_input)
|
||||||
self._index = self.__ogr_int.index(type_input)
|
self._index = self.__ogr_int.index(type_input)
|
||||||
else:
|
else:
|
||||||
raise TypeError('Invalid OGR Input type given!')
|
raise TypeError('Invalid OGR input type given.')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"Returns a short-hand string form of the OGR Geometry type."
|
"Returns a short-hand string form of the OGR Geometry type."
|
||||||
return self.__ogr_str[self._index]
|
return self.__ogr_str[self._index]
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
"""Does an equivalence test on the OGR type with the given
|
"""
|
||||||
other OGRGeomType, the short-hand string, or the integer."""
|
Does an equivalence test on the OGR type with the given
|
||||||
|
other OGRGeomType, the short-hand string, or the integer.
|
||||||
|
"""
|
||||||
if isinstance(other, OGRGeomType):
|
if isinstance(other, OGRGeomType):
|
||||||
return self._index == other._index
|
return self._index == other._index
|
||||||
elif isinstance(other, StringType):
|
elif isinstance(other, basestring):
|
||||||
idx = self._has_str(self.__ogr_str, other)
|
idx = self._has_str(self.__ogr_str, other)
|
||||||
if not (idx == None): return self._index == idx
|
if not (idx == None): return self._index == idx
|
||||||
return False
|
return False
|
||||||
|
@ -1,38 +1,36 @@
|
|||||||
# Needed ctypes routines
|
# Needed ctypes routines
|
||||||
from ctypes import c_int, c_long, c_void_p, byref, string_at
|
from ctypes import byref
|
||||||
|
|
||||||
# The GDAL C Library
|
|
||||||
from django.contrib.gis.gdal.libgdal import lgdal
|
|
||||||
|
|
||||||
# Other GDAL imports.
|
# Other GDAL imports.
|
||||||
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
|
from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
|
||||||
|
from django.contrib.gis.gdal.error import OGRException, OGRIndexError
|
||||||
from django.contrib.gis.gdal.feature import Feature
|
from django.contrib.gis.gdal.feature import Feature
|
||||||
from django.contrib.gis.gdal.geometries import OGRGeomType
|
from django.contrib.gis.gdal.geometries import OGRGeomType
|
||||||
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, check_err
|
|
||||||
from django.contrib.gis.gdal.srs import SpatialReference
|
from django.contrib.gis.gdal.srs import SpatialReference
|
||||||
|
|
||||||
|
# GDAL ctypes function prototypes.
|
||||||
|
from django.contrib.gis.gdal.prototypes.ds import \
|
||||||
|
get_extent, get_fd_geom_type, get_fd_name, get_feature, get_feature_count, \
|
||||||
|
get_field_count, get_field_defn, get_field_name, get_field_precision, \
|
||||||
|
get_field_width, get_layer_defn, get_layer_srs, get_next_feature, \
|
||||||
|
reset_reading
|
||||||
|
from django.contrib.gis.gdal.prototypes.srs import clone_srs
|
||||||
|
|
||||||
# For more information, see the OGR C API source code:
|
# For more information, see the OGR C API source code:
|
||||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
# http://www.gdal.org/ogr/ogr__api_8h.html
|
||||||
#
|
#
|
||||||
# The OGR_L_* routines are relevant here.
|
# The OGR_L_* routines are relevant here.
|
||||||
|
|
||||||
# function prototype for obtaining the spatial reference system
|
|
||||||
get_srs = lgdal.OGR_L_GetSpatialRef
|
|
||||||
get_srs.restype = c_void_p
|
|
||||||
get_srs.argtypes = [c_void_p]
|
|
||||||
|
|
||||||
class Layer(object):
|
class Layer(object):
|
||||||
"A class that wraps an OGR Layer, needs to be instantiated from a DataSource object."
|
"A class that wraps an OGR Layer, needs to be instantiated from a DataSource object."
|
||||||
|
|
||||||
#### Python 'magic' routines ####
|
#### Python 'magic' routines ####
|
||||||
def __init__(self, l):
|
def __init__(self, layer_ptr):
|
||||||
"Needs a C pointer (Python/ctypes integer) in order to initialize."
|
"Needs a C pointer (Python/ctypes integer) in order to initialize."
|
||||||
self._layer = None # Initially NULL
|
self._ptr = None # Initially NULL
|
||||||
self._ldefn = None
|
if not layer_ptr:
|
||||||
if not l:
|
raise OGRException('Cannot create Layer, invalid pointer given')
|
||||||
raise OGRException, 'Cannot create Layer, invalid pointer given'
|
self._ptr = layer_ptr
|
||||||
self._layer = l
|
self._ldefn = get_layer_defn(self._ptr)
|
||||||
self._ldefn = lgdal.OGR_L_GetLayerDefn(l)
|
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
"Gets the Feature at the specified index."
|
"Gets the Feature at the specified index."
|
||||||
@ -44,7 +42,7 @@ class Layer(object):
|
|||||||
if index < 0:
|
if index < 0:
|
||||||
index = end - index
|
index = end - index
|
||||||
if index < 0 or index >= self.num_feat:
|
if index < 0 or index >= self.num_feat:
|
||||||
raise OGRIndexError, 'index out of range'
|
raise OGRIndexError('index out of range')
|
||||||
return self._make_feature(index)
|
return self._make_feature(index)
|
||||||
else:
|
else:
|
||||||
# A slice was given
|
# A slice was given
|
||||||
@ -54,9 +52,9 @@ class Layer(object):
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
"Iterates over each Feature in the Layer."
|
"Iterates over each Feature in the Layer."
|
||||||
# ResetReading() must be called before iteration is to begin.
|
# ResetReading() must be called before iteration is to begin.
|
||||||
lgdal.OGR_L_ResetReading(self._layer)
|
reset_reading(self._ptr)
|
||||||
for i in range(self.num_feat):
|
for i in range(self.num_feat):
|
||||||
yield Feature(lgdal.OGR_L_GetNextFeature(self._layer), self._ldefn)
|
yield Feature(get_next_feature(self._ptr), self._ldefn)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
"The length is the number of features."
|
"The length is the number of features."
|
||||||
@ -68,76 +66,80 @@ class Layer(object):
|
|||||||
|
|
||||||
def _make_feature(self, offset):
|
def _make_feature(self, offset):
|
||||||
"Helper routine for __getitem__ that makes a feature from an offset."
|
"Helper routine for __getitem__ that makes a feature from an offset."
|
||||||
return Feature(lgdal.OGR_L_GetFeature(self._layer, c_long(offset)), self._ldefn)
|
return Feature(get_feature(self._ptr, offset), self._ldefn)
|
||||||
|
|
||||||
#### Layer properties ####
|
#### Layer properties ####
|
||||||
@property
|
@property
|
||||||
def extent(self):
|
def extent(self):
|
||||||
"Returns the extent (an Envelope) of this layer."
|
"Returns the extent (an Envelope) of this layer."
|
||||||
env = OGREnvelope()
|
env = OGREnvelope()
|
||||||
check_err(lgdal.OGR_L_GetExtent(self._layer, byref(env), c_int(1)))
|
get_extent(self._ptr, byref(env), 1)
|
||||||
return Envelope(env)
|
return Envelope(env)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"Returns the name of this layer in the Data Source."
|
"Returns the name of this layer in the Data Source."
|
||||||
return string_at(lgdal.OGR_FD_GetName(self._ldefn))
|
return get_fd_name(self._ldefn)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def num_feat(self, force=1):
|
def num_feat(self, force=1):
|
||||||
"Returns the number of features in the Layer."
|
"Returns the number of features in the Layer."
|
||||||
return lgdal.OGR_L_GetFeatureCount(self._layer, c_int(force))
|
return get_feature_count(self._ptr, force)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def num_fields(self):
|
def num_fields(self):
|
||||||
"Returns the number of fields in the Layer."
|
"Returns the number of fields in the Layer."
|
||||||
return lgdal.OGR_FD_GetFieldCount(self._ldefn)
|
return get_field_count(self._ldefn)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def geom_type(self):
|
def geom_type(self):
|
||||||
"Returns the geometry type (OGRGeomType) of the Layer."
|
"Returns the geometry type (OGRGeomType) of the Layer."
|
||||||
return OGRGeomType(lgdal.OGR_FD_GetGeomType(self._ldefn))
|
return OGRGeomType(get_fd_geom_type(self._ldefn))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def srs(self):
|
def srs(self):
|
||||||
"Returns the Spatial Reference used in this Layer."
|
"Returns the Spatial Reference used in this Layer."
|
||||||
ptr = lgdal.OGR_L_GetSpatialRef(self._layer)
|
ptr = get_layer_srs(self._ptr)
|
||||||
if ptr:
|
if ptr:
|
||||||
return SpatialReference(lgdal.OSRClone(ptr), 'ogr')
|
return SpatialReference(clone_srs(ptr))
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fields(self):
|
def fields(self):
|
||||||
"Returns a list of the fields available in this Layer."
|
"Returns a list of the fields available in this Layer."
|
||||||
return [ string_at(lgdal.OGR_Fld_GetNameRef(lgdal.OGR_FD_GetFieldDefn(self._ldefn, i)))
|
return [get_field_name(get_field_defn(self._ldefn, i))
|
||||||
for i in xrange(self.num_fields) ]
|
for i in xrange(self.num_fields) ]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def field_widths(self):
|
def field_widths(self):
|
||||||
"Returns a list of the maximum field widths for the features."
|
"Returns a list of the maximum field widths for the features."
|
||||||
return [ int(lgdal.OGR_Fld_GetWidth(lgdal.OGR_FD_GetFieldDefn(self._ldefn, i)))
|
return [get_field_width(get_field_defn(self._ldefn, i))
|
||||||
for i in xrange(self.num_fields)]
|
for i in xrange(self.num_fields)]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def field_precisions(self):
|
def field_precisions(self):
|
||||||
"Returns the field precisions for the features."
|
"Returns the field precisions for the features."
|
||||||
return [ int(lgdal.OGR_Fld_GetPrecision(lgdal.OGR_FD_GetFieldDefn(self._ldefn, i)))
|
return [get_field_precision(get_field_defn(self._ldefn, i))
|
||||||
for i in xrange(self.num_fields)]
|
for i in xrange(self.num_fields)]
|
||||||
|
|
||||||
#### Layer Methods ####
|
#### Layer Methods ####
|
||||||
def get_fields(self, field_name):
|
def get_fields(self, field_name):
|
||||||
"""Returns a list containing the given field name for every Feature
|
"""
|
||||||
in the Layer."""
|
Returns a list containing the given field name for every Feature
|
||||||
|
in the Layer.
|
||||||
|
"""
|
||||||
if not field_name in self.fields:
|
if not field_name in self.fields:
|
||||||
raise OGRException, 'invalid field name: %s' % field_name
|
raise OGRException('invalid field name: %s' % field_name)
|
||||||
return [feat.get(field_name) for feat in self]
|
return [feat.get(field_name) for feat in self]
|
||||||
|
|
||||||
def get_geoms(self, geos=False):
|
def get_geoms(self, geos=False):
|
||||||
"""Returns a list containing the OGRGeometry for every Feature in
|
"""
|
||||||
the Layer."""
|
Returns a list containing the OGRGeometry for every Feature in
|
||||||
|
the Layer.
|
||||||
|
"""
|
||||||
if geos:
|
if geos:
|
||||||
from django.contrib.gis.geos import fromstr
|
from django.contrib.gis.geos import GEOSGeometry
|
||||||
return [fromstr(feat.geom.wkt) for feat in self]
|
return [GEOSGeometry(feat.geom.wkb) for feat in self]
|
||||||
else:
|
else:
|
||||||
return [feat.geom for feat in self]
|
return [feat.geom for feat in self]
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import os, sys
|
import os, sys
|
||||||
from ctypes import CDLL, string_at
|
from ctypes import CDLL, string_at
|
||||||
|
from ctypes.util import find_library
|
||||||
from django.contrib.gis.gdal.error import OGRException
|
from django.contrib.gis.gdal.error import OGRException
|
||||||
|
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
@ -7,16 +8,14 @@ if os.name == 'nt':
|
|||||||
lib_name = 'libgdal-1.dll'
|
lib_name = 'libgdal-1.dll'
|
||||||
elif os.name == 'posix':
|
elif os.name == 'posix':
|
||||||
platform = os.uname()[0]
|
platform = os.uname()[0]
|
||||||
if platform in ('Linux', 'SunOS'):
|
if platform == 'Darwin':
|
||||||
# Linux or Solaris shared library
|
|
||||||
lib_name = 'libgdal.so'
|
|
||||||
elif platform == 'Darwin':
|
|
||||||
# Mac OSX shared library
|
# Mac OSX shared library
|
||||||
lib_name = 'libgdal.dylib'
|
lib_name = 'libgdal.dylib'
|
||||||
else:
|
else:
|
||||||
raise OGRException, 'Unknown POSIX platform "%s"' % platform
|
# Attempting to use .so extension for all other platforms.
|
||||||
|
lib_name = 'libgdal.so'
|
||||||
else:
|
else:
|
||||||
raise OGRException, 'Unsupported OS "%s"' % os.name
|
raise OGRException('Unsupported OS "%s"' % os.name)
|
||||||
|
|
||||||
# This loads the GDAL/OGR C library
|
# This loads the GDAL/OGR C library
|
||||||
lgdal = CDLL(lib_name)
|
lgdal = CDLL(lib_name)
|
||||||
|
16
django/contrib/gis/gdal/prototypes/__init__.py
Normal file
16
django/contrib/gis/gdal/prototypes/__init__.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
This routine provides shortuct functions to generate ctypes prototypes
|
||||||
|
for the GDAL routines.
|
||||||
|
"""
|
||||||
|
# OGR Geometry prototypes.
|
||||||
|
from django.contrib.gis.gdal.prototypes.geom import \
|
||||||
|
assign_srs, clone_geom, create_geom, destroy_geom, from_wkb, from_wkt, \
|
||||||
|
get_area, get_coord_dims, get_dims, get_envelope, get_geom_count, get_geom_name, get_geom_srs, get_geom_type, get_point_count, get_wkbsize, \
|
||||||
|
getx, get_geom_ref, gety, getz, to_gml, to_wkt
|
||||||
|
|
||||||
|
# Spatial Reference prototypes.
|
||||||
|
from django.contrib.gis.gdal.prototypes.srs import \
|
||||||
|
clone_srs
|
||||||
|
|
||||||
|
# TEMPORARY
|
||||||
|
from generation import double_output, string_output, void_output
|
67
django/contrib/gis/gdal/prototypes/ds.py
Normal file
67
django/contrib/gis/gdal/prototypes/ds.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
"""
|
||||||
|
This module houses the ctypes function prototypes for OGR DataSource
|
||||||
|
related data structures. OGR_Dr_*, OGR_DS_*, OGR_L_*, OGR_F_*,
|
||||||
|
OGR_Fld_* routines are relevant here.
|
||||||
|
"""
|
||||||
|
from ctypes import c_char_p, c_int, c_long, 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.prototypes.generation import \
|
||||||
|
const_string_output, double_output, geom_output, int_output, \
|
||||||
|
srs_output, void_output, voidptr_output
|
||||||
|
|
||||||
|
c_int_p = POINTER(c_int) # shortcut type
|
||||||
|
|
||||||
|
### Driver Routines ###
|
||||||
|
register_all = void_output(lgdal.OGRRegisterAll, [], errcheck=False)
|
||||||
|
cleanup_all = void_output(lgdal.OGRCleanupAll, [], errcheck=False)
|
||||||
|
get_driver = voidptr_output(lgdal.OGRGetDriver, [c_int])
|
||||||
|
get_driver_by_name = voidptr_output(lgdal.OGRGetDriverByName, [c_char_p])
|
||||||
|
get_driver_count = int_output(lgdal.OGRGetDriverCount, [])
|
||||||
|
get_driver_name = const_string_output(lgdal.OGR_Dr_GetName, [c_void_p])
|
||||||
|
|
||||||
|
### DataSource ###
|
||||||
|
open_ds = voidptr_output(lgdal.OGROpen, [c_char_p, c_int, POINTER(c_void_p)])
|
||||||
|
destroy_ds = void_output(lgdal.OGR_DS_Destroy, [c_void_p], errcheck=False)
|
||||||
|
release_ds = void_output(lgdal.OGRReleaseDataSource, [c_void_p])
|
||||||
|
get_ds_name = const_string_output(lgdal.OGR_DS_GetName, [c_void_p])
|
||||||
|
get_layer = voidptr_output(lgdal.OGR_DS_GetLayer, [c_void_p, c_int])
|
||||||
|
get_layer_by_name = voidptr_output(lgdal.OGR_DS_GetLayerByName, [c_void_p, c_char_p])
|
||||||
|
get_layer_count = int_output(lgdal.OGR_DS_GetLayerCount, [c_void_p])
|
||||||
|
|
||||||
|
### Layer Routines ###
|
||||||
|
get_extent = void_output(lgdal.OGR_L_GetExtent, [c_void_p, POINTER(OGREnvelope), c_int])
|
||||||
|
get_feature = voidptr_output(lgdal.OGR_L_GetFeature, [c_void_p, c_long])
|
||||||
|
get_feature_count = int_output(lgdal.OGR_L_GetFeatureCount, [c_void_p, c_int])
|
||||||
|
get_layer_defn = voidptr_output(lgdal.OGR_L_GetLayerDefn, [c_void_p])
|
||||||
|
get_layer_srs = srs_output(lgdal.OGR_L_GetSpatialRef, [c_void_p])
|
||||||
|
get_next_feature = voidptr_output(lgdal.OGR_L_GetNextFeature, [c_void_p])
|
||||||
|
reset_reading = void_output(lgdal.OGR_L_ResetReading, [c_void_p], errcheck=False)
|
||||||
|
|
||||||
|
### Feature Definition Routines ###
|
||||||
|
get_fd_geom_type = int_output(lgdal.OGR_FD_GetGeomType, [c_void_p])
|
||||||
|
get_fd_name = const_string_output(lgdal.OGR_FD_GetName, [c_void_p])
|
||||||
|
get_feat_name = const_string_output(lgdal.OGR_FD_GetName, [c_void_p])
|
||||||
|
get_field_count = int_output(lgdal.OGR_FD_GetFieldCount, [c_void_p])
|
||||||
|
get_field_defn = voidptr_output(lgdal.OGR_FD_GetFieldDefn, [c_void_p, c_int])
|
||||||
|
|
||||||
|
### Feature Routines ###
|
||||||
|
clone_feature = voidptr_output(lgdal.OGR_F_Clone, [c_void_p])
|
||||||
|
destroy_feature = void_output(lgdal.OGR_F_Destroy, [c_void_p])
|
||||||
|
feature_equal = int_output(lgdal.OGR_F_Equal, [c_void_p, c_void_p])
|
||||||
|
get_feat_geom_ref = geom_output(lgdal.OGR_F_GetGeometryRef, [c_void_p])
|
||||||
|
get_feat_field_count = int_output(lgdal.OGR_F_GetFieldCount, [c_void_p])
|
||||||
|
get_feat_field_defn = voidptr_output(lgdal.OGR_F_GetFieldDefnRef, [c_void_p, c_int])
|
||||||
|
get_fid = int_output(lgdal.OGR_F_GetFID, [c_void_p])
|
||||||
|
get_field_as_datetime = int_output(lgdal.OGR_F_GetFieldAsDateTime, [c_void_p, c_int, c_int_p, c_int_p, c_int_p, c_int_p, c_int_p, c_int_p])
|
||||||
|
get_field_as_double = double_output(lgdal.OGR_F_GetFieldAsDouble, [c_void_p, c_int])
|
||||||
|
get_field_as_integer = int_output(lgdal.OGR_F_GetFieldAsInteger, [c_void_p, c_int])
|
||||||
|
get_field_as_string = const_string_output(lgdal.OGR_F_GetFieldAsString, [c_void_p, c_int])
|
||||||
|
get_field_index = int_output(lgdal.OGR_F_GetFieldIndex, [c_void_p, c_char_p])
|
||||||
|
|
||||||
|
### Field Routines ###
|
||||||
|
get_field_name = const_string_output(lgdal.OGR_Fld_GetNameRef, [c_void_p])
|
||||||
|
get_field_precision = int_output(lgdal.OGR_Fld_GetPrecision, [c_void_p])
|
||||||
|
get_field_type = int_output(lgdal.OGR_Fld_GetType, [c_void_p])
|
||||||
|
get_field_type_name = const_string_output(lgdal.OGR_GetFieldTypeName, [c_int])
|
||||||
|
get_field_width = int_output(lgdal.OGR_Fld_GetWidth, [c_void_p])
|
125
django/contrib/gis/gdal/prototypes/errcheck.py
Normal file
125
django/contrib/gis/gdal/prototypes/errcheck.py
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
"""
|
||||||
|
This module houses the error-checking routines used by the GDAL
|
||||||
|
ctypes prototypes.
|
||||||
|
"""
|
||||||
|
from ctypes import c_void_p, string_at
|
||||||
|
from django.contrib.gis.gdal.error import check_err, OGRException, SRSException
|
||||||
|
from django.contrib.gis.gdal.libgdal import lgdal
|
||||||
|
|
||||||
|
# Helper routines for retrieving pointers and/or values from
|
||||||
|
# arguments passed in by reference.
|
||||||
|
def arg_byref(args, offset=-1):
|
||||||
|
"Returns the pointer argument's by-refernece value."
|
||||||
|
return args[offset]._obj.value
|
||||||
|
|
||||||
|
def ptr_byref(args, offset=-1):
|
||||||
|
"Returns the pointer argument passed in by-reference."
|
||||||
|
return args[offset]._obj
|
||||||
|
|
||||||
|
def check_bool(result, func, cargs):
|
||||||
|
"Returns the boolean evaluation of the value."
|
||||||
|
if bool(result): return True
|
||||||
|
else: return False
|
||||||
|
|
||||||
|
### String checking Routines ###
|
||||||
|
def check_const_string(result, func, cargs, offset=None):
|
||||||
|
"""
|
||||||
|
Similar functionality to `check_string`, but does not free the pointer.
|
||||||
|
"""
|
||||||
|
if offset:
|
||||||
|
check_err(result)
|
||||||
|
ptr = ptr_byref(cargs, offset)
|
||||||
|
return ptr.value
|
||||||
|
else:
|
||||||
|
return result
|
||||||
|
|
||||||
|
def check_string(result, func, cargs, offset=-1, str_result=False):
|
||||||
|
"""
|
||||||
|
Checks the string output returned from the given function, and frees
|
||||||
|
the string pointer allocated by OGR. The `str_result` keyword
|
||||||
|
may be used when the result is the string pointer, otherwise
|
||||||
|
the OGR error code is assumed. The `offset` keyword may be used
|
||||||
|
to extract the string pointer passed in by-reference at the given
|
||||||
|
slice offset in the function arguments.
|
||||||
|
"""
|
||||||
|
if str_result:
|
||||||
|
# For routines that return a string.
|
||||||
|
ptr = result
|
||||||
|
if not ptr: s = None
|
||||||
|
else: s = string_at(result)
|
||||||
|
else:
|
||||||
|
# Error-code return specified.
|
||||||
|
check_err(result)
|
||||||
|
ptr = ptr_byref(cargs, offset)
|
||||||
|
# Getting the string value
|
||||||
|
s = ptr.value
|
||||||
|
# Correctly freeing the allocated memory beind GDAL pointer
|
||||||
|
# w/the VSIFree routine.
|
||||||
|
if ptr: lgdal.VSIFree(ptr)
|
||||||
|
return s
|
||||||
|
|
||||||
|
### DataSource, Layer error-checking ###
|
||||||
|
|
||||||
|
### Envelope checking ###
|
||||||
|
def check_envelope(result, func, cargs, offset=-1):
|
||||||
|
"Checks a function that returns an OGR Envelope by reference."
|
||||||
|
env = ptr_byref(cargs, offset)
|
||||||
|
return env
|
||||||
|
|
||||||
|
### Geometry error-checking routines ###
|
||||||
|
def check_geom(result, func, cargs):
|
||||||
|
"Checks a function that returns a geometry."
|
||||||
|
# OGR_G_Clone may return an integer, even though the
|
||||||
|
# restype is set to c_void_p
|
||||||
|
if isinstance(result, int):
|
||||||
|
result = c_void_p(result)
|
||||||
|
if not result:
|
||||||
|
raise OGRException('Invalid geometry pointer returned from "%s".' % func.__name__)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def check_geom_offset(result, func, cargs, offset=-1):
|
||||||
|
"Chcks the geometry at the given offset in the C parameter list."
|
||||||
|
check_err(result)
|
||||||
|
geom = ptr_byref(cargs, offset=offset)
|
||||||
|
return check_geom(geom, func, cargs)
|
||||||
|
|
||||||
|
### Spatial Reference error-checking routines ###
|
||||||
|
def check_srs(result, func, cargs):
|
||||||
|
if isinstance(result, int):
|
||||||
|
result = c_void_p(result)
|
||||||
|
if not result:
|
||||||
|
raise SRSException('Invalid spatial reference pointer returned from "%s".' % func.__name__)
|
||||||
|
return result
|
||||||
|
|
||||||
|
### Other error-checking routines ###
|
||||||
|
def check_arg_errcode(result, func, cargs):
|
||||||
|
"""
|
||||||
|
The error code is returned in the last argument, by reference.
|
||||||
|
Check its value with `check_err` before returning the result.
|
||||||
|
"""
|
||||||
|
check_err(arg_byref(cargs))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def check_errcode(result, func, cargs):
|
||||||
|
"""
|
||||||
|
Check the error code returned (c_int).
|
||||||
|
"""
|
||||||
|
check_err(result)
|
||||||
|
return
|
||||||
|
|
||||||
|
def check_pointer(result, func, cargs):
|
||||||
|
"Makes sure the result pointer is valid."
|
||||||
|
if bool(result):
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
raise OGRException('Invalid pointer returned from "%s"' % func.__name__)
|
||||||
|
|
||||||
|
def check_str_arg(result, func, cargs):
|
||||||
|
"""
|
||||||
|
This is for the OSRGet[Angular|Linear]Units functions, which
|
||||||
|
require that the returned string pointer not be freed. This
|
||||||
|
returns both the double and tring values.
|
||||||
|
"""
|
||||||
|
dbl = result
|
||||||
|
ptr = cargs[-1]._obj
|
||||||
|
return dbl, ptr.value
|
113
django/contrib/gis/gdal/prototypes/generation.py
Normal file
113
django/contrib/gis/gdal/prototypes/generation.py
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
"""
|
||||||
|
This module contains functions that generate ctypes prototypes for the
|
||||||
|
GDAL routines.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ctypes import c_char_p, c_double, c_int, c_void_p
|
||||||
|
from django.contrib.gis.gdal.prototypes.errcheck import \
|
||||||
|
check_arg_errcode, check_errcode, check_geom, check_geom_offset, \
|
||||||
|
check_pointer, check_srs, check_str_arg, check_string, check_const_string
|
||||||
|
|
||||||
|
def double_output(func, argtypes, errcheck=False, strarg=False):
|
||||||
|
"Generates a ctypes function that returns a double value."
|
||||||
|
func.argtypes = argtypes
|
||||||
|
func.restype = c_double
|
||||||
|
if errcheck: func.errcheck = check_arg_errcode
|
||||||
|
if strarg: func.errcheck = check_str_arg
|
||||||
|
return func
|
||||||
|
|
||||||
|
def geom_output(func, argtypes, offset=None):
|
||||||
|
"""
|
||||||
|
Generates a function that returns a Geometry either by reference
|
||||||
|
or directly (if the return_geom keyword is set to True).
|
||||||
|
"""
|
||||||
|
# Setting the argument types
|
||||||
|
func.argtypes = argtypes
|
||||||
|
|
||||||
|
if not offset:
|
||||||
|
# When a geometry pointer is directly returned.
|
||||||
|
func.restype = c_void_p
|
||||||
|
func.errcheck = check_geom
|
||||||
|
else:
|
||||||
|
# Error code returned, geometry is returned by-reference.
|
||||||
|
func.restype = c_int
|
||||||
|
def geomerrcheck(result, func, cargs):
|
||||||
|
return check_geom_offset(result, func, cargs, offset)
|
||||||
|
func.errcheck = geomerrcheck
|
||||||
|
|
||||||
|
return func
|
||||||
|
|
||||||
|
def int_output(func, argtypes):
|
||||||
|
"Generates a ctypes function that returns an integer value."
|
||||||
|
func.argtypes = argtypes
|
||||||
|
func.restype = c_int
|
||||||
|
return func
|
||||||
|
|
||||||
|
def srs_output(func, argtypes):
|
||||||
|
"""
|
||||||
|
Generates a ctypes prototype for the given function with
|
||||||
|
the given C arguments that returns a pointer to an OGR
|
||||||
|
Spatial Reference System.
|
||||||
|
"""
|
||||||
|
func.argtypes = argtypes
|
||||||
|
func.restype = c_void_p
|
||||||
|
func.errcheck = check_srs
|
||||||
|
return func
|
||||||
|
|
||||||
|
def const_string_output(func, argtypes, offset=None):
|
||||||
|
func.argtypes = argtypes
|
||||||
|
if offset:
|
||||||
|
func.restype = c_int
|
||||||
|
else:
|
||||||
|
func.restype = c_char_p
|
||||||
|
|
||||||
|
def _check_const(result, func, cargs):
|
||||||
|
return check_const_string(result, func, cargs, offset=offset)
|
||||||
|
func.errcheck = _check_const
|
||||||
|
|
||||||
|
return func
|
||||||
|
|
||||||
|
def string_output(func, argtypes, offset=-1, str_result=False):
|
||||||
|
"""
|
||||||
|
Generates a ctypes prototype for the given function with the
|
||||||
|
given argument types that returns a string from a GDAL pointer.
|
||||||
|
The `const` flag indicates whether the allocated pointer should
|
||||||
|
be freed via the GDAL library routine VSIFree -- but only applies
|
||||||
|
only when `str_result` is True.
|
||||||
|
"""
|
||||||
|
func.argtypes = argtypes
|
||||||
|
if str_result:
|
||||||
|
# String is the result, don't explicitly define
|
||||||
|
# the argument type so we can get the pointer.
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# Error code is returned
|
||||||
|
func.restype = c_int
|
||||||
|
|
||||||
|
# Dynamically defining our error-checking function with the
|
||||||
|
# given offset.
|
||||||
|
def _check_str(result, func, cargs):
|
||||||
|
return check_string(result, func, cargs,
|
||||||
|
offset=offset, str_result=str_result)
|
||||||
|
func.errcheck = _check_str
|
||||||
|
return func
|
||||||
|
|
||||||
|
def void_output(func, argtypes, errcheck=True):
|
||||||
|
"""
|
||||||
|
For functions that don't only return an error code that needs to
|
||||||
|
be examined.
|
||||||
|
"""
|
||||||
|
if argtypes: func.argtypes = argtypes
|
||||||
|
if errcheck:
|
||||||
|
# `errcheck` keyword may be set to False for routines that
|
||||||
|
# return void, rather than a status code.
|
||||||
|
func.restype = c_int
|
||||||
|
func.errcheck = check_errcode
|
||||||
|
return func
|
||||||
|
|
||||||
|
def voidptr_output(func, argtypes):
|
||||||
|
"For functions that return c_void_p."
|
||||||
|
func.argtypes = argtypes
|
||||||
|
func.restype = c_void_p
|
||||||
|
func.errcheck = check_pointer
|
||||||
|
return func
|
95
django/contrib/gis/gdal/prototypes/geom.py
Normal file
95
django/contrib/gis/gdal/prototypes/geom.py
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
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.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
|
||||||
|
|
||||||
|
### Generation routines specific to this module ###
|
||||||
|
def env_func(f, argtypes):
|
||||||
|
"For getting OGREnvelopes."
|
||||||
|
f.argtypes = argtypes
|
||||||
|
f.restype = None
|
||||||
|
f.errcheck = check_envelope
|
||||||
|
return f
|
||||||
|
|
||||||
|
def pnt_func(f):
|
||||||
|
"For accessing point information."
|
||||||
|
return double_output(f, [c_void_p, c_int])
|
||||||
|
|
||||||
|
def topology_func(f):
|
||||||
|
f.argtypes = [c_void_p, c_void_p]
|
||||||
|
f.restype = c_int
|
||||||
|
f.errchck = check_bool
|
||||||
|
return f
|
||||||
|
|
||||||
|
### OGR_G ctypes function prototypes ###
|
||||||
|
|
||||||
|
# GetX, GetY, GetZ all return doubles.
|
||||||
|
getx = pnt_func(lgdal.OGR_G_GetX)
|
||||||
|
gety = pnt_func(lgdal.OGR_G_GetY)
|
||||||
|
getz = pnt_func(lgdal.OGR_G_GetZ)
|
||||||
|
|
||||||
|
# Geometry creation routines.
|
||||||
|
from_wkb = geom_output(lgdal.OGR_G_CreateFromWkb, [c_char_p, c_void_p, POINTER(c_void_p), c_int], offset=-2)
|
||||||
|
from_wkt = geom_output(lgdal.OGR_G_CreateFromWkt, [POINTER(c_char_p), c_void_p, POINTER(c_void_p)], offset=-1)
|
||||||
|
create_geom = geom_output(lgdal.OGR_G_CreateGeometry, [c_int])
|
||||||
|
clone_geom = geom_output(lgdal.OGR_G_Clone, [c_void_p])
|
||||||
|
get_geom_ref = geom_output(lgdal.OGR_G_GetGeometryRef, [c_void_p, c_int])
|
||||||
|
get_boundary = geom_output(lgdal.OGR_G_GetBoundary, [c_void_p])
|
||||||
|
geom_convex_hull = geom_output(lgdal.OGR_G_ConvexHull, [c_void_p])
|
||||||
|
geom_diff = geom_output(lgdal.OGR_G_Difference, [c_void_p, c_void_p])
|
||||||
|
geom_intersection = geom_output(lgdal.OGR_G_Intersection, [c_void_p, c_void_p])
|
||||||
|
geom_sym_diff = geom_output(lgdal.OGR_G_SymmetricDifference, [c_void_p, c_void_p])
|
||||||
|
geom_union = geom_output(lgdal.OGR_G_Union, [c_void_p, c_void_p])
|
||||||
|
|
||||||
|
# Geometry modification routines.
|
||||||
|
add_geom = void_output(lgdal.OGR_G_AddGeometry, [c_void_p, c_void_p])
|
||||||
|
import_wkt = void_output(lgdal.OGR_G_ImportFromWkt, [c_void_p, POINTER(c_char_p)])
|
||||||
|
|
||||||
|
# Destroys a geometry
|
||||||
|
destroy_geom = void_output(lgdal.OGR_G_DestroyGeometry, [c_void_p], errcheck=False)
|
||||||
|
|
||||||
|
# Geometry export routines.
|
||||||
|
to_wkb = void_output(lgdal.OGR_G_ExportToWkb, None, errcheck=True) # special handling for WKB.
|
||||||
|
to_wkt = string_output(lgdal.OGR_G_ExportToWkt, [c_void_p, POINTER(c_char_p)])
|
||||||
|
to_gml = string_output(lgdal.OGR_G_ExportToGML, [c_void_p], str_result=True)
|
||||||
|
get_wkbsize = int_output(lgdal.OGR_G_WkbSize, [c_void_p])
|
||||||
|
|
||||||
|
# Geometry spatial-reference related routines.
|
||||||
|
assign_srs = void_output(lgdal.OGR_G_AssignSpatialReference, [c_void_p, c_void_p], errcheck=False)
|
||||||
|
get_geom_srs = srs_output(lgdal.OGR_G_GetSpatialReference, [c_void_p])
|
||||||
|
|
||||||
|
# Geometry properties
|
||||||
|
get_area = double_output(lgdal.OGR_G_GetArea, [c_void_p])
|
||||||
|
get_centroid = void_output(lgdal.OGR_G_Centroid, [c_void_p, c_void_p])
|
||||||
|
get_dims = int_output(lgdal.OGR_G_GetDimension, [c_void_p])
|
||||||
|
get_coord_dims = int_output(lgdal.OGR_G_GetCoordinateDimension, [c_void_p])
|
||||||
|
|
||||||
|
get_geom_count = int_output(lgdal.OGR_G_GetGeometryCount, [c_void_p])
|
||||||
|
get_geom_name = const_string_output(lgdal.OGR_G_GetGeometryName, [c_void_p])
|
||||||
|
get_geom_type = int_output(lgdal.OGR_G_GetGeometryType, [c_void_p])
|
||||||
|
get_point_count = int_output(lgdal.OGR_G_GetPointCount, [c_void_p])
|
||||||
|
get_point = void_output(lgdal.OGR_G_GetPoint, [c_void_p, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_double)], errcheck=False)
|
||||||
|
geom_close_rings = void_output(lgdal.OGR_G_CloseRings, [c_void_p])
|
||||||
|
|
||||||
|
# Topology routines.
|
||||||
|
ogr_contains = topology_func(lgdal.OGR_G_Contains)
|
||||||
|
ogr_crosses = topology_func(lgdal.OGR_G_Crosses)
|
||||||
|
ogr_disjoint = topology_func(lgdal.OGR_G_Disjoint)
|
||||||
|
ogr_equals = topology_func(lgdal.OGR_G_Equals)
|
||||||
|
ogr_intersects = topology_func(lgdal.OGR_G_Intersects)
|
||||||
|
ogr_overlaps = topology_func(lgdal.OGR_G_Overlaps)
|
||||||
|
ogr_touches = topology_func(lgdal.OGR_G_Touches)
|
||||||
|
ogr_within = topology_func(lgdal.OGR_G_Within)
|
||||||
|
|
||||||
|
# Transformation routines.
|
||||||
|
geom_transform = void_output(lgdal.OGR_G_Transform, [c_void_p, c_void_p], errcheck=True)
|
||||||
|
geom_transform_to = void_output(lgdal.OGR_G_TransformTo, [c_void_p, c_void_p], errcheck=True)
|
||||||
|
|
||||||
|
# For retrieving the envelope of the geometry.
|
||||||
|
get_envelope = lgdal.OGR_G_GetEnvelope
|
||||||
|
get_envelope.restype = None
|
||||||
|
get_envelope.argtypes = [c_void_p, POINTER(OGREnvelope)]
|
||||||
|
get_envelope.errcheck = check_envelope
|
70
django/contrib/gis/gdal/prototypes/srs.py
Normal file
70
django/contrib/gis/gdal/prototypes/srs.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
from ctypes import c_char_p, c_int, c_void_p, POINTER
|
||||||
|
from django.contrib.gis.gdal.libgdal import lgdal
|
||||||
|
from django.contrib.gis.gdal.prototypes.generation import \
|
||||||
|
const_string_output, double_output, int_output, \
|
||||||
|
srs_output, string_output, void_output
|
||||||
|
|
||||||
|
## Shortcut generation for routines with known parameters.
|
||||||
|
def srs_double(f):
|
||||||
|
"""
|
||||||
|
Creates a function prototype for the OSR routines that take
|
||||||
|
the OSRSpatialReference object and
|
||||||
|
"""
|
||||||
|
return double_output(f, [c_void_p, POINTER(c_int)], errcheck=True)
|
||||||
|
|
||||||
|
def units_func(f):
|
||||||
|
"""
|
||||||
|
Creates a ctypes function prototype for OSR units functions, e.g.,
|
||||||
|
OSRGetAngularUnits, OSRGetLinearUnits.
|
||||||
|
"""
|
||||||
|
return double_output(f, [c_void_p, POINTER(c_char_p)], strarg=True)
|
||||||
|
|
||||||
|
# Creation & destruction.
|
||||||
|
clone_srs = srs_output(lgdal.OSRClone, [c_void_p])
|
||||||
|
new_srs = srs_output(lgdal.OSRNewSpatialReference, [c_char_p])
|
||||||
|
release_srs = void_output(lgdal.OSRRelease, [c_void_p])
|
||||||
|
srs_validate = void_output(lgdal.OSRValidate, [c_void_p], errcheck=True)
|
||||||
|
|
||||||
|
# Getting the semi_major, semi_minor, and flattening functions.
|
||||||
|
semi_major = srs_double(lgdal.OSRGetSemiMajor)
|
||||||
|
semi_minor = srs_double(lgdal.OSRGetSemiMinor)
|
||||||
|
invflattening = srs_double(lgdal.OSRGetInvFlattening)
|
||||||
|
|
||||||
|
# WKT, PROJ, EPSG, XML importation routines.
|
||||||
|
from_wkt = void_output(lgdal.OSRImportFromWkt, [c_void_p, POINTER(c_char_p)])
|
||||||
|
from_proj = void_output(lgdal.OSRImportFromProj4, [c_void_p, c_char_p])
|
||||||
|
from_epsg = void_output(lgdal.OSRImportFromEPSG, [c_void_p, c_int])
|
||||||
|
from_xml = void_output(lgdal.OSRImportFromXML, [c_void_p, c_char_p])
|
||||||
|
|
||||||
|
# Morphing to/from ESRI WKT.
|
||||||
|
morph_to_esri = void_output(lgdal.OSRMorphToESRI, [c_void_p])
|
||||||
|
morph_from_esri = void_output(lgdal.OSRMorphFromESRI, [c_void_p])
|
||||||
|
|
||||||
|
# Identifying the EPSG
|
||||||
|
identify_epsg = void_output(lgdal.OSRAutoIdentifyEPSG, [c_void_p])
|
||||||
|
|
||||||
|
# Getting the angular_units, linear_units functions
|
||||||
|
linear_units = units_func(lgdal.OSRGetLinearUnits)
|
||||||
|
angular_units = units_func(lgdal.OSRGetAngularUnits)
|
||||||
|
|
||||||
|
# For exporting to WKT, PROJ.4, "Pretty" WKT, and XML.
|
||||||
|
to_wkt = string_output(lgdal.OSRExportToWkt, [c_void_p, POINTER(c_char_p)])
|
||||||
|
to_proj = string_output(lgdal.OSRExportToProj4, [c_void_p, POINTER(c_char_p)])
|
||||||
|
to_pretty_wkt = string_output(lgdal.OSRExportToPrettyWkt, [c_void_p, POINTER(c_char_p), c_int], offset=-2)
|
||||||
|
|
||||||
|
# FIXME: This leaks memory, still don't know why.
|
||||||
|
to_xml = string_output(lgdal.OSRExportToXML, [c_void_p, POINTER(c_char_p), c_char_p], offset=-2)
|
||||||
|
|
||||||
|
# String attribute retrival routines.
|
||||||
|
get_attr_value = const_string_output(lgdal.OSRGetAttrValue, [c_void_p, c_char_p, c_int])
|
||||||
|
get_auth_name = const_string_output(lgdal.OSRGetAuthorityName, [c_void_p, c_char_p])
|
||||||
|
get_auth_code = const_string_output(lgdal.OSRGetAuthorityCode, [c_void_p, c_char_p])
|
||||||
|
|
||||||
|
# SRS Properties
|
||||||
|
isgeographic = int_output(lgdal.OSRIsGeographic, [c_void_p])
|
||||||
|
islocal = int_output(lgdal.OSRIsLocal, [c_void_p])
|
||||||
|
isprojected = int_output(lgdal.OSRIsProjected, [c_void_p])
|
||||||
|
|
||||||
|
# Coordinate transformation
|
||||||
|
new_ct= srs_output(lgdal.OCTNewCoordinateTransformation, [c_void_p, c_void_p])
|
||||||
|
destroy_ct = void_output(lgdal.OCTDestroyCoordinateTransformation, [c_void_p])
|
@ -28,50 +28,18 @@
|
|||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
from types import StringType, UnicodeType, TupleType
|
from types import StringType, UnicodeType, TupleType
|
||||||
from ctypes import \
|
from ctypes import byref, c_char_p, c_int, c_void_p
|
||||||
c_char_p, c_int, c_double, c_void_p, POINTER, \
|
|
||||||
byref, string_at, create_string_buffer
|
|
||||||
|
|
||||||
# Getting the GDAL C Library
|
|
||||||
from django.contrib.gis.gdal.libgdal import lgdal
|
|
||||||
|
|
||||||
# Getting the error checking routine and exceptions
|
# Getting the error checking routine and exceptions
|
||||||
from django.contrib.gis.gdal.error import check_err, OGRException, SRSException
|
from django.contrib.gis.gdal.error import OGRException, SRSException
|
||||||
|
from django.contrib.gis.gdal.prototypes.srs import *
|
||||||
#### ctypes function prototypes ####
|
|
||||||
def ellipsis_func(f):
|
|
||||||
"""
|
|
||||||
Creates a ctypes function prototype for OSR ellipsis property functions, e.g.,
|
|
||||||
OSRGetSemiMajor, OSRGetSemiMinor, OSRGetInvFlattening.
|
|
||||||
"""
|
|
||||||
f.restype = c_double
|
|
||||||
f.argtypes = [c_void_p, POINTER(c_int)]
|
|
||||||
return f
|
|
||||||
|
|
||||||
# Getting the semi_major, semi_minor, and flattening functions.
|
|
||||||
semi_major = ellipsis_func(lgdal.OSRGetSemiMajor)
|
|
||||||
semi_minor = ellipsis_func(lgdal.OSRGetSemiMinor)
|
|
||||||
invflattening = ellipsis_func(lgdal.OSRGetInvFlattening)
|
|
||||||
|
|
||||||
def units_func(f):
|
|
||||||
"""
|
|
||||||
Creates a ctypes function prototype for OSR units functions, e.g.,
|
|
||||||
OSRGetAngularUnits, OSRGetLinearUnits.
|
|
||||||
"""
|
|
||||||
f.restype = c_double
|
|
||||||
f.argtypes = [c_void_p, POINTER(c_char_p)]
|
|
||||||
return f
|
|
||||||
|
|
||||||
# Getting the angular_units, linear_units functions
|
|
||||||
linear_units = units_func(lgdal.OSRGetLinearUnits)
|
|
||||||
angular_units = units_func(lgdal.OSRGetAngularUnits)
|
|
||||||
|
|
||||||
#### Spatial Reference class. ####
|
#### Spatial Reference class. ####
|
||||||
class SpatialReference(object):
|
class SpatialReference(object):
|
||||||
"""
|
"""
|
||||||
A wrapper for the OGRSpatialReference object. According to the GDAL website,
|
A wrapper for the OGRSpatialReference object. According to the GDAL website,
|
||||||
the SpatialReference object 'provide[s] services to represent coordinate
|
the SpatialReference object "provide[s] services to represent coordinate
|
||||||
systems (projections and datums) and to transform between them.'
|
systems (projections and datums) and to transform between them."
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Well-Known Geographical Coordinate System Name
|
# Well-Known Geographical Coordinate System Name
|
||||||
@ -82,9 +50,8 @@ class SpatialReference(object):
|
|||||||
def __init__(self, srs_input='', srs_type='wkt'):
|
def __init__(self, srs_input='', srs_type='wkt'):
|
||||||
"Creates a spatial reference object from the given OGC Well Known Text (WKT)."
|
"Creates a spatial reference object from the given OGC Well Known Text (WKT)."
|
||||||
|
|
||||||
self._srs = None # Initially NULL
|
# Intializing pointer and string buffer.
|
||||||
|
self._ptr = None
|
||||||
# Creating an initial empty string buffer.
|
|
||||||
buf = c_char_p('')
|
buf = c_char_p('')
|
||||||
|
|
||||||
# Encoding to ASCII if unicode passed in.
|
# Encoding to ASCII if unicode passed in.
|
||||||
@ -92,37 +59,40 @@ class SpatialReference(object):
|
|||||||
srs_input = srs_input.encode('ascii')
|
srs_input = srs_input.encode('ascii')
|
||||||
|
|
||||||
if isinstance(srs_input, StringType):
|
if isinstance(srs_input, StringType):
|
||||||
# Is this an EPSG well known name?
|
|
||||||
m = self._epsg_regex.match(srs_input)
|
m = self._epsg_regex.match(srs_input)
|
||||||
if m:
|
if m:
|
||||||
|
# Is this an EPSG well known name?
|
||||||
srs_type = 'epsg'
|
srs_type = 'epsg'
|
||||||
srs_input = int(m.group('epsg'))
|
srs_input = int(m.group('epsg'))
|
||||||
# Is this a short-hand well known name?
|
|
||||||
elif srs_input in self._well_known:
|
elif srs_input in self._well_known:
|
||||||
|
# Is this a short-hand well known name?
|
||||||
srs_type = 'epsg'
|
srs_type = 'epsg'
|
||||||
srs_input = self._well_known[srs_input]
|
srs_input = self._well_known[srs_input]
|
||||||
elif srs_type == 'proj':
|
elif srs_type == 'proj':
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
# Setting the buffer with WKT, PROJ.4 string, etc.
|
||||||
buf = c_char_p(srs_input)
|
buf = c_char_p(srs_input)
|
||||||
elif isinstance(srs_input, int):
|
elif isinstance(srs_input, int):
|
||||||
if srs_type == 'wkt': srs_type = 'epsg' # want to try epsg if only integer provided
|
# EPSG integer code was input.
|
||||||
if srs_type not in ('epsg', 'ogr'):
|
if srs_type != 'epsg': srs_type = 'epsg'
|
||||||
raise SRSException('Integer input requires SRS type of "ogr" or "epsg".')
|
elif isinstance(srs_input, c_void_p):
|
||||||
|
srs_type = 'ogr'
|
||||||
else:
|
else:
|
||||||
raise TypeError('Invalid SRS type "%s"' % srs_type)
|
raise TypeError('Invalid SRS type "%s"' % srs_type)
|
||||||
|
|
||||||
# Calling OSRNewSpatialReference with the string buffer.
|
|
||||||
if srs_type == 'ogr':
|
if srs_type == 'ogr':
|
||||||
srs = srs_input # SRS input is OGR pointer
|
# SRS input is OGR pointer
|
||||||
|
srs = srs_input
|
||||||
else:
|
else:
|
||||||
srs = lgdal.OSRNewSpatialReference(buf)
|
# Creating a new pointer, using the string buffer.
|
||||||
|
srs = new_srs(buf)
|
||||||
|
|
||||||
# If the pointer is NULL, throw an exception.
|
# If the pointer is NULL, throw an exception.
|
||||||
if not srs:
|
if not srs:
|
||||||
raise SRSException('Could not create spatial reference from: %s' % srs_input)
|
raise SRSException('Could not create spatial reference from: %s' % srs_input)
|
||||||
else:
|
else:
|
||||||
self._srs = srs
|
self._ptr = srs
|
||||||
|
|
||||||
# Post-processing if in PROJ.4 or EPSG formats.
|
# Post-processing if in PROJ.4 or EPSG formats.
|
||||||
if srs_type == 'proj': self.import_proj(srs_input)
|
if srs_type == 'proj': self.import_proj(srs_input)
|
||||||
@ -130,7 +100,7 @@ class SpatialReference(object):
|
|||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
"Destroys this spatial reference."
|
"Destroys this spatial reference."
|
||||||
if self._srs: lgdal.OSRRelease(self._srs)
|
if self._ptr: release_srs(self._ptr)
|
||||||
|
|
||||||
def __getitem__(self, target):
|
def __getitem__(self, target):
|
||||||
"""
|
"""
|
||||||
@ -172,43 +142,48 @@ class SpatialReference(object):
|
|||||||
"The string representation uses 'pretty' WKT."
|
"The string representation uses 'pretty' WKT."
|
||||||
return self.pretty_wkt
|
return self.pretty_wkt
|
||||||
|
|
||||||
def _string_ptr(self, ptr):
|
|
||||||
"""
|
|
||||||
Returns the string at the pointer if it is valid, None if the pointer
|
|
||||||
is NULL.
|
|
||||||
"""
|
|
||||||
if not ptr: return None
|
|
||||||
else: return string_at(ptr)
|
|
||||||
|
|
||||||
#### SpatialReference Methods ####
|
#### SpatialReference Methods ####
|
||||||
def auth_name(self, target):
|
|
||||||
"Getting the authority name for the target node."
|
|
||||||
ptr = lgdal.OSRGetAuthorityName(self._srs, c_char_p(target))
|
|
||||||
return self._string_ptr(ptr)
|
|
||||||
|
|
||||||
def auth_code(self, target):
|
|
||||||
"Getting the authority code for the given target node."
|
|
||||||
ptr = lgdal.OSRGetAuthorityCode(self._srs, c_char_p(target))
|
|
||||||
return self._string_ptr(ptr)
|
|
||||||
|
|
||||||
def attr_value(self, target, index=0):
|
def attr_value(self, target, index=0):
|
||||||
"""
|
"""
|
||||||
The attribute value for the given target node (e.g. 'PROJCS'). The index
|
The attribute value for the given target node (e.g. 'PROJCS'). The index
|
||||||
keyword specifies an index of the child node to return.
|
keyword specifies an index of the child node to return.
|
||||||
"""
|
"""
|
||||||
if not isinstance(target, str):
|
if not isinstance(target, str) or not isinstance(index, int):
|
||||||
raise TypeError('Attribute target must be a string')
|
raise TypeError
|
||||||
ptr = lgdal.OSRGetAttrValue(self._srs, c_char_p(target), c_int(index))
|
return get_attr_value(self._ptr, target, index)
|
||||||
return self._string_ptr(ptr)
|
|
||||||
|
def auth_name(self, target):
|
||||||
|
"Returns the authority name for the given string target node."
|
||||||
|
return get_auth_name(self._ptr, target)
|
||||||
|
|
||||||
|
def auth_code(self, target):
|
||||||
|
"Returns the authority code for the given string target node."
|
||||||
|
return get_auth_code(self._ptr, target)
|
||||||
|
|
||||||
|
def clone(self):
|
||||||
|
"Returns a clone of this SpatialReference object."
|
||||||
|
return SpatialReference(clone_srs(self._ptr))
|
||||||
|
|
||||||
|
def from_esri(self):
|
||||||
|
"Morphs this SpatialReference from ESRI's format to EPSG."
|
||||||
|
morph_from_esri(self._ptr)
|
||||||
|
|
||||||
|
def identify_epsg(self):
|
||||||
|
"""
|
||||||
|
This method inspects the WKT of this SpatialReference, and will
|
||||||
|
add EPSG authority nodes where an EPSG identifier is applicable.
|
||||||
|
"""
|
||||||
|
identify_epsg(self._ptr)
|
||||||
|
|
||||||
|
def to_esri(self):
|
||||||
|
"Morphs this SpatialReference to ESRI's format."
|
||||||
|
morph_to_esri(self._ptr)
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
"Checks to see if the given spatial reference is valid."
|
"Checks to see if the given spatial reference is valid."
|
||||||
check_err(lgdal.OSRValidate(self._srs))
|
srs_validate(self._ptr)
|
||||||
|
|
||||||
def clone(self):
|
|
||||||
"Returns a clone of this Spatial Reference."
|
|
||||||
return SpatialReference(lgdal.OSRClone(self._srs), 'ogr')
|
|
||||||
|
|
||||||
|
#### Name & SRID properties ####
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"Returns the name of this Spatial Reference."
|
"Returns the name of this Spatial Reference."
|
||||||
@ -226,43 +201,29 @@ class SpatialReference(object):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
#### Unit Properties ####
|
#### Unit Properties ####
|
||||||
def _cache_linear(self):
|
|
||||||
"Caches the linear units value and name."
|
|
||||||
if not hasattr(self, '_linear_units') or not hasattr(self, '_linear_name'):
|
|
||||||
name_buf = c_char_p()
|
|
||||||
self._linear_units = linear_units(self._srs, byref(name_buf))
|
|
||||||
self._linear_name = string_at(name_buf)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def linear_name(self):
|
def linear_name(self):
|
||||||
"Returns the name of the linear units."
|
"Returns the name of the linear units."
|
||||||
self._cache_linear()
|
units, name = linear_units(self._ptr, byref(c_char_p()))
|
||||||
return self._linear_name
|
return name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def linear_units(self):
|
def linear_units(self):
|
||||||
"Returns the value of the linear units."
|
"Returns the value of the linear units."
|
||||||
self._cache_linear()
|
units, name = linear_units(self._ptr, byref(c_char_p()))
|
||||||
return self._linear_units
|
return units
|
||||||
|
|
||||||
def _cache_angular(self):
|
|
||||||
"Caches the angular units value and name."
|
|
||||||
name_buf = c_char_p()
|
|
||||||
if not hasattr(self, '_angular_units') or not hasattr(self, '_angular_name'):
|
|
||||||
self._angular_units = angular_units(self._srs, byref(name_buf))
|
|
||||||
self._angular_name = string_at(name_buf)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def angular_name(self):
|
def angular_name(self):
|
||||||
"Returns the name of the angular units."
|
"Returns the name of the angular units."
|
||||||
self._cache_angular()
|
units, name = angular_units(self._ptr, byref(c_char_p()))
|
||||||
return self._angular_name
|
return name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def angular_units(self):
|
def angular_units(self):
|
||||||
"Returns the value of the angular units."
|
"Returns the value of the angular units."
|
||||||
self._cache_angular()
|
units, name = angular_units(self._ptr, byref(c_char_p()))
|
||||||
return self._angular_units
|
return units
|
||||||
|
|
||||||
#### Spheroid/Ellipsoid Properties ####
|
#### Spheroid/Ellipsoid Properties ####
|
||||||
@property
|
@property
|
||||||
@ -276,26 +237,17 @@ class SpatialReference(object):
|
|||||||
@property
|
@property
|
||||||
def semi_major(self):
|
def semi_major(self):
|
||||||
"Returns the Semi Major Axis for this Spatial Reference."
|
"Returns the Semi Major Axis for this Spatial Reference."
|
||||||
err = c_int(0)
|
return semi_major(self._ptr, byref(c_int()))
|
||||||
sm = semi_major(self._srs, byref(err))
|
|
||||||
check_err(err.value)
|
|
||||||
return sm
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def semi_minor(self):
|
def semi_minor(self):
|
||||||
"Returns the Semi Minor Axis for this Spatial Reference."
|
"Returns the Semi Minor Axis for this Spatial Reference."
|
||||||
err = c_int()
|
return semi_minor(self._ptr, byref(c_int()))
|
||||||
sm = semi_minor(self._srs, byref(err))
|
|
||||||
check_err(err.value)
|
|
||||||
return sm
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def inverse_flattening(self):
|
def inverse_flattening(self):
|
||||||
"Returns the Inverse Flattening for this Spatial Reference."
|
"Returns the Inverse Flattening for this Spatial Reference."
|
||||||
err = c_int()
|
return invflattening(self._ptr, byref(c_int()))
|
||||||
inv_flat = invflattening(self._srs, byref(err))
|
|
||||||
check_err(err.value)
|
|
||||||
return inv_flat
|
|
||||||
|
|
||||||
#### Boolean Properties ####
|
#### Boolean Properties ####
|
||||||
@property
|
@property
|
||||||
@ -304,14 +256,12 @@ class SpatialReference(object):
|
|||||||
Returns True if this SpatialReference is geographic
|
Returns True if this SpatialReference is geographic
|
||||||
(root node is GEOGCS).
|
(root node is GEOGCS).
|
||||||
"""
|
"""
|
||||||
if lgdal.OSRIsGeographic(self._srs): return True
|
return bool(isgeographic(self._ptr))
|
||||||
else: return False
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def local(self):
|
def local(self):
|
||||||
"Returns True if this SpatialReference is local (root node is LOCAL_CS)."
|
"Returns True if this SpatialReference is local (root node is LOCAL_CS)."
|
||||||
if lgdal.OSRIsLocal(self._srs): return True
|
return bool(islocal(self._ptr))
|
||||||
else: return False
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def projected(self):
|
def projected(self):
|
||||||
@ -319,48 +269,40 @@ class SpatialReference(object):
|
|||||||
Returns True if this SpatialReference is a projected coordinate system
|
Returns True if this SpatialReference is a projected coordinate system
|
||||||
(root node is PROJCS).
|
(root node is PROJCS).
|
||||||
"""
|
"""
|
||||||
if lgdal.OSRIsProjected(self._srs): return True
|
return bool(isprojected(self._ptr))
|
||||||
else: return False
|
|
||||||
|
|
||||||
#### Import Routines #####
|
#### Import Routines #####
|
||||||
def import_wkt(self, wkt):
|
def import_wkt(self, wkt):
|
||||||
"Imports the Spatial Reference from OGC WKT (string)"
|
"Imports the Spatial Reference from OGC WKT (string)"
|
||||||
buf = create_string_buffer(wkt)
|
from_wkt(self._ptr, byref(c_char_p(wkt)))
|
||||||
check_err(lgdal.OSRImportFromWkt(self._srs, byref(buf)))
|
|
||||||
|
|
||||||
def import_proj(self, proj):
|
def import_proj(self, proj):
|
||||||
"Imports the Spatial Reference from a PROJ.4 string."
|
"Imports the Spatial Reference from a PROJ.4 string."
|
||||||
check_err(lgdal.OSRImportFromProj4(self._srs, create_string_buffer(proj)))
|
from_proj(self._ptr, proj)
|
||||||
|
|
||||||
def import_epsg(self, epsg):
|
def import_epsg(self, epsg):
|
||||||
"Imports the Spatial Reference from the EPSG code (an integer)."
|
"Imports the Spatial Reference from the EPSG code (an integer)."
|
||||||
check_err(lgdal.OSRImportFromEPSG(self._srs, c_int(epsg)))
|
from_epsg(self._ptr, epsg)
|
||||||
|
|
||||||
def import_xml(self, xml):
|
def import_xml(self, xml):
|
||||||
"Imports the Spatial Reference from an XML string."
|
"Imports the Spatial Reference from an XML string."
|
||||||
check_err(lgdal.OSRImportFromXML(self._srs, create_string_buffer(xml)))
|
from_xml(self._ptr, xml)
|
||||||
|
|
||||||
#### Export Properties ####
|
#### Export Properties ####
|
||||||
@property
|
@property
|
||||||
def wkt(self):
|
def wkt(self):
|
||||||
"Returns the WKT representation of this Spatial Reference."
|
"Returns the WKT representation of this Spatial Reference."
|
||||||
w = c_char_p()
|
return to_wkt(self._ptr, byref(c_char_p()))
|
||||||
check_err(lgdal.OSRExportToWkt(self._srs, byref(w)))
|
|
||||||
if w: return string_at(w)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pretty_wkt(self, simplify=0):
|
def pretty_wkt(self, simplify=0):
|
||||||
"Returns the 'pretty' representation of the WKT."
|
"Returns the 'pretty' representation of the WKT."
|
||||||
w = c_char_p()
|
return to_pretty_wkt(self._ptr, byref(c_char_p()), simplify)
|
||||||
check_err(lgdal.OSRExportToPrettyWkt(self._srs, byref(w), c_int(simplify)))
|
|
||||||
if w: return string_at(w)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def proj(self):
|
def proj(self):
|
||||||
"Returns the PROJ.4 representation for this Spatial Reference."
|
"Returns the PROJ.4 representation for this Spatial Reference."
|
||||||
w = c_char_p()
|
return to_proj(self._ptr, byref(c_char_p()))
|
||||||
check_err(lgdal.OSRExportToProj4(self._srs, byref(w)))
|
|
||||||
if w: return string_at(w)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def proj4(self):
|
def proj4(self):
|
||||||
@ -370,28 +312,34 @@ class SpatialReference(object):
|
|||||||
@property
|
@property
|
||||||
def xml(self, dialect=''):
|
def xml(self, dialect=''):
|
||||||
"Returns the XML representation of this Spatial Reference."
|
"Returns the XML representation of this Spatial Reference."
|
||||||
w = c_char_p()
|
# FIXME: This leaks memory, have to figure out why.
|
||||||
check_err(lgdal.OSRExportToXML(self._srs, byref(w), create_string_buffer(dialect)))
|
return to_xml(self._ptr, byref(c_char_p()), dialect)
|
||||||
return string_at(w)
|
|
||||||
|
def to_esri(self):
|
||||||
|
"Morphs this SpatialReference to ESRI's format."
|
||||||
|
morph_to_esri(self._ptr)
|
||||||
|
|
||||||
|
def from_esri(self):
|
||||||
|
"Morphs this SpatialReference from ESRI's format to EPSG."
|
||||||
|
morph_from_esri(self._ptr)
|
||||||
|
|
||||||
class CoordTransform(object):
|
class CoordTransform(object):
|
||||||
"A coordinate system transformation object."
|
"The coordinate system transformation object."
|
||||||
|
|
||||||
def __init__(self, source, target):
|
def __init__(self, source, target):
|
||||||
"Initializes on a source and target SpatialReference objects."
|
"Initializes on a source and target SpatialReference objects."
|
||||||
self._ct = 0 # Initially NULL
|
self._ptr = None # Initially NULL
|
||||||
if not isinstance(source, SpatialReference) or not isinstance(target, SpatialReference):
|
if not isinstance(source, SpatialReference) or not isinstance(target, SpatialReference):
|
||||||
raise SRSException('source and target must be of type SpatialReference')
|
raise SRSException('source and target must be of type SpatialReference')
|
||||||
ct = lgdal.OCTNewCoordinateTransformation(source._srs, target._srs)
|
self._ptr = new_ct(source._ptr, target._ptr)
|
||||||
if not ct:
|
if not self._ptr:
|
||||||
raise SRSException('could not intialize CoordTransform object')
|
raise SRSException('could not intialize CoordTransform object')
|
||||||
self._ct = ct
|
|
||||||
self._srs1_name = source.name
|
self._srs1_name = source.name
|
||||||
self._srs2_name = target.name
|
self._srs2_name = target.name
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
"Deletes this Coordinate Transformation object."
|
"Deletes this Coordinate Transformation object."
|
||||||
if self._ct: lgdal.OCTDestroyCoordinateTransformation(self._ct)
|
if self._ptr: destroy_ct(self._ptr)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Transform from "%s" to "%s"' % (str(self._srs1_name), str(self._srs2_name))
|
return 'Transform from "%s" to "%s"' % (self._srs1_name, self._srs2_name)
|
||||||
|
@ -15,10 +15,10 @@ class TestSHP:
|
|||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
|
||||||
# List of acceptable data sources.
|
# List of acceptable data sources.
|
||||||
ds_list = (TestSHP('test_point', nfeat=5, nfld=3, geom='POINT', gtype=1, fields={'dbl' : OFTReal, 'int' : OFTReal, 'str' : OFTString,},
|
ds_list = (TestSHP('test_point', nfeat=5, nfld=3, geom='POINT', gtype=1, fields={'dbl' : OFTReal, 'int' : OFTInteger, 'str' : OFTString,},
|
||||||
extent=(-1.35011,0.166623,-0.524093,0.824508), # Got extent from QGIS
|
extent=(-1.35011,0.166623,-0.524093,0.824508), # Got extent from QGIS
|
||||||
srs_wkt='GEOGCS["GCS_WGS_1984",DATUM["WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]'),
|
srs_wkt='GEOGCS["GCS_WGS_1984",DATUM["WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]'),
|
||||||
TestSHP('test_poly', nfeat=3, nfld=3, geom='POLYGON', gtype=3, fields={'float' : OFTReal, 'int' : OFTReal, 'str' : OFTString,},
|
TestSHP('test_poly', nfeat=3, nfld=3, geom='POLYGON', gtype=3, fields={'float' : OFTReal, 'int' : OFTInteger, 'str' : OFTString,},
|
||||||
extent=(-1.01513,-0.558245,0.161876,0.839637), # Got extent from QGIS
|
extent=(-1.01513,-0.558245,0.161876,0.839637), # Got extent from QGIS
|
||||||
srs_wkt='GEOGCS["GCS_WGS_1984",DATUM["WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]'),
|
srs_wkt='GEOGCS["GCS_WGS_1984",DATUM["WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]'),
|
||||||
)
|
)
|
||||||
@ -101,17 +101,12 @@ class DataSourceTest(unittest.TestCase):
|
|||||||
|
|
||||||
# Making sure the fields match to an appropriate OFT type.
|
# Making sure the fields match to an appropriate OFT type.
|
||||||
for k, v in source.fields.items():
|
for k, v in source.fields.items():
|
||||||
fld = feat[k] # Indexing with string value
|
# Making sure we get the proper OGR Field instance, using
|
||||||
|
# a string value index for the feature.
|
||||||
# Asserting the string representation, and making sure we get
|
self.assertEqual(True, isinstance(feat[k], v))
|
||||||
# the proper OGR Field instance.
|
|
||||||
if isinstance(fld, OFTString): fmt = '%s ("%s")'
|
|
||||||
else: fmt = '%s (%s)'
|
|
||||||
self.assertEqual(fmt % (k, fld.value), str(fld))
|
|
||||||
self.assertEqual(True, isinstance(fld, v))
|
|
||||||
|
|
||||||
# Testing __iter__ on the Feature
|
# Testing __iter__ on the Feature
|
||||||
for fld in feat: self.assertEqual(fld.name in source.fields.keys(), True)
|
for fld in feat: self.assertEqual(True, fld.name in source.fields.keys())
|
||||||
|
|
||||||
def test05_geometries(self):
|
def test05_geometries(self):
|
||||||
"Testing Geometries from Data Source Features."
|
"Testing Geometries from Data Source Features."
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import unittest
|
import unittest
|
||||||
from django.contrib.gis.gdal import OGRGeometry, OGRGeomType, OGRException, SpatialReference
|
from django.contrib.gis.gdal import OGRGeometry, OGRGeomType, \
|
||||||
|
OGRException, OGRIndexError, SpatialReference
|
||||||
from django.contrib.gis.tests.geometries import *
|
from django.contrib.gis.tests.geometries import *
|
||||||
|
|
||||||
class OGRGeomTest(unittest.TestCase):
|
class OGRGeomTest(unittest.TestCase):
|
||||||
@ -94,41 +95,78 @@ class OGRGeomTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test04_linestring(self):
|
def test04_linestring(self):
|
||||||
"Testing LineString objects."
|
"Testing LineString objects."
|
||||||
|
prev = OGRGeometry('POINT(0 0)')
|
||||||
for ls in linestrings:
|
for ls in linestrings:
|
||||||
linestr = OGRGeometry(ls.wkt)
|
linestr = OGRGeometry(ls.wkt)
|
||||||
self.assertEqual(2, linestr.geom_type)
|
self.assertEqual(2, linestr.geom_type)
|
||||||
self.assertEqual('LINESTRING', linestr.geom_name)
|
self.assertEqual('LINESTRING', linestr.geom_name)
|
||||||
self.assertEqual(ls.n_p, linestr.point_count)
|
self.assertEqual(ls.n_p, linestr.point_count)
|
||||||
self.assertEqual(ls.tup, linestr.tuple)
|
self.assertEqual(ls.tup, linestr.tuple)
|
||||||
|
self.assertEqual(True, linestr == OGRGeometry(ls.wkt))
|
||||||
|
self.assertEqual(True, linestr != prev)
|
||||||
|
self.assertRaises(OGRIndexError, linestr.__getitem__, len(linestr))
|
||||||
|
prev = linestr
|
||||||
|
|
||||||
def test05_multilinestring(self):
|
def test05_multilinestring(self):
|
||||||
"Testing MultiLineString objects."
|
"Testing MultiLineString objects."
|
||||||
|
prev = OGRGeometry('POINT(0 0)')
|
||||||
for mls in multilinestrings:
|
for mls in multilinestrings:
|
||||||
mlinestr = OGRGeometry(mls.wkt)
|
mlinestr = OGRGeometry(mls.wkt)
|
||||||
self.assertEqual(5, mlinestr.geom_type)
|
self.assertEqual(5, mlinestr.geom_type)
|
||||||
self.assertEqual('MULTILINESTRING', mlinestr.geom_name)
|
self.assertEqual('MULTILINESTRING', mlinestr.geom_name)
|
||||||
self.assertEqual(mls.n_p, mlinestr.point_count)
|
self.assertEqual(mls.n_p, mlinestr.point_count)
|
||||||
self.assertEqual(mls.tup, mlinestr.tuple)
|
self.assertEqual(mls.tup, mlinestr.tuple)
|
||||||
|
self.assertEqual(True, mlinestr == OGRGeometry(mls.wkt))
|
||||||
|
self.assertEqual(True, mlinestr != prev)
|
||||||
|
prev = mlinestr
|
||||||
|
for ls in mlinestr:
|
||||||
|
self.assertEqual(2, ls.geom_type)
|
||||||
|
self.assertEqual('LINESTRING', ls.geom_name)
|
||||||
|
self.assertRaises(OGRIndexError, mlinestr.__getitem__, len(mlinestr))
|
||||||
|
|
||||||
def test06_polygons(self):
|
def test06_linearring(self):
|
||||||
|
"Testing LinearRing objects."
|
||||||
|
prev = OGRGeometry('POINT(0 0)')
|
||||||
|
for rr in linearrings:
|
||||||
|
lr = OGRGeometry(rr.wkt)
|
||||||
|
#self.assertEqual(101, lr.geom_type.num)
|
||||||
|
self.assertEqual('LINEARRING', lr.geom_name)
|
||||||
|
self.assertEqual(rr.n_p, len(lr))
|
||||||
|
self.assertEqual(True, lr == OGRGeometry(rr.wkt))
|
||||||
|
self.assertEqual(True, lr != prev)
|
||||||
|
prev = lr
|
||||||
|
|
||||||
|
def test07a_polygons(self):
|
||||||
"Testing Polygon objects."
|
"Testing Polygon objects."
|
||||||
|
prev = OGRGeometry('POINT(0 0)')
|
||||||
for p in polygons:
|
for p in polygons:
|
||||||
poly = OGRGeometry(p.wkt)
|
poly = OGRGeometry(p.wkt)
|
||||||
self.assertEqual(3, poly.geom_type)
|
self.assertEqual(3, poly.geom_type)
|
||||||
self.assertEqual('POLYGON', poly.geom_name)
|
self.assertEqual('POLYGON', poly.geom_name)
|
||||||
self.assertEqual(p.n_p, poly.point_count)
|
self.assertEqual(p.n_p, poly.point_count)
|
||||||
first = True
|
self.assertEqual(p.n_i + 1, len(poly))
|
||||||
|
|
||||||
|
# Testing area & centroid.
|
||||||
|
self.assertAlmostEqual(p.area, poly.area, 9)
|
||||||
|
x, y = poly.centroid.tuple
|
||||||
|
self.assertAlmostEqual(p.centroid[0], x, 9)
|
||||||
|
self.assertAlmostEqual(p.centroid[1], y, 9)
|
||||||
|
|
||||||
|
# Testing equivalence
|
||||||
|
self.assertEqual(True, poly == OGRGeometry(p.wkt))
|
||||||
|
self.assertEqual(True, poly != prev)
|
||||||
|
|
||||||
|
if p.ext_ring_cs:
|
||||||
|
ring = poly[0]
|
||||||
|
self.assertEqual(p.ext_ring_cs, ring.tuple)
|
||||||
|
self.assertEqual(p.ext_ring_cs, poly[0].tuple)
|
||||||
|
self.assertEqual(len(p.ext_ring_cs), ring.point_count)
|
||||||
|
|
||||||
for r in poly:
|
for r in poly:
|
||||||
if first and p.ext_ring_cs:
|
self.assertEqual('LINEARRING', r.geom_name)
|
||||||
first = False
|
|
||||||
# Testing the equivilance of the exerior rings
|
|
||||||
# since the first iteration will be the exterior ring.
|
|
||||||
self.assertEqual(len(p.ext_ring_cs), r.point_count)
|
|
||||||
self.assertEqual(p.ext_ring_cs, r.tuple)
|
|
||||||
|
|
||||||
def test07_closepolygons(self):
|
def test07b_closepolygons(self):
|
||||||
"Testing closing Polygon objects."
|
"Testing closing Polygon objects."
|
||||||
|
|
||||||
# Both rings in this geometry are not closed.
|
# Both rings in this geometry are not closed.
|
||||||
poly = OGRGeometry('POLYGON((0 0, 5 0, 5 5, 0 5), (1 1, 2 1, 2 2, 2 1))')
|
poly = OGRGeometry('POLYGON((0 0, 5 0, 5 5, 0 5), (1 1, 2 1, 2 2, 2 1))')
|
||||||
self.assertEqual(8, poly.point_count)
|
self.assertEqual(8, poly.point_count)
|
||||||
@ -149,6 +187,7 @@ class OGRGeomTest(unittest.TestCase):
|
|||||||
|
|
||||||
def test08_multipolygons(self):
|
def test08_multipolygons(self):
|
||||||
"Testing MultiPolygon objects."
|
"Testing MultiPolygon objects."
|
||||||
|
prev = OGRGeometry('POINT(0 0)')
|
||||||
for mp in multipolygons:
|
for mp in multipolygons:
|
||||||
mpoly = OGRGeometry(mp.wkt)
|
mpoly = OGRGeometry(mp.wkt)
|
||||||
self.assertEqual(6, mpoly.geom_type)
|
self.assertEqual(6, mpoly.geom_type)
|
||||||
@ -156,27 +195,53 @@ class OGRGeomTest(unittest.TestCase):
|
|||||||
if mp.valid:
|
if mp.valid:
|
||||||
self.assertEqual(mp.n_p, mpoly.point_count)
|
self.assertEqual(mp.n_p, mpoly.point_count)
|
||||||
self.assertEqual(mp.num_geom, len(mpoly))
|
self.assertEqual(mp.num_geom, len(mpoly))
|
||||||
|
self.assertRaises(OGRIndexError, mpoly.__getitem__, len(mpoly))
|
||||||
|
for p in mpoly:
|
||||||
|
self.assertEqual('POLYGON', p.geom_name)
|
||||||
|
self.assertEqual(3, p.geom_type)
|
||||||
|
self.assertEqual(mpoly.wkt, OGRGeometry(mp.wkt).wkt)
|
||||||
|
|
||||||
def test09_srs(self):
|
def test09_srs(self):
|
||||||
"Testing OGR Geometries with Spatial Reference objects."
|
"Testing OGR Geometries with Spatial Reference objects."
|
||||||
for mp in multipolygons:
|
for mp in multipolygons:
|
||||||
|
# Creating a geometry w/spatial reference
|
||||||
sr = SpatialReference('WGS84')
|
sr = SpatialReference('WGS84')
|
||||||
mpoly = OGRGeometry(mp.wkt, sr)
|
mpoly = OGRGeometry(mp.wkt, sr)
|
||||||
self.assertEqual(sr.wkt, mpoly.srs.wkt)
|
self.assertEqual(sr.wkt, mpoly.srs.wkt)
|
||||||
|
|
||||||
|
# Ensuring that SRS is propagated to clones.
|
||||||
|
klone = mpoly.clone()
|
||||||
|
self.assertEqual(sr.wkt, klone.srs.wkt)
|
||||||
|
|
||||||
|
# Ensuring all children geometries (polygons and their rings) all
|
||||||
|
# return the assigned spatial reference as well.
|
||||||
for poly in mpoly:
|
for poly in mpoly:
|
||||||
self.assertEqual(sr.wkt, poly.srs.wkt)
|
self.assertEqual(sr.wkt, poly.srs.wkt)
|
||||||
for ring in poly:
|
for ring in poly:
|
||||||
self.assertEqual(sr.wkt, ring.srs.wkt)
|
self.assertEqual(sr.wkt, ring.srs.wkt)
|
||||||
|
|
||||||
|
# Ensuring SRS propagate in topological ops.
|
||||||
|
a, b = topology_geoms[0]
|
||||||
|
a, b = OGRGeometry(a.wkt, sr), OGRGeometry(b.wkt, sr)
|
||||||
|
diff = a.difference(b)
|
||||||
|
union = a.union(b)
|
||||||
|
self.assertEqual(sr.wkt, diff.srs.wkt)
|
||||||
|
self.assertEqual(sr.srid, union.srs.srid)
|
||||||
|
|
||||||
|
# Instantiating w/an integer SRID
|
||||||
mpoly = OGRGeometry(mp.wkt, 4326)
|
mpoly = OGRGeometry(mp.wkt, 4326)
|
||||||
self.assertEqual(4326, mpoly.srid)
|
self.assertEqual(4326, mpoly.srid)
|
||||||
mpoly.srs = SpatialReference(4269)
|
mpoly.srs = SpatialReference(4269)
|
||||||
self.assertEqual(4269, mpoly.srid)
|
self.assertEqual(4269, mpoly.srid)
|
||||||
self.assertEqual('NAD83', mpoly.srs.name)
|
self.assertEqual('NAD83', mpoly.srs.name)
|
||||||
|
|
||||||
|
# Incrementing through the multipolyogn after the spatial reference
|
||||||
|
# has been re-assigned.
|
||||||
for poly in mpoly:
|
for poly in mpoly:
|
||||||
self.assertEqual(mpoly.srs.wkt, poly.srs.wkt)
|
self.assertEqual(mpoly.srs.wkt, poly.srs.wkt)
|
||||||
poly.srs = 32140
|
poly.srs = 32140
|
||||||
for ring in poly:
|
for ring in poly:
|
||||||
|
# Changing each ring in the polygon
|
||||||
self.assertEqual(32140, ring.srs.srid)
|
self.assertEqual(32140, ring.srs.srid)
|
||||||
self.assertEqual('NAD83 / Texas South Central', ring.srs.name)
|
self.assertEqual('NAD83 / Texas South Central', ring.srs.name)
|
||||||
ring.srs = str(SpatialReference(4326)) # back to WGS84
|
ring.srs = str(SpatialReference(4326)) # back to WGS84
|
||||||
@ -187,7 +252,58 @@ class OGRGeomTest(unittest.TestCase):
|
|||||||
self.assertEqual('WGS 72', ring.srs.name)
|
self.assertEqual('WGS 72', ring.srs.name)
|
||||||
self.assertEqual(4322, ring.srid)
|
self.assertEqual(4322, ring.srid)
|
||||||
|
|
||||||
|
def test10_difference(self):
|
||||||
|
"Testing difference()."
|
||||||
|
for i in xrange(len(topology_geoms)):
|
||||||
|
g_tup = topology_geoms[i]
|
||||||
|
a = OGRGeometry(g_tup[0].wkt)
|
||||||
|
b = OGRGeometry(g_tup[1].wkt)
|
||||||
|
d1 = OGRGeometry(diff_geoms[i].wkt)
|
||||||
|
d2 = a.difference(b)
|
||||||
|
self.assertEqual(d1, d2)
|
||||||
|
self.assertEqual(d1, a - b) # __sub__ is difference operator
|
||||||
|
a -= b # testing __isub__
|
||||||
|
self.assertEqual(d1, a)
|
||||||
|
|
||||||
|
def test11_intersection(self):
|
||||||
|
"Testing intersects() and intersection()."
|
||||||
|
for i in xrange(len(topology_geoms)):
|
||||||
|
g_tup = topology_geoms[i]
|
||||||
|
a = OGRGeometry(g_tup[0].wkt)
|
||||||
|
b = OGRGeometry(g_tup[1].wkt)
|
||||||
|
i1 = OGRGeometry(intersect_geoms[i].wkt)
|
||||||
|
self.assertEqual(True, a.intersects(b))
|
||||||
|
i2 = a.intersection(b)
|
||||||
|
self.assertEqual(i1, i2)
|
||||||
|
self.assertEqual(i1, a & b) # __and__ is intersection operator
|
||||||
|
a &= b # testing __iand__
|
||||||
|
self.assertEqual(i1, a)
|
||||||
|
|
||||||
|
def test12_symdifference(self):
|
||||||
|
"Testing sym_difference()."
|
||||||
|
for i in xrange(len(topology_geoms)):
|
||||||
|
g_tup = topology_geoms[i]
|
||||||
|
a = OGRGeometry(g_tup[0].wkt)
|
||||||
|
b = OGRGeometry(g_tup[1].wkt)
|
||||||
|
d1 = OGRGeometry(sdiff_geoms[i].wkt)
|
||||||
|
d2 = a.sym_difference(b)
|
||||||
|
self.assertEqual(d1, d2)
|
||||||
|
self.assertEqual(d1, a ^ b) # __xor__ is symmetric difference operator
|
||||||
|
a ^= b # testing __ixor__
|
||||||
|
self.assertEqual(d1, a)
|
||||||
|
|
||||||
|
def test13_union(self):
|
||||||
|
"Testing union()."
|
||||||
|
for i in xrange(len(topology_geoms)):
|
||||||
|
g_tup = topology_geoms[i]
|
||||||
|
a = OGRGeometry(g_tup[0].wkt)
|
||||||
|
b = OGRGeometry(g_tup[1].wkt)
|
||||||
|
u1 = OGRGeometry(union_geoms[i].wkt)
|
||||||
|
u2 = a.union(b)
|
||||||
|
self.assertEqual(u1, u2)
|
||||||
|
self.assertEqual(u1, a | b) # __or__ is union operator
|
||||||
|
a |= b # testing __ior__
|
||||||
|
self.assertEqual(u1, a)
|
||||||
|
|
||||||
def suite():
|
def suite():
|
||||||
s = unittest.TestSuite()
|
s = unittest.TestSuite()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user