mirror of
https://github.com/django/django.git
synced 2025-07-04 01:39:20 +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
@ -21,8 +21,8 @@
|
||||
SpatialReference: Represents OSR Spatial Reference objects.
|
||||
"""
|
||||
# Attempting to import objects that depend on the GDAL library. The
|
||||
# HAS_GDAL flag will be set to True if the library is present on
|
||||
# the system.
|
||||
# HAS_GDAL flag will be set to True if the library is present on
|
||||
# the system.
|
||||
try:
|
||||
from django.contrib.gis.gdal.driver import Driver
|
||||
from django.contrib.gis.gdal.datasource import DataSource
|
||||
|
@ -1,105 +1,113 @@
|
||||
# types and ctypes
|
||||
from types import StringType
|
||||
from ctypes import c_char_p, c_int, c_void_p, byref, string_at
|
||||
"""
|
||||
DataSource is a wrapper for the OGR Data Source object, which provides
|
||||
an interface for reading vector geometry data from many different file
|
||||
formats (including ESRI shapefiles).
|
||||
|
||||
When instantiating a DataSource object, use the filename of a
|
||||
GDAL-supported data source. For example, a SHP file or a
|
||||
TIGER/Line file from the government.
|
||||
|
||||
The ds_driver keyword is used internally when a ctypes pointer
|
||||
is passed in directly.
|
||||
|
||||
Example:
|
||||
ds = DataSource('/home/foo/bar.shp')
|
||||
for layer in ds:
|
||||
for feature in layer:
|
||||
# Getting the geometry for the feature.
|
||||
g = feature.geom
|
||||
|
||||
# Getting the 'description' field for the feature.
|
||||
desc = feature['description']
|
||||
|
||||
# We can also increment through all of the fields
|
||||
# attached to this feature.
|
||||
for field in feature:
|
||||
# Get the name of the field (e.g. 'description')
|
||||
nm = field.name
|
||||
|
||||
# Get the type (integer) of the field, e.g. 0 => OFTInteger
|
||||
t = field.type
|
||||
|
||||
# Returns the value the field; OFTIntegers return ints,
|
||||
# OFTReal returns floats, all else returns string.
|
||||
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.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
|
||||
from django.contrib.gis.gdal.error import OGRException, OGRIndexError
|
||||
from django.contrib.gis.gdal.layer import Layer
|
||||
|
||||
"""
|
||||
DataSource is a wrapper for the OGR Data Source object, which provides
|
||||
an interface for reading vector geometry data from many different file
|
||||
formats (including ESRI shapefiles).
|
||||
|
||||
When instantiating a DataSource object, use the filename of a
|
||||
GDAL-supported data source. For example, a SHP file or a
|
||||
TIGER/Line file from the government.
|
||||
|
||||
The ds_driver keyword is used internally when a ctypes pointer
|
||||
is passed in directly.
|
||||
|
||||
Example:
|
||||
ds = DataSource('/home/foo/bar.shp')
|
||||
for layer in ds:
|
||||
for feature in layer:
|
||||
# Getting the geometry for the feature.
|
||||
g = feature.geom
|
||||
|
||||
# Getting the 'description' field for the feature.
|
||||
desc = feature['description']
|
||||
|
||||
# We can also increment through all of the fields
|
||||
# attached to this feature.
|
||||
for field in feature:
|
||||
# Get the name of the field (e.g. 'description')
|
||||
nm = field.name
|
||||
|
||||
# Get the type (integer) of the field, e.g. 0 => OFTInteger
|
||||
t = field.type
|
||||
|
||||
# Returns the value the field; OFTIntegers return ints,
|
||||
# OFTReal returns floats, all else returns string.
|
||||
val = field.value
|
||||
"""
|
||||
# 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:
|
||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
||||
#
|
||||
# The OGR_DS_* routines are relevant here.
|
||||
|
||||
class DataSource(object):
|
||||
"Wraps an OGR Data Source object."
|
||||
|
||||
#### 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
|
||||
# _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!')
|
||||
|
||||
if isinstance(ds_input, StringType):
|
||||
|
||||
if isinstance(ds_input, basestring):
|
||||
# The data source driver is a void pointer.
|
||||
ds_driver = c_void_p()
|
||||
|
||||
# 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):
|
||||
ds = ds_input
|
||||
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 not ds:
|
||||
self._ds = False
|
||||
raise OGRException('Invalid data source file "%s"' % ds_input)
|
||||
else:
|
||||
self._ds = ds
|
||||
if bool(ds):
|
||||
self._ptr = ds
|
||||
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):
|
||||
"This releases the reference to the data source (destroying it if it's the only one)."
|
||||
if self._ds: lgdal.OGRReleaseDataSource(self._ds)
|
||||
"Destroys this DataStructure object."
|
||||
if self._ptr: destroy_ds(self._ptr)
|
||||
|
||||
def __iter__(self):
|
||||
"Allows for iteration over the layers in a data source."
|
||||
for i in xrange(self.layer_count):
|
||||
yield self.__getitem__(i)
|
||||
yield self[i]
|
||||
|
||||
def __getitem__(self, index):
|
||||
"Allows use of the index [] operator to get a layer at the index."
|
||||
if isinstance(index, StringType):
|
||||
l = lgdal.OGR_DS_GetLayerByName(self._ds, c_char_p(index))
|
||||
if isinstance(index, basestring):
|
||||
l = get_layer_by_name(self._ptr, 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:
|
||||
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)
|
||||
|
||||
def __len__(self):
|
||||
@ -119,10 +127,9 @@ class DataSource(object):
|
||||
@property
|
||||
def layer_count(self):
|
||||
"Returns the number of layers in the data source."
|
||||
return lgdal.OGR_DS_GetLayerCount(self._ds)
|
||||
return get_layer_count(self._ptr)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"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
|
||||
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
|
||||
# prerequisites imports
|
||||
from ctypes import c_void_p
|
||||
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:
|
||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
||||
#
|
||||
# The OGR_Dr_* routines are relevant here.
|
||||
|
||||
class Driver(object):
|
||||
"Wraps an OGR Data Source Driver."
|
||||
|
||||
@ -22,64 +19,49 @@ class Driver(object):
|
||||
'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."
|
||||
|
||||
if isinstance(input, StringType):
|
||||
if isinstance(dr_input, basestring):
|
||||
# If a string name of the driver was passed in
|
||||
self._dr = None # Initially NULL
|
||||
self._ptr = None # Initially NULL
|
||||
self._register()
|
||||
|
||||
# Checking the alias dictionary (case-insensitive) to see if an alias
|
||||
# exists for the given driver.
|
||||
if input.lower() in self._alias:
|
||||
name = c_char_p(self._alias[input.lower()])
|
||||
if dr_input.lower() in self._alias:
|
||||
name = self._alias[dr_input.lower()]
|
||||
else:
|
||||
name = c_char_p(input)
|
||||
name = dr_input
|
||||
|
||||
# Attempting to get the OGR driver by the string name.
|
||||
dr = lgdal.OGRGetDriverByName(name)
|
||||
elif isinstance(input, int):
|
||||
dr = get_driver_by_name(name)
|
||||
elif isinstance(dr_input, int):
|
||||
self._register()
|
||||
dr = lgdal.OGRGetDriver(c_int(input))
|
||||
elif isinstance(input, c_void_p):
|
||||
dr = input
|
||||
dr = get_driver(dr_input)
|
||||
elif isinstance(dr_input, c_void_p):
|
||||
dr = dr_input
|
||||
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
|
||||
if not dr:
|
||||
raise OGRException('Could not initialize OGR Driver on input: %s' % str(input))
|
||||
self._dr = dr
|
||||
raise OGRException('Could not initialize OGR Driver on input: %s' % str(dr_input))
|
||||
self._ptr = dr
|
||||
|
||||
def __str__(self):
|
||||
"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):
|
||||
"Attempts to register all the data source drivers."
|
||||
# Only register all if the driver count is 0 (or else all drivers
|
||||
# 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!')
|
||||
|
||||
# Driver properties
|
||||
@property
|
||||
def driver_count(self):
|
||||
"Returns the number of OGR data source drivers registered."
|
||||
return lgdal.OGRGetDriverCount()
|
||||
|
||||
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)
|
||||
|
||||
|
||||
|
||||
|
||||
return get_driver_count()
|
||||
|
@ -1,15 +1,14 @@
|
||||
"""
|
||||
The GDAL/OGR library uses an Envelope structure to hold the bounding
|
||||
box information for a geometry. The envelope (bounding box) contains
|
||||
two pairs of coordinates, one for the lower left coordinate and one
|
||||
for the upper right coordinate:
|
||||
box information for a geometry. The envelope (bounding box) contains
|
||||
two pairs of coordinates, one for the lower left coordinate and one
|
||||
for the upper right coordinate:
|
||||
|
||||
+----------o Upper right; (max_x, max_y)
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
Lower left (min_x, min_y) o----------+
|
||||
|
||||
+----------o Upper right; (max_x, max_y)
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
Lower left (min_x, min_y) o----------+
|
||||
"""
|
||||
from ctypes import Structure, c_double
|
||||
from types import TupleType, ListType
|
||||
@ -29,14 +28,14 @@ class OGREnvelope(Structure):
|
||||
class Envelope(object):
|
||||
"""
|
||||
The Envelope object is a C structure that contains the minimum and
|
||||
maximum X, Y coordinates for a rectangle bounding box. The naming
|
||||
of the variables is compatible with the OGR Envelope structure.
|
||||
maximum X, Y coordinates for a rectangle bounding box. The naming
|
||||
of the variables is compatible with the OGR Envelope structure.
|
||||
"""
|
||||
|
||||
def __init__(self, *args):
|
||||
"""
|
||||
The initialization function may take an OGREnvelope structure, 4-element
|
||||
tuple or list, or 4 individual arguments.
|
||||
tuple or list, or 4 individual arguments.
|
||||
"""
|
||||
|
||||
if len(args) == 1:
|
||||
|
@ -1,10 +1,9 @@
|
||||
"""
|
||||
This module houses the OGR & SRS Exception objects, and the
|
||||
check_err() routine which checks the status code returned by
|
||||
OGR methods.
|
||||
This module houses the OGR & SRS Exception objects, and the
|
||||
check_err() routine which checks the status code returned by
|
||||
OGR methods.
|
||||
"""
|
||||
|
||||
# OGR & SRS Exceptions
|
||||
#### OGR & SRS Exceptions ####
|
||||
class OGRException(Exception): pass
|
||||
class SRSException(Exception): pass
|
||||
class OGRIndexError(OGRException, KeyError):
|
||||
@ -16,6 +15,8 @@ class OGRIndexError(OGRException, KeyError):
|
||||
"""
|
||||
silent_variable_failure = True
|
||||
|
||||
#### OGR error checking codes and routine ####
|
||||
|
||||
# OGR Error Codes
|
||||
OGRERR_DICT = { 1 : (OGRException, 'Not enough data.'),
|
||||
2 : (OGRException, 'Not enough memory.'),
|
||||
@ -36,4 +37,4 @@ def check_err(code):
|
||||
e, msg = OGRERR_DICT[code]
|
||||
raise e, msg
|
||||
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
|
||||
from django.contrib.gis.gdal.libgdal import lgdal
|
||||
from django.contrib.gis.gdal.error import OGRException, OGRIndexError
|
||||
from django.contrib.gis.gdal.field import Field
|
||||
from django.contrib.gis.gdal.geometries import OGRGeometry, OGRGeomType
|
||||
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:
|
||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
||||
#
|
||||
@ -18,33 +21,31 @@ class Feature(object):
|
||||
|
||||
#### Python 'magic' routines ####
|
||||
def __init__(self, feat, fdefn):
|
||||
"Needs a C pointer (Python integer in ctypes) in order to initialize."
|
||||
self._feat = None # Initially NULL
|
||||
self._fdefn = None
|
||||
"Initializes on the pointers for the feature and the layer definition."
|
||||
self._ptr = None # Initially NULL
|
||||
if not feat or not fdefn:
|
||||
raise OGRException('Cannot create OGR Feature, invalid pointer given.')
|
||||
self._feat = feat
|
||||
self._ptr = feat
|
||||
self._fdefn = fdefn
|
||||
|
||||
def __del__(self):
|
||||
"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):
|
||||
"Gets the Field at the specified index."
|
||||
if isinstance(index, StringType):
|
||||
if isinstance(index, basestring):
|
||||
i = self.index(index)
|
||||
else:
|
||||
if index < 0 or index > self.num_fields:
|
||||
raise OGRIndexError('index out of range')
|
||||
i = index
|
||||
return Field(lgdal.OGR_F_GetFieldDefnRef(self._feat, c_int(i)),
|
||||
string_at(lgdal.OGR_F_GetFieldAsString(self._feat, c_int(i))))
|
||||
return Field(self._ptr, i)
|
||||
|
||||
def __iter__(self):
|
||||
"Iterates over each field in the Feature."
|
||||
for i in xrange(self.num_fields):
|
||||
yield self.__getitem__(i)
|
||||
yield self[i]
|
||||
|
||||
def __len__(self):
|
||||
"Returns the count of fields in this feature."
|
||||
@ -56,54 +57,49 @@ class Feature(object):
|
||||
|
||||
def __eq__(self, other):
|
||||
"Does equivalence testing on the features."
|
||||
if lgdal.OGR_F_Equal(self._feat, other._feat):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return bool(feature_equal(self._ptr, other._ptr))
|
||||
|
||||
#### Feature Properties ####
|
||||
@property
|
||||
def fid(self):
|
||||
"Returns the feature identifier."
|
||||
return lgdal.OGR_F_GetFID(self._feat)
|
||||
return get_fid(self._ptr)
|
||||
|
||||
@property
|
||||
def layer_name(self):
|
||||
"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
|
||||
def num_fields(self):
|
||||
"Returns the number of fields in the Feature."
|
||||
return lgdal.OGR_F_GetFieldCount(self._feat)
|
||||
return get_feat_field_count(self._ptr)
|
||||
|
||||
@property
|
||||
def fields(self):
|
||||
"Returns a list of fields in the Feature."
|
||||
return [ string_at(lgdal.OGR_Fld_GetNameRef(lgdal.OGR_FD_GetFieldDefn(self._fdefn, i)))
|
||||
for i in xrange(self.num_fields) ]
|
||||
return [get_field_name(get_field_defn(self._fdefn, i))
|
||||
for i in xrange(self.num_fields)]
|
||||
|
||||
@property
|
||||
def geom(self):
|
||||
"Returns the OGR Geometry for this Feature."
|
||||
# Retrieving the geometry pointer for the feature.
|
||||
geom_ptr = lgdal.OGR_F_GetGeometryRef(self._feat)
|
||||
if not geom_ptr:
|
||||
raise OGRException('Cannot retrieve Geometry from the feature.')
|
||||
geom_ptr = get_feat_geom_ref(self._ptr)
|
||||
|
||||
# Attempting to retrieve the Spatial Reference for the geometry.
|
||||
srs_ptr = lgdal.OSRClone(lgdal.OGR_G_GetSpatialReference(geom_ptr))
|
||||
if srs_ptr:
|
||||
srs = SpatialReference(srs_ptr, 'ogr')
|
||||
else:
|
||||
try:
|
||||
srs_ptr = get_geom_srs(geom_ptr)
|
||||
srs = SpatialReference(clone_srs(srs_ptr))
|
||||
except OGRException:
|
||||
srs = None
|
||||
|
||||
# Geometry is cloned so the feature isn't invalidated.
|
||||
return OGRGeometry(c_void_p(lgdal.OGR_G_Clone(geom_ptr)), srs)
|
||||
|
||||
# Geometry is cloned so the feature isn't invalidated.
|
||||
return OGRGeometry(clone_geom(geom_ptr), srs)
|
||||
|
||||
@property
|
||||
def geom_type(self):
|
||||
"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 ####
|
||||
def get(self, field):
|
||||
@ -113,14 +109,10 @@ class Feature(object):
|
||||
parameters.
|
||||
"""
|
||||
field_name = getattr(field, 'name', field)
|
||||
return self.__getitem__(field_name).value
|
||||
return self[field_name].value
|
||||
|
||||
def index(self, 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)
|
||||
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 django.contrib.gis.gdal.libgdal import lgdal
|
||||
from ctypes import byref, c_int
|
||||
from datetime import date, datetime, time
|
||||
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:
|
||||
# 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."
|
||||
|
||||
#### Python 'magic' routines ####
|
||||
def __init__(self, fld, val=''):
|
||||
"Needs a C pointer (Python integer in ctypes) in order to initialize."
|
||||
self._fld = None # Initially NULL
|
||||
|
||||
def __init__(self, feat, index):
|
||||
"""
|
||||
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:
|
||||
raise OGRException('Cannot create OGR Field, invalid pointer given.')
|
||||
self._fld = fld
|
||||
self._val = val
|
||||
self._ptr = fld
|
||||
|
||||
# Setting the class depending upon the OGR Field Type (OFT)
|
||||
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):
|
||||
"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 ####
|
||||
@property
|
||||
def name(self):
|
||||
"Returns the name of the field."
|
||||
return string_at(lgdal.OGR_Fld_GetNameRef(self._fld))
|
||||
"Returns the name of this Field."
|
||||
return get_field_name(self._ptr)
|
||||
|
||||
@property
|
||||
def precision(self):
|
||||
"Returns the precision of this Field."
|
||||
return get_field_precision(self._ptr)
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"Returns the type of this field."
|
||||
return lgdal.OGR_Fld_GetType(self._fld)
|
||||
"Returns the OGR type of this Field."
|
||||
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
|
||||
def value(self):
|
||||
"Returns the value of this type of field."
|
||||
return self._val
|
||||
"Returns the value of this Field."
|
||||
# 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):
|
||||
@property
|
||||
def value(self):
|
||||
"Returns an integer contained in this field."
|
||||
try:
|
||||
return int(self._val)
|
||||
except ValueError:
|
||||
return None
|
||||
class OFTIntegerList(Field): pass
|
||||
return self.as_int()
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"""
|
||||
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):
|
||||
@property
|
||||
def value(self):
|
||||
"Returns a float contained in this field."
|
||||
try:
|
||||
return float(self._val)
|
||||
except ValueError:
|
||||
return None
|
||||
class OFTRealList(Field): pass
|
||||
return self.as_double()
|
||||
|
||||
class OFTString(Field):
|
||||
def __str__(self):
|
||||
return '%s ("%s")' % (self.name, self.value)
|
||||
|
||||
class OFTStringList(Field): pass
|
||||
# String & Binary fields, just subclasses
|
||||
class OFTString(Field): pass
|
||||
class OFTWideString(Field): pass
|
||||
class OFTWideStringList(Field): pass
|
||||
class OFTBinary(Field): pass
|
||||
class OFTDate(Field): pass
|
||||
class OFTTime(Field): pass
|
||||
class OFTDateTime(Field): pass
|
||||
|
||||
# OFTDate, OFTTime, OFTDateTime fields.
|
||||
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
|
||||
FIELD_CLASSES = { 0 : OFTInteger,
|
||||
|
@ -1,79 +1,67 @@
|
||||
"""
|
||||
The OGRGeometry is a wrapper for using the OGR Geometry class
|
||||
(see http://www.gdal.org/ogr/classOGRGeometry.html). OGRGeometry
|
||||
may be instantiated when reading geometries from OGR Data Sources
|
||||
(e.g. SHP files), or when given OGC WKT (a string).
|
||||
The OGRGeometry is a wrapper for using the OGR Geometry class
|
||||
(see http://www.gdal.org/ogr/classOGRGeometry.html). OGRGeometry
|
||||
may be instantiated when reading geometries from OGR Data Sources
|
||||
(e.g. SHP files), or when given OGC WKT (a string).
|
||||
|
||||
While the 'full' API is not present yet, the API is "pythonic" unlike
|
||||
the traditional and "next-generation" OGR Python bindings. One major
|
||||
advantage OGR Geometries have over their GEOS counterparts is support
|
||||
for spatial reference systems and their transformation.
|
||||
While the 'full' API is not present yet, the API is "pythonic" unlike
|
||||
the traditional and "next-generation" OGR Python bindings. One major
|
||||
advantage OGR Geometries have over their GEOS counterparts is support
|
||||
for spatial reference systems and their transformation.
|
||||
|
||||
Example:
|
||||
>>> from django.contrib.gis.gdal import OGRGeometry, OGRGeomType, SpatialReference
|
||||
>>> wkt1, wkt2 = 'POINT(-90 30)', 'POLYGON((0 0, 5 0, 5 5, 0 5)'
|
||||
>>> pnt = OGRGeometry(wkt1)
|
||||
>>> print pnt
|
||||
POINT (-90 30)
|
||||
>>> mpnt = OGRGeometry(OGRGeomType('MultiPoint'), SpatialReference('WGS84'))
|
||||
>>> mpnt.add(wkt1)
|
||||
>>> mpnt.add(wkt1)
|
||||
>>> print mpnt
|
||||
MULTIPOINT (-90 30,-90 30)
|
||||
>>> print mpnt.srs.name
|
||||
WGS 84
|
||||
>>> print mpnt.srs.proj
|
||||
+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs
|
||||
>>> mpnt.transform_to(SpatialReference('NAD27'))
|
||||
>>> print mpnt.proj
|
||||
+proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs
|
||||
>>> print mpnt
|
||||
MULTIPOINT (-89.999930378602485 29.999797886557641,-89.999930378602485 29.999797886557641)
|
||||
|
||||
Example:
|
||||
>>> from django.contrib.gis.gdal import OGRGeometry, OGRGeomType, SpatialReference
|
||||
>>> wkt1, wkt2 = 'POINT(-90 30)', 'POLYGON((0 0, 5 0, 5 5, 0 5)'
|
||||
>>> pnt = OGRGeometry(wkt1)
|
||||
>>> print pnt
|
||||
POINT (-90 30)
|
||||
>>> mpnt = OGRGeometry(OGRGeomType('MultiPoint'), SpatialReference('WGS84'))
|
||||
>>> mpnt.add(wkt1)
|
||||
>>> mpnt.add(wkt1)
|
||||
>>> print mpnt
|
||||
MULTIPOINT (-90 30,-90 30)
|
||||
>>> print mpnt.srs.name
|
||||
WGS 84
|
||||
>>> print mpnt.srs.proj
|
||||
+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs
|
||||
>>> mpnt.transform_to(SpatialReference('NAD27'))
|
||||
>>> print mpnt.proj
|
||||
+proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs
|
||||
>>> print mpnt
|
||||
MULTIPOINT (-89.999930378602485 29.999797886557641,-89.999930378602485 29.999797886557641)
|
||||
|
||||
The OGRGeomType class is to make it easy to specify an OGR geometry type:
|
||||
>>> from django.contrib.gis.gdal import OGRGeomType
|
||||
>>> gt1 = OGRGeomType(3) # Using an integer for the type
|
||||
>>> gt2 = OGRGeomType('Polygon') # Using a string
|
||||
>>> gt3 = OGRGeomType('POLYGON') # It's case-insensitive
|
||||
>>> print gt1 == 3, gt1 == 'Polygon' # Equivalence works w/non-OGRGeomType objects
|
||||
True
|
||||
>>> from django.contrib.gis.gdal import OGRGeomType
|
||||
>>> gt1 = OGRGeomType(3) # Using an integer for the type
|
||||
>>> gt2 = OGRGeomType('Polygon') # Using a string
|
||||
>>> gt3 = OGRGeomType('POLYGON') # It's case-insensitive
|
||||
>>> print gt1 == 3, gt1 == 'Polygon' # Equivalence works w/non-OGRGeomType objects
|
||||
True
|
||||
"""
|
||||
# Python library imports
|
||||
# Python library requisites.
|
||||
import re, sys
|
||||
from binascii import a2b_hex, b2a_hex
|
||||
from ctypes import byref, create_string_buffer, string_at, c_char_p, c_double, c_int, c_void_p
|
||||
from binascii import a2b_hex
|
||||
from ctypes import byref, string_at, c_char_p, c_double, c_ubyte, c_void_p
|
||||
from types import BufferType, IntType, StringType, UnicodeType
|
||||
|
||||
# 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.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.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:
|
||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
||||
#
|
||||
# The OGR_G_* routines are relevant here.
|
||||
|
||||
#### ctypes prototypes for functions that return double values ####
|
||||
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.
|
||||
# Regular expressions for recognizing HEXEWKB and WKT.
|
||||
hex_regex = re.compile(r'^[0-9A-F]+$', re.I)
|
||||
wkt_regex = re.compile(r'^(?P<type>POINT|LINESTRING|LINEARRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)[ACEGIMLONPSRUTY\d,\.\-\(\) ]+$', re.I)
|
||||
|
||||
#### OGRGeometry Class ####
|
||||
class OGRGeometry(object):
|
||||
@ -82,7 +70,7 @@ class OGRGeometry(object):
|
||||
def __init__(self, geom_input, srs=None):
|
||||
"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
|
||||
if isinstance(geom_input, UnicodeType):
|
||||
@ -94,52 +82,47 @@ class OGRGeometry(object):
|
||||
geom_input = buffer(a2b_hex(geom_input.upper()))
|
||||
|
||||
if isinstance(geom_input, StringType):
|
||||
# First, trying the input as WKT
|
||||
buf = c_char_p(geom_input)
|
||||
g = c_void_p()
|
||||
|
||||
try:
|
||||
check_err(lgdal.OGR_G_CreateFromWkt(byref(buf), c_void_p(), byref(g)))
|
||||
except OGRException:
|
||||
try:
|
||||
# Seeing if the input is a valid short-hand string
|
||||
ogr_t = OGRGeomType(geom_input)
|
||||
g = lgdal.OGR_G_CreateGeometry(ogr_t.num)
|
||||
except:
|
||||
raise OGRException('Could not initialize OGR Geometry from: %s' % geom_input)
|
||||
m = wkt_regex.match(geom_input)
|
||||
if m:
|
||||
if m.group('type').upper() == 'LINEARRING':
|
||||
# OGR_G_CreateFromWkt doesn't work with LINEARRING WKT.
|
||||
# See http://trac.osgeo.org/gdal/ticket/1992.
|
||||
g = create_geom(OGRGeomType(m.group('type')).num)
|
||||
import_wkt(g, byref(c_char_p(geom_input)))
|
||||
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
|
||||
# (e.g., 'Point', 'POLYGON').
|
||||
ogr_t = OGRGeomType(geom_input)
|
||||
g = create_geom(OGRGeomType(geom_input).num)
|
||||
elif isinstance(geom_input, BufferType):
|
||||
# WKB was passed in
|
||||
g = c_void_p()
|
||||
check_err(lgdal.OGR_G_CreateFromWkb(c_char_p(str(geom_input)), c_void_p(), byref(g), len(geom_input)))
|
||||
g = from_wkb(str(geom_input), None, byref(c_void_p()), len(geom_input))
|
||||
elif isinstance(geom_input, OGRGeomType):
|
||||
# OGRGeomType was passed in, an empty geometry will be created.
|
||||
g = lgdal.OGR_G_CreateGeometry(geom_input.num)
|
||||
g = create_geom(geom_input.num)
|
||||
elif isinstance(geom_input, c_void_p):
|
||||
# OGR pointer (c_void_p) was the input.
|
||||
g = geom_input
|
||||
else:
|
||||
raise OGRException('Type of input cannot be determined!')
|
||||
|
||||
# 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)
|
||||
raise OGRException('Invalid input type for OGR Geometry construction: %s' % type(geom_input))
|
||||
|
||||
# Now checking the Geometry pointer before finishing initialization
|
||||
# by setting the pointer for the object.
|
||||
if not g:
|
||||
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
|
||||
self.__class__ = GEO_CLASSES[self.geom_type.num]
|
||||
|
||||
def __del__(self):
|
||||
"Deletes this Geometry."
|
||||
if self._g: lgdal.OGR_G_DestroyGeometry(self._g)
|
||||
if self._ptr: destroy_geom(self._ptr)
|
||||
|
||||
### Geometry set-like operations ###
|
||||
# g = g1 | g2
|
||||
@ -178,71 +161,74 @@ class OGRGeometry(object):
|
||||
@property
|
||||
def dimension(self):
|
||||
"Returns 0 for points, 1 for lines, and 2 for surfaces."
|
||||
return lgdal.OGR_G_GetDimension(self._g)
|
||||
return get_dims(self._ptr)
|
||||
|
||||
@property
|
||||
def coord_dim(self):
|
||||
"Returns the coordinate dimension of the Geometry."
|
||||
return lgdal.OGR_G_GetCoordinateDimension(self._g)
|
||||
return get_coord_dims(self._ptr)
|
||||
|
||||
@property
|
||||
def geom_count(self):
|
||||
"The number of elements in this Geometry."
|
||||
return lgdal.OGR_G_GetGeometryCount(self._g)
|
||||
return get_geom_count(self._ptr)
|
||||
|
||||
@property
|
||||
def point_count(self):
|
||||
"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
|
||||
def num_coords(self):
|
||||
"Returns the number of Points in this Geometry."
|
||||
"Alais for `point_count`."
|
||||
return self.point_count
|
||||
|
||||
@property
|
||||
def geom_type(self):
|
||||
"Returns the Type for this Geometry."
|
||||
return OGRGeomType(lgdal.OGR_G_GetGeometryType(self._g))
|
||||
return OGRGeomType(get_geom_type(self._ptr))
|
||||
|
||||
@property
|
||||
def geom_name(self):
|
||||
"Returns the Name of this Geometry."
|
||||
return string_at(lgdal.OGR_G_GetGeometryName(self._g))
|
||||
return get_geom_name(self._ptr)
|
||||
|
||||
@property
|
||||
def area(self):
|
||||
"Returns the area for a LinearRing, Polygon, or MultiPolygon; 0 otherwise."
|
||||
return get_area(self._g)
|
||||
return get_area(self._ptr)
|
||||
|
||||
@property
|
||||
def envelope(self):
|
||||
"Returns the envelope for this Geometry."
|
||||
env = OGREnvelope()
|
||||
lgdal.OGR_G_GetEnvelope(self._g, byref(env))
|
||||
return Envelope(env)
|
||||
return Envelope(get_envelope(self._ptr, byref(OGREnvelope())))
|
||||
|
||||
#### SpatialReference-related Properties ####
|
||||
|
||||
# The SRS property
|
||||
def get_srs(self):
|
||||
"Returns the Spatial Reference for this Geometry."
|
||||
srs_ptr = lgdal.OGR_G_GetSpatialReference(self._g)
|
||||
if srs_ptr:
|
||||
return SpatialReference(lgdal.OSRClone(srs_ptr), 'ogr')
|
||||
else:
|
||||
try:
|
||||
srs_ptr = get_geom_srs(self._ptr)
|
||||
return SpatialReference(clone_srs(srs_ptr))
|
||||
except SRSException:
|
||||
return None
|
||||
|
||||
def set_srs(self, srs):
|
||||
"Sets the SpatialReference for this geometry."
|
||||
if isinstance(srs, SpatialReference):
|
||||
srs_ptr = lgdal.OSRClone(srs._srs)
|
||||
srs_ptr = clone_srs(srs._ptr)
|
||||
elif isinstance(srs, (StringType, UnicodeType, IntType)):
|
||||
sr = SpatialReference(srs)
|
||||
srs_ptr = lgdal.OSRClone(sr._srs)
|
||||
srs_ptr = clone_srs(sr._ptr)
|
||||
else:
|
||||
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)
|
||||
|
||||
@ -260,151 +246,168 @@ class OGRGeometry(object):
|
||||
srid = property(get_srid, set_srid)
|
||||
|
||||
#### 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
|
||||
def gml(self):
|
||||
"Returns the GML representation of the Geometry."
|
||||
buf = lgdal.OGR_G_ExportToGML(self._g)
|
||||
if buf: return string_at(buf)
|
||||
else: return None
|
||||
return to_gml(self._ptr)
|
||||
|
||||
@property
|
||||
def hex(self):
|
||||
"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
|
||||
def wkb_size(self):
|
||||
"Returns the size of the WKB buffer."
|
||||
return lgdal.OGR_G_WkbSize(self._g)
|
||||
return get_wkbsize(self._ptr)
|
||||
|
||||
@property
|
||||
def wkb(self):
|
||||
"Returns the WKB representation of the Geometry."
|
||||
if sys.byteorder == 'little':
|
||||
byteorder = c_int(1) # wkbNDR (from ogr_core.h)
|
||||
byteorder = 1 # wkbNDR (from ogr_core.h)
|
||||
else:
|
||||
byteorder = c_int(0) # wkbXDR (from ogr_core.h)
|
||||
# Creating a mutable string buffer of the given size, exporting
|
||||
# to WKB, and returning a Python buffer of the WKB.
|
||||
byteorder = 0 # wkbXDR
|
||||
sz = self.wkb_size
|
||||
wkb = create_string_buffer(sz)
|
||||
check_err(lgdal.OGR_G_ExportToWkb(self._g, byteorder, byref(wkb)))
|
||||
return buffer(string_at(wkb, sz))
|
||||
# Creating the unsigned character buffer, and passing it in by reference.
|
||||
buf = (c_ubyte * 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
|
||||
def wkt(self):
|
||||
"Returns the WKT representation of the Geometry."
|
||||
buf = c_char_p()
|
||||
check_err(lgdal.OGR_G_ExportToWkt(self._g, byref(buf)))
|
||||
return string_at(buf)
|
||||
return to_wkt(self._ptr, byref(c_char_p()))
|
||||
|
||||
#### Geometry Methods ####
|
||||
def clone(self):
|
||||
"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):
|
||||
"""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
|
||||
end."""
|
||||
end.
|
||||
"""
|
||||
# Closing the open rings.
|
||||
lgdal.OGR_G_CloseRings(self._g)
|
||||
geom_close_rings(self._ptr)
|
||||
|
||||
def transform(self, coord_trans):
|
||||
"Transforms this Geometry with the given CoordTransform object."
|
||||
if not isinstance(coord_trans, CoordTransform):
|
||||
raise OGRException('CoordTransform object required for transform.')
|
||||
check_err(lgdal.OGR_G_Transform(self._g, coord_trans._ct))
|
||||
"""
|
||||
Transforms this geometry to a different spatial reference system. May take
|
||||
either a CoordTransform object or a SpatialReference object.
|
||||
"""
|
||||
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):
|
||||
"Transforms this Geometry with the given SpatialReference."
|
||||
if not isinstance(srs, SpatialReference):
|
||||
raise OGRException('SpatialReference object required for transform_to.')
|
||||
check_err(lgdal.OGR_G_TransformTo(self._g, srs._srs))
|
||||
"For backwards-compatibility."
|
||||
self.transform(srs)
|
||||
|
||||
#### Topology Methods ####
|
||||
def _topology(self, topo_func, other):
|
||||
def _topology(self, func, other):
|
||||
"""A generalized function for topology operations, takes a GDAL function and
|
||||
the other geometry to perform the operation on."""
|
||||
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
|
||||
status = topo_func(self._g, other._g)
|
||||
|
||||
# Returning based on the status code (an integer)
|
||||
if status: return True
|
||||
else: return False
|
||||
# Returning the output of the given function with the other geometry's
|
||||
# pointer.
|
||||
return func(self._ptr, other._ptr)
|
||||
|
||||
def intersects(self, 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):
|
||||
"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):
|
||||
"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):
|
||||
"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):
|
||||
"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):
|
||||
"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):
|
||||
"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):
|
||||
"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 ####
|
||||
def _geomgen(self, gen_func, other=None):
|
||||
"A helper routine for the OGR routines that generate geometries."
|
||||
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:
|
||||
return OGRGeometry(c_void_p(gen_func(self._g)))
|
||||
return OGRGeometry(gen_func(self._ptr), self.srs)
|
||||
|
||||
@property
|
||||
def boundary(self):
|
||||
"Returns the boundary of this geometry."
|
||||
return self._geomgen(lgdal.OGR_G_GetBoundary)
|
||||
return self._geomgen(get_boundary)
|
||||
|
||||
@property
|
||||
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.
|
||||
"""
|
||||
return self._geomgen(geom_convex_hull)
|
||||
|
||||
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(lgdal.OGR_G_Union, other)
|
||||
|
||||
def difference(self, other):
|
||||
"""Returns a new geometry consisting of the region which is the difference
|
||||
of this geometry and the other."""
|
||||
return self._geomgen(lgdal.OGR_G_Difference, other)
|
||||
|
||||
def sym_difference(self, other):
|
||||
"""Returns a new geometry which is the symmetric difference of this
|
||||
geometry and the other."""
|
||||
return self._geomgen(lgdal.OGR_G_SymmetricDifference, other)
|
||||
"""
|
||||
Returns a new geometry consisting of the region which is the difference
|
||||
of this geometry and the other.
|
||||
"""
|
||||
return self._geomgen(geom_diff, other)
|
||||
|
||||
def intersection(self, other):
|
||||
"""Returns a new geometry consisting of the region of intersection of this
|
||||
geometry and the other."""
|
||||
return self._geomgen(lgdal.OGR_G_Intersection, other)
|
||||
"""
|
||||
Returns a new geometry consisting of the region of intersection of this
|
||||
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.
|
||||
class Point(OGRGeometry):
|
||||
@ -412,17 +415,17 @@ class Point(OGRGeometry):
|
||||
@property
|
||||
def x(self):
|
||||
"Returns the X coordinate for this Point."
|
||||
return getx(self._g, c_int(0))
|
||||
return getx(self._ptr, 0)
|
||||
|
||||
@property
|
||||
def y(self):
|
||||
"Returns the Y coordinate for this Point."
|
||||
return gety(self._g, c_int(0))
|
||||
return gety(self._ptr, 0)
|
||||
|
||||
@property
|
||||
def z(self):
|
||||
"Returns the Z coordinate for this Point."
|
||||
return getz(self._g, c_int(0))
|
||||
return getz(self._ptr, 0)
|
||||
|
||||
@property
|
||||
def tuple(self):
|
||||
@ -436,17 +439,15 @@ class LineString(OGRGeometry):
|
||||
|
||||
def __getitem__(self, index):
|
||||
"Returns the Point at the given index."
|
||||
if index > 0 or index < self.point_count:
|
||||
x = c_double()
|
||||
y = c_double()
|
||||
z = c_double()
|
||||
lgdal.OGR_G_GetPoint(self._g, c_int(index),
|
||||
byref(x), byref(y), byref(z))
|
||||
if self.coord_dim == 1:
|
||||
if index >= 0 and index < self.point_count:
|
||||
x, y, z = c_double(), c_double(), c_double()
|
||||
get_point(self._ptr, index, byref(x), byref(y), byref(z))
|
||||
dim = self.coord_dim
|
||||
if dim == 1:
|
||||
return (x.value,)
|
||||
elif self.coord_dim == 2:
|
||||
elif dim == 2:
|
||||
return (x.value, y.value)
|
||||
elif self.coord_dim == 3:
|
||||
elif dim == 3:
|
||||
return (x.value, y.value, z.value)
|
||||
else:
|
||||
raise OGRIndexError('index out of range: %s' % str(index))
|
||||
@ -454,16 +455,16 @@ class LineString(OGRGeometry):
|
||||
def __iter__(self):
|
||||
"Iterates over each point in the LineString."
|
||||
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."
|
||||
return self.point_count
|
||||
|
||||
@property
|
||||
def tuple(self):
|
||||
"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.
|
||||
class LinearRing(LineString): pass
|
||||
@ -477,38 +478,38 @@ class Polygon(OGRGeometry):
|
||||
def __iter__(self):
|
||||
"Iterates through each ring in the Polygon."
|
||||
for i in xrange(self.geom_count):
|
||||
yield self.__getitem__(i)
|
||||
yield self[i]
|
||||
|
||||
def __getitem__(self, index):
|
||||
"Gets the ring at the specified index."
|
||||
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:
|
||||
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
|
||||
@property
|
||||
def shell(self):
|
||||
"Returns the shell of this Polygon."
|
||||
return self.__getitem__(0) # First ring is the shell
|
||||
return self[0] # First ring is the shell
|
||||
|
||||
@property
|
||||
def tuple(self):
|
||||
"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
|
||||
def point_count(self):
|
||||
"The number of Points in this 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
|
||||
def centroid(self):
|
||||
"Returns the centroid (a Point) of this Polygon."
|
||||
# The centroid is a Point, create a geometry for this.
|
||||
p = OGRGeometry(OGRGeomType('Point'))
|
||||
check_err(lgdal.OGR_G_Centroid(self._g, p._g))
|
||||
get_centroid(self._ptr, p._ptr)
|
||||
return p
|
||||
|
||||
# Geometry Collection base class.
|
||||
@ -518,14 +519,14 @@ class GeometryCollection(OGRGeometry):
|
||||
def __getitem__(self, index):
|
||||
"Gets the Geometry at the specified index."
|
||||
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:
|
||||
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):
|
||||
"Iterates over each Geometry."
|
||||
for i in xrange(self.geom_count):
|
||||
yield self.__getitem__(i)
|
||||
yield self[i]
|
||||
|
||||
def __len__(self):
|
||||
"The number of geometries in this Geometry Collection."
|
||||
@ -534,24 +535,24 @@ class GeometryCollection(OGRGeometry):
|
||||
def add(self, geom):
|
||||
"Add the geometry to this Geometry Collection."
|
||||
if isinstance(geom, OGRGeometry):
|
||||
ptr = geom._g
|
||||
ptr = geom._ptr
|
||||
elif isinstance(geom, (StringType, UnicodeType)):
|
||||
tmp = OGRGeometry(geom)
|
||||
ptr = tmp._g
|
||||
ptr = tmp._ptr
|
||||
else:
|
||||
raise OGRException('Must add an OGRGeometry.')
|
||||
lgdal.OGR_G_AddGeometry(self._g, ptr)
|
||||
add_geom(self._ptr, ptr)
|
||||
|
||||
@property
|
||||
def point_count(self):
|
||||
"The number of Points in this Geometry 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
|
||||
def tuple(self):
|
||||
"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.
|
||||
class MultiPoint(GeometryCollection): pass
|
||||
@ -566,4 +567,5 @@ GEO_CLASSES = {1 : Point,
|
||||
5 : MultiLineString,
|
||||
6 : MultiPolygon,
|
||||
7 : GeometryCollection,
|
||||
101: LinearRing,
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
from types import StringType
|
||||
from django.contrib.gis.gdal.error import OGRException
|
||||
|
||||
#### OGRGeomType ####
|
||||
@ -15,7 +14,7 @@ class OGRGeomType(object):
|
||||
"Figures out the correct OGR Type based upon the input."
|
||||
if isinstance(type_input, OGRGeomType):
|
||||
self._index = type_input._index
|
||||
elif isinstance(type_input, StringType):
|
||||
elif isinstance(type_input, basestring):
|
||||
idx = self._has_str(self.__ogr_str, type_input)
|
||||
if idx == None:
|
||||
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)
|
||||
self._index = self.__ogr_int.index(type_input)
|
||||
else:
|
||||
raise TypeError('Invalid OGR Input type given!')
|
||||
raise TypeError('Invalid OGR input type given.')
|
||||
|
||||
def __str__(self):
|
||||
"Returns a short-hand string form of the OGR Geometry type."
|
||||
return self.__ogr_str[self._index]
|
||||
|
||||
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):
|
||||
return self._index == other._index
|
||||
elif isinstance(other, StringType):
|
||||
elif isinstance(other, basestring):
|
||||
idx = self._has_str(self.__ogr_str, other)
|
||||
if not (idx == None): return self._index == idx
|
||||
return False
|
||||
|
@ -1,38 +1,36 @@
|
||||
# Needed ctypes routines
|
||||
from ctypes import c_int, c_long, c_void_p, byref, string_at
|
||||
|
||||
# The GDAL C Library
|
||||
from django.contrib.gis.gdal.libgdal import lgdal
|
||||
from ctypes import byref
|
||||
|
||||
# Other GDAL imports.
|
||||
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.geometries import OGRGeomType
|
||||
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, check_err
|
||||
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:
|
||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
||||
#
|
||||
# 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):
|
||||
"A class that wraps an OGR Layer, needs to be instantiated from a DataSource object."
|
||||
|
||||
#### Python 'magic' routines ####
|
||||
def __init__(self, l):
|
||||
def __init__(self, layer_ptr):
|
||||
"Needs a C pointer (Python/ctypes integer) in order to initialize."
|
||||
self._layer = None # Initially NULL
|
||||
self._ldefn = None
|
||||
if not l:
|
||||
raise OGRException, 'Cannot create Layer, invalid pointer given'
|
||||
self._layer = l
|
||||
self._ldefn = lgdal.OGR_L_GetLayerDefn(l)
|
||||
self._ptr = None # Initially NULL
|
||||
if not layer_ptr:
|
||||
raise OGRException('Cannot create Layer, invalid pointer given')
|
||||
self._ptr = layer_ptr
|
||||
self._ldefn = get_layer_defn(self._ptr)
|
||||
|
||||
def __getitem__(self, index):
|
||||
"Gets the Feature at the specified index."
|
||||
@ -44,7 +42,7 @@ class Layer(object):
|
||||
if index < 0:
|
||||
index = end - index
|
||||
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)
|
||||
else:
|
||||
# A slice was given
|
||||
@ -54,9 +52,9 @@ class Layer(object):
|
||||
def __iter__(self):
|
||||
"Iterates over each Feature in the Layer."
|
||||
# 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):
|
||||
yield Feature(lgdal.OGR_L_GetNextFeature(self._layer), self._ldefn)
|
||||
yield Feature(get_next_feature(self._ptr), self._ldefn)
|
||||
|
||||
def __len__(self):
|
||||
"The length is the number of features."
|
||||
@ -68,76 +66,80 @@ class Layer(object):
|
||||
|
||||
def _make_feature(self, 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 ####
|
||||
@property
|
||||
def extent(self):
|
||||
"Returns the extent (an Envelope) of this layer."
|
||||
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)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"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
|
||||
def num_feat(self, force=1):
|
||||
"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
|
||||
def num_fields(self):
|
||||
"Returns the number of fields in the Layer."
|
||||
return lgdal.OGR_FD_GetFieldCount(self._ldefn)
|
||||
return get_field_count(self._ldefn)
|
||||
|
||||
@property
|
||||
def geom_type(self):
|
||||
"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
|
||||
def srs(self):
|
||||
"Returns the Spatial Reference used in this Layer."
|
||||
ptr = lgdal.OGR_L_GetSpatialRef(self._layer)
|
||||
ptr = get_layer_srs(self._ptr)
|
||||
if ptr:
|
||||
return SpatialReference(lgdal.OSRClone(ptr), 'ogr')
|
||||
return SpatialReference(clone_srs(ptr))
|
||||
else:
|
||||
return None
|
||||
|
||||
@property
|
||||
def fields(self):
|
||||
"Returns a list of the fields available in this Layer."
|
||||
return [ string_at(lgdal.OGR_Fld_GetNameRef(lgdal.OGR_FD_GetFieldDefn(self._ldefn, i)))
|
||||
for i in xrange(self.num_fields) ]
|
||||
return [get_field_name(get_field_defn(self._ldefn, i))
|
||||
for i in xrange(self.num_fields) ]
|
||||
|
||||
@property
|
||||
def field_widths(self):
|
||||
"Returns a list of the maximum field widths for the features."
|
||||
return [ int(lgdal.OGR_Fld_GetWidth(lgdal.OGR_FD_GetFieldDefn(self._ldefn, i)))
|
||||
for i in xrange(self.num_fields) ]
|
||||
return [get_field_width(get_field_defn(self._ldefn, i))
|
||||
for i in xrange(self.num_fields)]
|
||||
|
||||
@property
|
||||
def field_precisions(self):
|
||||
"Returns the field precisions for the features."
|
||||
return [ int(lgdal.OGR_Fld_GetPrecision(lgdal.OGR_FD_GetFieldDefn(self._ldefn, i)))
|
||||
for i in xrange(self.num_fields) ]
|
||||
return [get_field_precision(get_field_defn(self._ldefn, i))
|
||||
for i in xrange(self.num_fields)]
|
||||
|
||||
#### Layer Methods ####
|
||||
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:
|
||||
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]
|
||||
|
||||
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:
|
||||
from django.contrib.gis.geos import fromstr
|
||||
return [fromstr(feat.geom.wkt) for feat in self]
|
||||
from django.contrib.gis.geos import GEOSGeometry
|
||||
return [GEOSGeometry(feat.geom.wkb) for feat in self]
|
||||
else:
|
||||
return [feat.geom for feat in self]
|
||||
|
@ -1,5 +1,6 @@
|
||||
import os, sys
|
||||
from ctypes import CDLL, string_at
|
||||
from ctypes.util import find_library
|
||||
from django.contrib.gis.gdal.error import OGRException
|
||||
|
||||
if os.name == 'nt':
|
||||
@ -7,16 +8,14 @@ if os.name == 'nt':
|
||||
lib_name = 'libgdal-1.dll'
|
||||
elif os.name == 'posix':
|
||||
platform = os.uname()[0]
|
||||
if platform in ('Linux', 'SunOS'):
|
||||
# Linux or Solaris shared library
|
||||
lib_name = 'libgdal.so'
|
||||
elif platform == 'Darwin':
|
||||
if platform == 'Darwin':
|
||||
# Mac OSX shared library
|
||||
lib_name = 'libgdal.dylib'
|
||||
else:
|
||||
raise OGRException, 'Unknown POSIX platform "%s"' % platform
|
||||
else:
|
||||
# Attempting to use .so extension for all other platforms.
|
||||
lib_name = 'libgdal.so'
|
||||
else:
|
||||
raise OGRException, 'Unsupported OS "%s"' % os.name
|
||||
raise OGRException('Unsupported OS "%s"' % os.name)
|
||||
|
||||
# This loads the GDAL/OGR C library
|
||||
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
|
||||
from types import StringType, UnicodeType, TupleType
|
||||
from ctypes import \
|
||||
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
|
||||
from ctypes import byref, c_char_p, c_int, c_void_p
|
||||
|
||||
# Getting the error checking routine and exceptions
|
||||
from django.contrib.gis.gdal.error import check_err, OGRException, SRSException
|
||||
|
||||
#### 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)
|
||||
from django.contrib.gis.gdal.error import OGRException, SRSException
|
||||
from django.contrib.gis.gdal.prototypes.srs import *
|
||||
|
||||
#### Spatial Reference class. ####
|
||||
class SpatialReference(object):
|
||||
"""
|
||||
A wrapper for the OGRSpatialReference object. According to the GDAL website,
|
||||
the SpatialReference object 'provide[s] services to represent coordinate
|
||||
systems (projections and datums) and to transform between them.'
|
||||
the SpatialReference object "provide[s] services to represent coordinate
|
||||
systems (projections and datums) and to transform between them."
|
||||
"""
|
||||
|
||||
# Well-Known Geographical Coordinate System Name
|
||||
@ -82,9 +50,8 @@ class SpatialReference(object):
|
||||
def __init__(self, srs_input='', srs_type='wkt'):
|
||||
"Creates a spatial reference object from the given OGC Well Known Text (WKT)."
|
||||
|
||||
self._srs = None # Initially NULL
|
||||
|
||||
# Creating an initial empty string buffer.
|
||||
# Intializing pointer and string buffer.
|
||||
self._ptr = None
|
||||
buf = c_char_p('')
|
||||
|
||||
# Encoding to ASCII if unicode passed in.
|
||||
@ -92,37 +59,40 @@ class SpatialReference(object):
|
||||
srs_input = srs_input.encode('ascii')
|
||||
|
||||
if isinstance(srs_input, StringType):
|
||||
# Is this an EPSG well known name?
|
||||
m = self._epsg_regex.match(srs_input)
|
||||
if m:
|
||||
# Is this an EPSG well known name?
|
||||
srs_type = 'epsg'
|
||||
srs_input = int(m.group('epsg'))
|
||||
# Is this a short-hand well known name?
|
||||
elif srs_input in self._well_known:
|
||||
# Is this a short-hand well known name?
|
||||
srs_type = 'epsg'
|
||||
srs_input = self._well_known[srs_input]
|
||||
elif srs_type == 'proj':
|
||||
pass
|
||||
else:
|
||||
# Setting the buffer with WKT, PROJ.4 string, etc.
|
||||
buf = c_char_p(srs_input)
|
||||
elif isinstance(srs_input, int):
|
||||
if srs_type == 'wkt': srs_type = 'epsg' # want to try epsg if only integer provided
|
||||
if srs_type not in ('epsg', 'ogr'):
|
||||
raise SRSException('Integer input requires SRS type of "ogr" or "epsg".')
|
||||
# EPSG integer code was input.
|
||||
if srs_type != 'epsg': srs_type = 'epsg'
|
||||
elif isinstance(srs_input, c_void_p):
|
||||
srs_type = 'ogr'
|
||||
else:
|
||||
raise TypeError('Invalid SRS type "%s"' % srs_type)
|
||||
|
||||
# Calling OSRNewSpatialReference with the string buffer.
|
||||
if srs_type == 'ogr':
|
||||
srs = srs_input # SRS input is OGR pointer
|
||||
# SRS input is OGR pointer
|
||||
srs = srs_input
|
||||
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 not srs:
|
||||
raise SRSException('Could not create spatial reference from: %s' % srs_input)
|
||||
else:
|
||||
self._srs = srs
|
||||
self._ptr = srs
|
||||
|
||||
# Post-processing if in PROJ.4 or EPSG formats.
|
||||
if srs_type == 'proj': self.import_proj(srs_input)
|
||||
@ -130,7 +100,7 @@ class SpatialReference(object):
|
||||
|
||||
def __del__(self):
|
||||
"Destroys this spatial reference."
|
||||
if self._srs: lgdal.OSRRelease(self._srs)
|
||||
if self._ptr: release_srs(self._ptr)
|
||||
|
||||
def __getitem__(self, target):
|
||||
"""
|
||||
@ -172,43 +142,48 @@ class SpatialReference(object):
|
||||
"The string representation uses '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 ####
|
||||
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):
|
||||
"""
|
||||
The attribute value for the given target node (e.g. 'PROJCS'). The index
|
||||
keyword specifies an index of the child node to return.
|
||||
"""
|
||||
if not isinstance(target, str):
|
||||
raise TypeError('Attribute target must be a string')
|
||||
ptr = lgdal.OSRGetAttrValue(self._srs, c_char_p(target), c_int(index))
|
||||
return self._string_ptr(ptr)
|
||||
if not isinstance(target, str) or not isinstance(index, int):
|
||||
raise TypeError
|
||||
return get_attr_value(self._ptr, target, index)
|
||||
|
||||
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):
|
||||
"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
|
||||
def name(self):
|
||||
"Returns the name of this Spatial Reference."
|
||||
@ -226,43 +201,29 @@ class SpatialReference(object):
|
||||
return None
|
||||
|
||||
#### 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
|
||||
def linear_name(self):
|
||||
"Returns the name of the linear units."
|
||||
self._cache_linear()
|
||||
return self._linear_name
|
||||
units, name = linear_units(self._ptr, byref(c_char_p()))
|
||||
return name
|
||||
|
||||
@property
|
||||
def linear_units(self):
|
||||
"Returns the value of the linear units."
|
||||
self._cache_linear()
|
||||
return self._linear_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)
|
||||
units, name = linear_units(self._ptr, byref(c_char_p()))
|
||||
return units
|
||||
|
||||
@property
|
||||
def angular_name(self):
|
||||
"Returns the name of the angular units."
|
||||
self._cache_angular()
|
||||
return self._angular_name
|
||||
units, name = angular_units(self._ptr, byref(c_char_p()))
|
||||
return name
|
||||
|
||||
@property
|
||||
def angular_units(self):
|
||||
"Returns the value of the angular units."
|
||||
self._cache_angular()
|
||||
return self._angular_units
|
||||
units, name = angular_units(self._ptr, byref(c_char_p()))
|
||||
return units
|
||||
|
||||
#### Spheroid/Ellipsoid Properties ####
|
||||
@property
|
||||
@ -276,26 +237,17 @@ class SpatialReference(object):
|
||||
@property
|
||||
def semi_major(self):
|
||||
"Returns the Semi Major Axis for this Spatial Reference."
|
||||
err = c_int(0)
|
||||
sm = semi_major(self._srs, byref(err))
|
||||
check_err(err.value)
|
||||
return sm
|
||||
return semi_major(self._ptr, byref(c_int()))
|
||||
|
||||
@property
|
||||
def semi_minor(self):
|
||||
"Returns the Semi Minor Axis for this Spatial Reference."
|
||||
err = c_int()
|
||||
sm = semi_minor(self._srs, byref(err))
|
||||
check_err(err.value)
|
||||
return sm
|
||||
return semi_minor(self._ptr, byref(c_int()))
|
||||
|
||||
@property
|
||||
def inverse_flattening(self):
|
||||
"Returns the Inverse Flattening for this Spatial Reference."
|
||||
err = c_int()
|
||||
inv_flat = invflattening(self._srs, byref(err))
|
||||
check_err(err.value)
|
||||
return inv_flat
|
||||
return invflattening(self._ptr, byref(c_int()))
|
||||
|
||||
#### Boolean Properties ####
|
||||
@property
|
||||
@ -304,14 +256,12 @@ class SpatialReference(object):
|
||||
Returns True if this SpatialReference is geographic
|
||||
(root node is GEOGCS).
|
||||
"""
|
||||
if lgdal.OSRIsGeographic(self._srs): return True
|
||||
else: return False
|
||||
return bool(isgeographic(self._ptr))
|
||||
|
||||
@property
|
||||
def local(self):
|
||||
"Returns True if this SpatialReference is local (root node is LOCAL_CS)."
|
||||
if lgdal.OSRIsLocal(self._srs): return True
|
||||
else: return False
|
||||
return bool(islocal(self._ptr))
|
||||
|
||||
@property
|
||||
def projected(self):
|
||||
@ -319,48 +269,40 @@ class SpatialReference(object):
|
||||
Returns True if this SpatialReference is a projected coordinate system
|
||||
(root node is PROJCS).
|
||||
"""
|
||||
if lgdal.OSRIsProjected(self._srs): return True
|
||||
else: return False
|
||||
return bool(isprojected(self._ptr))
|
||||
|
||||
#### Import Routines #####
|
||||
def import_wkt(self, wkt):
|
||||
"Imports the Spatial Reference from OGC WKT (string)"
|
||||
buf = create_string_buffer(wkt)
|
||||
check_err(lgdal.OSRImportFromWkt(self._srs, byref(buf)))
|
||||
from_wkt(self._ptr, byref(c_char_p(wkt)))
|
||||
|
||||
def import_proj(self, proj):
|
||||
"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):
|
||||
"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):
|
||||
"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 ####
|
||||
@property
|
||||
def wkt(self):
|
||||
"Returns the WKT representation of this Spatial Reference."
|
||||
w = c_char_p()
|
||||
check_err(lgdal.OSRExportToWkt(self._srs, byref(w)))
|
||||
if w: return string_at(w)
|
||||
return to_wkt(self._ptr, byref(c_char_p()))
|
||||
|
||||
@property
|
||||
def pretty_wkt(self, simplify=0):
|
||||
"Returns the 'pretty' representation of the WKT."
|
||||
w = c_char_p()
|
||||
check_err(lgdal.OSRExportToPrettyWkt(self._srs, byref(w), c_int(simplify)))
|
||||
if w: return string_at(w)
|
||||
return to_pretty_wkt(self._ptr, byref(c_char_p()), simplify)
|
||||
|
||||
@property
|
||||
def proj(self):
|
||||
"Returns the PROJ.4 representation for this Spatial Reference."
|
||||
w = c_char_p()
|
||||
check_err(lgdal.OSRExportToProj4(self._srs, byref(w)))
|
||||
if w: return string_at(w)
|
||||
return to_proj(self._ptr, byref(c_char_p()))
|
||||
|
||||
@property
|
||||
def proj4(self):
|
||||
@ -370,28 +312,34 @@ class SpatialReference(object):
|
||||
@property
|
||||
def xml(self, dialect=''):
|
||||
"Returns the XML representation of this Spatial Reference."
|
||||
w = c_char_p()
|
||||
check_err(lgdal.OSRExportToXML(self._srs, byref(w), create_string_buffer(dialect)))
|
||||
return string_at(w)
|
||||
# FIXME: This leaks memory, have to figure out why.
|
||||
return to_xml(self._ptr, byref(c_char_p()), dialect)
|
||||
|
||||
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):
|
||||
"A coordinate system transformation object."
|
||||
"The coordinate system transformation object."
|
||||
|
||||
def __init__(self, source, target):
|
||||
"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):
|
||||
raise SRSException('source and target must be of type SpatialReference')
|
||||
ct = lgdal.OCTNewCoordinateTransformation(source._srs, target._srs)
|
||||
if not ct:
|
||||
self._ptr = new_ct(source._ptr, target._ptr)
|
||||
if not self._ptr:
|
||||
raise SRSException('could not intialize CoordTransform object')
|
||||
self._ct = ct
|
||||
self._srs1_name = source.name
|
||||
self._srs2_name = target.name
|
||||
|
||||
def __del__(self):
|
||||
"Deletes this Coordinate Transformation object."
|
||||
if self._ct: lgdal.OCTDestroyCoordinateTransformation(self._ct)
|
||||
if self._ptr: destroy_ct(self._ptr)
|
||||
|
||||
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)
|
||||
|
||||
# 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
|
||||
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
|
||||
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.
|
||||
for k, v in source.fields.items():
|
||||
fld = feat[k] # Indexing with string value
|
||||
|
||||
# Asserting the string representation, and making sure we get
|
||||
# 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))
|
||||
# Making sure we get the proper OGR Field instance, using
|
||||
# a string value index for the feature.
|
||||
self.assertEqual(True, isinstance(feat[k], v))
|
||||
|
||||
# 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):
|
||||
"Testing Geometries from Data Source Features."
|
||||
|
@ -1,5 +1,6 @@
|
||||
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 *
|
||||
|
||||
class OGRGeomTest(unittest.TestCase):
|
||||
@ -94,41 +95,78 @@ class OGRGeomTest(unittest.TestCase):
|
||||
|
||||
def test04_linestring(self):
|
||||
"Testing LineString objects."
|
||||
prev = OGRGeometry('POINT(0 0)')
|
||||
for ls in linestrings:
|
||||
linestr = OGRGeometry(ls.wkt)
|
||||
self.assertEqual(2, linestr.geom_type)
|
||||
self.assertEqual('LINESTRING', linestr.geom_name)
|
||||
self.assertEqual(ls.n_p, linestr.point_count)
|
||||
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):
|
||||
"Testing MultiLineString objects."
|
||||
prev = OGRGeometry('POINT(0 0)')
|
||||
for mls in multilinestrings:
|
||||
mlinestr = OGRGeometry(mls.wkt)
|
||||
self.assertEqual(5, mlinestr.geom_type)
|
||||
self.assertEqual('MULTILINESTRING', mlinestr.geom_name)
|
||||
self.assertEqual(mls.n_p, mlinestr.point_count)
|
||||
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."
|
||||
prev = OGRGeometry('POINT(0 0)')
|
||||
for p in polygons:
|
||||
poly = OGRGeometry(p.wkt)
|
||||
self.assertEqual(3, poly.geom_type)
|
||||
self.assertEqual('POLYGON', poly.geom_name)
|
||||
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:
|
||||
if first and p.ext_ring_cs:
|
||||
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)
|
||||
self.assertEqual('LINEARRING', r.geom_name)
|
||||
|
||||
def test07_closepolygons(self):
|
||||
def test07b_closepolygons(self):
|
||||
"Testing closing Polygon objects."
|
||||
|
||||
# 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))')
|
||||
self.assertEqual(8, poly.point_count)
|
||||
@ -149,6 +187,7 @@ class OGRGeomTest(unittest.TestCase):
|
||||
|
||||
def test08_multipolygons(self):
|
||||
"Testing MultiPolygon objects."
|
||||
prev = OGRGeometry('POINT(0 0)')
|
||||
for mp in multipolygons:
|
||||
mpoly = OGRGeometry(mp.wkt)
|
||||
self.assertEqual(6, mpoly.geom_type)
|
||||
@ -156,27 +195,53 @@ class OGRGeomTest(unittest.TestCase):
|
||||
if mp.valid:
|
||||
self.assertEqual(mp.n_p, mpoly.point_count)
|
||||
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):
|
||||
"Testing OGR Geometries with Spatial Reference objects."
|
||||
for mp in multipolygons:
|
||||
# Creating a geometry w/spatial reference
|
||||
sr = SpatialReference('WGS84')
|
||||
mpoly = OGRGeometry(mp.wkt, sr)
|
||||
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:
|
||||
self.assertEqual(sr.wkt, poly.srs.wkt)
|
||||
for ring in poly:
|
||||
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)
|
||||
self.assertEqual(4326, mpoly.srid)
|
||||
mpoly.srs = SpatialReference(4269)
|
||||
self.assertEqual(4269, mpoly.srid)
|
||||
self.assertEqual('NAD83', mpoly.srs.name)
|
||||
|
||||
# Incrementing through the multipolyogn after the spatial reference
|
||||
# has been re-assigned.
|
||||
for poly in mpoly:
|
||||
self.assertEqual(mpoly.srs.wkt, poly.srs.wkt)
|
||||
poly.srs = 32140
|
||||
for ring in poly:
|
||||
# Changing each ring in the polygon
|
||||
self.assertEqual(32140, ring.srs.srid)
|
||||
self.assertEqual('NAD83 / Texas South Central', ring.srs.name)
|
||||
ring.srs = str(SpatialReference(4326)) # back to WGS84
|
||||
@ -186,8 +251,59 @@ class OGRGeomTest(unittest.TestCase):
|
||||
ring.srid = 4322
|
||||
self.assertEqual('WGS 72', ring.srs.name)
|
||||
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():
|
||||
s = unittest.TestSuite()
|
||||
|
Loading…
x
Reference in New Issue
Block a user