app/django/contrib/gis/gdal/datasource.py
changeset 323 ff1a9aa48cfd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/django/contrib/gis/gdal/datasource.py	Tue Oct 14 16:00:59 2008 +0000
@@ -0,0 +1,138 @@
+"""
+ 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.driver import Driver
+from django.contrib.gis.gdal.error import OGRException, OGRIndexError
+from django.contrib.gis.gdal.layer import Layer
+
+# Getting the ctypes prototypes for the DataSource.
+from django.contrib.gis.gdal.prototypes.ds import \
+    destroy_ds, get_driver_count, register_all, open_ds, release_ds, \
+    get_ds_name, get_layer, get_layer_count, get_layer_by_name
+
+# For more information, see the OGR C API source code:
+#  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, write=False):
+
+        # 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 get_driver_count(): register_all()
+
+        if isinstance(ds_input, basestring):
+            # The data source driver is a void pointer.
+            ds_driver = c_void_p()
+            try:
+                # OGROpen will auto-detect the data source type.
+                ds = open_ds(ds_input, self._write, byref(ds_driver))
+            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)
+        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' % type(ds_input))
+
+        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):
+        "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[i]
+
+    def __getitem__(self, index):
+        "Allows use of the index [] operator to get a layer at the 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)
+        elif isinstance(index, int):
+            if index < 0 or index >= self.layer_count:
+                raise OGRIndexError('index out of range')
+            l = get_layer(self._ptr, index)
+        else:
+            raise TypeError('Invalid index type: %s' % type(index))
+        return Layer(l)
+        
+    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))
+
+    #### DataSource Properties ####
+    @property
+    def driver(self):
+        "Returns the Driver object for this Data Source."
+        return self._driver
+        
+    @property
+    def layer_count(self):
+        "Returns the number of layers in the data source."
+        return get_layer_count(self._ptr)
+
+    @property
+    def name(self):
+        "Returns the name of the data source."
+        return get_ds_name(self._ptr)