2008-08-06 02:13:06 +08:00
|
|
|
"""
|
|
|
|
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.
|
2011-07-13 17:35:51 +08:00
|
|
|
from ctypes import byref
|
2008-08-06 02:13:06 +08:00
|
|
|
|
|
|
|
# The GDAL C library, OGR exceptions, and the Layer object.
|
2009-03-08 07:02:48 +08:00
|
|
|
from django.contrib.gis.gdal.base import GDALBase
|
2008-08-06 02:13:06 +08:00
|
|
|
from django.contrib.gis.gdal.driver import Driver
|
|
|
|
from django.contrib.gis.gdal.error import OGRException, OGRIndexError
|
|
|
|
from django.contrib.gis.gdal.layer import Layer
|
|
|
|
|
|
|
|
# Getting the ctypes prototypes for the DataSource.
|
2009-03-08 07:02:48 +08:00
|
|
|
from django.contrib.gis.gdal.prototypes import ds as capi
|
2008-08-06 02:13:06 +08:00
|
|
|
|
2012-10-07 04:56:47 +08:00
|
|
|
from django.utils.encoding import force_bytes, force_text
|
2012-07-20 20:22:00 +08:00
|
|
|
from django.utils import six
|
2012-07-21 00:53:11 +08:00
|
|
|
from django.utils.six.moves import xrange
|
2012-07-20 20:22:00 +08:00
|
|
|
|
2013-11-03 01:18:46 +08:00
|
|
|
|
2008-08-06 02:13:06 +08:00
|
|
|
# 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.
|
2009-03-08 07:02:48 +08:00
|
|
|
class DataSource(GDALBase):
|
2008-08-06 02:13:06 +08:00
|
|
|
"Wraps an OGR Data Source object."
|
|
|
|
|
|
|
|
#### Python 'magic' routines ####
|
2012-10-07 04:56:47 +08:00
|
|
|
def __init__(self, ds_input, ds_driver=False, write=False, encoding='utf-8'):
|
2008-08-06 02:13:06 +08:00
|
|
|
# The write flag.
|
|
|
|
if write:
|
|
|
|
self._write = 1
|
|
|
|
else:
|
|
|
|
self._write = 0
|
2012-10-07 04:56:47 +08:00
|
|
|
# See also http://trac.osgeo.org/gdal/wiki/rfc23_ogr_unicode
|
|
|
|
self.encoding = encoding
|
2008-08-06 02:13:06 +08:00
|
|
|
|
|
|
|
# Registering all the drivers, this needs to be done
|
|
|
|
# _before_ we try to open up a data source.
|
2009-03-08 07:02:48 +08:00
|
|
|
if not capi.get_driver_count():
|
|
|
|
capi.register_all()
|
2008-08-06 02:13:06 +08:00
|
|
|
|
2012-07-20 20:22:00 +08:00
|
|
|
if isinstance(ds_input, six.string_types):
|
2008-08-06 02:13:06 +08:00
|
|
|
# The data source driver is a void pointer.
|
2009-03-08 07:02:48 +08:00
|
|
|
ds_driver = Driver.ptr_type()
|
2008-08-06 02:13:06 +08:00
|
|
|
try:
|
|
|
|
# OGROpen will auto-detect the data source type.
|
2012-09-24 01:59:27 +08:00
|
|
|
ds = capi.open_ds(force_bytes(ds_input), self._write, byref(ds_driver))
|
2008-08-06 02:13:06 +08:00
|
|
|
except OGRException:
|
|
|
|
# Making the error message more clear rather than something
|
|
|
|
# like "Invalid pointer returned from OGROpen".
|
|
|
|
raise OGRException('Could not open the datasource at "%s"' % ds_input)
|
2009-03-08 07:02:48 +08:00
|
|
|
elif isinstance(ds_input, self.ptr_type) and isinstance(ds_driver, Driver.ptr_type):
|
2008-08-06 02:13:06 +08:00
|
|
|
ds = ds_input
|
|
|
|
else:
|
|
|
|
raise OGRException('Invalid data source input type: %s' % type(ds_input))
|
|
|
|
|
2013-10-17 20:27:34 +08:00
|
|
|
if ds:
|
2009-03-08 07:02:48 +08:00
|
|
|
self.ptr = ds
|
|
|
|
self.driver = Driver(ds_driver)
|
2008-08-06 02:13:06 +08:00
|
|
|
else:
|
2012-07-20 20:22:00 +08:00
|
|
|
# Raise an exception if the returned pointer is NULL
|
2008-08-06 02:13:06 +08:00
|
|
|
raise OGRException('Invalid data source file "%s"' % ds_input)
|
|
|
|
|
|
|
|
def __del__(self):
|
|
|
|
"Destroys this DataStructure object."
|
2014-09-13 02:45:59 +08:00
|
|
|
if self._ptr and capi:
|
2013-10-17 16:17:41 +08:00
|
|
|
capi.destroy_ds(self._ptr)
|
2008-08-06 02:13:06 +08:00
|
|
|
|
|
|
|
def __iter__(self):
|
|
|
|
"Allows for iteration over the layers in a data source."
|
|
|
|
for i in xrange(self.layer_count):
|
|
|
|
yield self[i]
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
"Allows use of the index [] operator to get a layer at the index."
|
2012-07-20 20:22:00 +08:00
|
|
|
if isinstance(index, six.string_types):
|
2012-09-24 01:59:27 +08:00
|
|
|
l = capi.get_layer_by_name(self.ptr, force_bytes(index))
|
2013-10-17 16:17:41 +08:00
|
|
|
if not l:
|
|
|
|
raise OGRIndexError('invalid OGR Layer name given: "%s"' % index)
|
2008-08-06 02:13:06 +08:00
|
|
|
elif isinstance(index, int):
|
|
|
|
if index < 0 or index >= self.layer_count:
|
|
|
|
raise OGRIndexError('index out of range')
|
2009-03-08 07:02:48 +08:00
|
|
|
l = capi.get_layer(self._ptr, index)
|
2008-08-06 02:13:06 +08:00
|
|
|
else:
|
|
|
|
raise TypeError('Invalid index type: %s' % type(index))
|
2008-10-27 06:24:21 +08:00
|
|
|
return Layer(l, self)
|
2012-07-20 20:22:00 +08:00
|
|
|
|
2008-08-06 02:13:06 +08:00
|
|
|
def __len__(self):
|
|
|
|
"Returns the number of layers within the data source."
|
|
|
|
return self.layer_count
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
"Returns OGR GetName and Driver for the Data Source."
|
|
|
|
return '%s (%s)' % (self.name, str(self.driver))
|
|
|
|
|
|
|
|
@property
|
|
|
|
def layer_count(self):
|
|
|
|
"Returns the number of layers in the data source."
|
2009-03-08 07:02:48 +08:00
|
|
|
return capi.get_layer_count(self._ptr)
|
2008-08-06 02:13:06 +08:00
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
"Returns the name of the data source."
|
2012-10-07 04:56:47 +08:00
|
|
|
name = capi.get_ds_name(self._ptr)
|
|
|
|
return force_text(name, self.encoding, strings_only=True)
|