|
1 """ |
|
2 DataSource is a wrapper for the OGR Data Source object, which provides |
|
3 an interface for reading vector geometry data from many different file |
|
4 formats (including ESRI shapefiles). |
|
5 |
|
6 When instantiating a DataSource object, use the filename of a |
|
7 GDAL-supported data source. For example, a SHP file or a |
|
8 TIGER/Line file from the government. |
|
9 |
|
10 The ds_driver keyword is used internally when a ctypes pointer |
|
11 is passed in directly. |
|
12 |
|
13 Example: |
|
14 ds = DataSource('/home/foo/bar.shp') |
|
15 for layer in ds: |
|
16 for feature in layer: |
|
17 # Getting the geometry for the feature. |
|
18 g = feature.geom |
|
19 |
|
20 # Getting the 'description' field for the feature. |
|
21 desc = feature['description'] |
|
22 |
|
23 # We can also increment through all of the fields |
|
24 # attached to this feature. |
|
25 for field in feature: |
|
26 # Get the name of the field (e.g. 'description') |
|
27 nm = field.name |
|
28 |
|
29 # Get the type (integer) of the field, e.g. 0 => OFTInteger |
|
30 t = field.type |
|
31 |
|
32 # Returns the value the field; OFTIntegers return ints, |
|
33 # OFTReal returns floats, all else returns string. |
|
34 val = field.value |
|
35 """ |
|
36 # ctypes prerequisites. |
|
37 from ctypes import byref, c_void_p |
|
38 |
|
39 # The GDAL C library, OGR exceptions, and the Layer object. |
|
40 from django.contrib.gis.gdal.driver import Driver |
|
41 from django.contrib.gis.gdal.error import OGRException, OGRIndexError |
|
42 from django.contrib.gis.gdal.layer import Layer |
|
43 |
|
44 # Getting the ctypes prototypes for the DataSource. |
|
45 from django.contrib.gis.gdal.prototypes.ds import \ |
|
46 destroy_ds, get_driver_count, register_all, open_ds, release_ds, \ |
|
47 get_ds_name, get_layer, get_layer_count, get_layer_by_name |
|
48 |
|
49 # For more information, see the OGR C API source code: |
|
50 # http://www.gdal.org/ogr/ogr__api_8h.html |
|
51 # |
|
52 # The OGR_DS_* routines are relevant here. |
|
53 class DataSource(object): |
|
54 "Wraps an OGR Data Source object." |
|
55 |
|
56 #### Python 'magic' routines #### |
|
57 def __init__(self, ds_input, ds_driver=False, write=False): |
|
58 |
|
59 # DataSource pointer is initially NULL. |
|
60 self._ptr = None |
|
61 |
|
62 # The write flag. |
|
63 if write: |
|
64 self._write = 1 |
|
65 else: |
|
66 self._write = 0 |
|
67 |
|
68 # Registering all the drivers, this needs to be done |
|
69 # _before_ we try to open up a data source. |
|
70 if not get_driver_count(): register_all() |
|
71 |
|
72 if isinstance(ds_input, basestring): |
|
73 # The data source driver is a void pointer. |
|
74 ds_driver = c_void_p() |
|
75 try: |
|
76 # OGROpen will auto-detect the data source type. |
|
77 ds = open_ds(ds_input, self._write, byref(ds_driver)) |
|
78 except OGRException: |
|
79 # Making the error message more clear rather than something |
|
80 # like "Invalid pointer returned from OGROpen". |
|
81 raise OGRException('Could not open the datasource at "%s"' % ds_input) |
|
82 elif isinstance(ds_input, c_void_p) and isinstance(ds_driver, c_void_p): |
|
83 ds = ds_input |
|
84 else: |
|
85 raise OGRException('Invalid data source input type: %s' % type(ds_input)) |
|
86 |
|
87 if bool(ds): |
|
88 self._ptr = ds |
|
89 self._driver = Driver(ds_driver) |
|
90 else: |
|
91 # Raise an exception if the returned pointer is NULL |
|
92 raise OGRException('Invalid data source file "%s"' % ds_input) |
|
93 |
|
94 def __del__(self): |
|
95 "Destroys this DataStructure object." |
|
96 if self._ptr: destroy_ds(self._ptr) |
|
97 |
|
98 def __iter__(self): |
|
99 "Allows for iteration over the layers in a data source." |
|
100 for i in xrange(self.layer_count): |
|
101 yield self[i] |
|
102 |
|
103 def __getitem__(self, index): |
|
104 "Allows use of the index [] operator to get a layer at the index." |
|
105 if isinstance(index, basestring): |
|
106 l = get_layer_by_name(self._ptr, index) |
|
107 if not l: raise OGRIndexError('invalid OGR Layer name given: "%s"' % index) |
|
108 elif isinstance(index, int): |
|
109 if index < 0 or index >= self.layer_count: |
|
110 raise OGRIndexError('index out of range') |
|
111 l = get_layer(self._ptr, index) |
|
112 else: |
|
113 raise TypeError('Invalid index type: %s' % type(index)) |
|
114 return Layer(l) |
|
115 |
|
116 def __len__(self): |
|
117 "Returns the number of layers within the data source." |
|
118 return self.layer_count |
|
119 |
|
120 def __str__(self): |
|
121 "Returns OGR GetName and Driver for the Data Source." |
|
122 return '%s (%s)' % (self.name, str(self.driver)) |
|
123 |
|
124 #### DataSource Properties #### |
|
125 @property |
|
126 def driver(self): |
|
127 "Returns the Driver object for this Data Source." |
|
128 return self._driver |
|
129 |
|
130 @property |
|
131 def layer_count(self): |
|
132 "Returns the number of layers in the data source." |
|
133 return get_layer_count(self._ptr) |
|
134 |
|
135 @property |
|
136 def name(self): |
|
137 "Returns the name of the data source." |
|
138 return get_ds_name(self._ptr) |