/[thuban]/branches/WIP-pyshapelib-bramz/Extensions/ogr/ogrshapes.py
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/Extensions/ogr/ogrshapes.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2435 - (show annotations)
Tue Dec 7 16:44:51 2004 UTC (20 years, 3 months ago) by nhueffme
Original Path: trunk/thuban/Extensions/ogr/ogrshapes.py
File MIME type: text/x-python
File size: 11240 byte(s)
Adding a new extension to read shapefiles with ogr. It is planned to add other
vector formats.

1 # Copyright (C) 2004 by Intevation GmbH
2 # Authors:
3 # Nina Hüffmeyer <[email protected]>
4 #
5 # This program is free software under the GPL (>=v2)
6 # Read the file COPYING coming with the software for details.
7
8 __version__ = "$Revision$"
9 # $Source$
10 # $Id$
11
12 from __future__ import generators
13
14 try:
15 import ogr
16 except ImportError:
17 ogr = None
18
19 import os
20 import weakref
21 from math import ceil, log
22
23 from Thuban import _
24 from Thuban.Model import table
25
26 from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT
27 from Thuban.Model.data import RAW_PYTHON, RAW_SHAPEFILE, RAW_WKT
28
29 # Raw data in ogr format
30 RAW_OGRSHAPES = "RAW_OGRSHAPES"
31
32
33
34 def has_ogr_support():
35 """Return whether this Thuban instance supports ogr file formats
36
37 Having OGR support means that the ogr module can be
38 imported.
39 """
40 return ogr is not None
41
42 if ogr is not None:
43 # mapping from ogr-lib shapetype and table constants to our constants
44 ogrlib_shapetypes = {ogr.wkbPolygon: SHAPETYPE_POLYGON,
45 ogr.wkbLineString: SHAPETYPE_ARC,
46 ogr.wkbPoint: SHAPETYPE_POINT}
47
48 fieldtype_map = {ogr.OFTString: table.FIELDTYPE_STRING,
49 ogr.OFTInteger: table.FIELDTYPE_INT,
50 ogr.OFTReal: table.FIELDTYPE_DOUBLE}
51
52
53 class OGRShape:
54
55 """Represent one shape of an OGRShapeStore"""
56
57 def __init__(self, ogrlayer, shapeid):
58 self.ogrlayer = ogrlayer
59 self.shapeid = shapeid
60
61 def compute_bbox(self):
62 """
63 Return the bounding box of the shape as a tuple (minx,miny,maxx,maxy)
64 """
65 shape = self.ogrlayer.GetFeature(self.shapeid)
66 geom = shape.GetGeometryRef()
67 minx, maxx, miny, maxy = geom.GetEnvelope()
68 return (minx, miny, maxx, maxy)
69
70 def ShapeID(self):
71 return self.shapeid
72
73 # diese Methode funktioniert vielleicht noch nicht für andere Formate als shp
74 #(wenn ein polygon aus mehreren
75 # Ringen besteht o.ä., hat ein Geometry-Objekt mehr als einen GeometryRef().----------------------------
76 def Points(self):
77 """Return the coordinates of the shape as a list of lists of pairs"""
78 feature = self.ogrlayer.GetFeature(self.shapeid)
79 geometry = feature.GetGeometryRef()
80 while geometry.GetGeometryCount() != 0:
81 geometry = geometry.GetGeometryRef(0)
82 points = []
83 for point in range(geometry.GetPointCount()):
84 x = geometry.GetX(point)
85 y = geometry.GetY(point)
86 points.append((x, y))
87 points = [points]
88 return points
89
90 def RawData(self):
91 """Return the shape id to use with the shapestore"""
92 return self.shapeid
93
94 def OGRLayer(self):
95 """Return the ogrlayer object"""
96 return self.ogrlayer
97
98
99 class OGRShapeStore:
100
101 """Corresponds to an OGRLayer object, containing features/shapes and providing all methods Thuban
102 needs."""
103
104 def __init__(self, session, filename, layername):
105 # Make the filename absolute. The filename will be
106 # interpreted relative to that anyway, but when saving a
107 # session we need to compare absolute paths and it's usually
108 # safer to always work with absolute paths.
109
110 self.filename = os.path.abspath(filename)
111 self.layername = layername
112
113 self.ogrdatasource = ogr.Open(self.filename)
114 self.ogrlayer = (self.ogrdatasource).GetLayerByName(layername)
115 self.table = OGRTable(self.ogrdatasource, self.ogrlayer)
116
117 self._open_ogrlayer(layername)
118
119 def _open_ogrlayer(self, layername):
120 self.numshapes = self.ogrlayer.GetFeatureCount()
121 self.shapetype = self.ogrlayer.GetLayerDefn().GetGeomType()
122 extent = self.ogrlayer.GetExtent()
123
124 if extent:
125 self.bbox = [extent[0], extent[2], extent[1], extent[3]]
126 else:
127 self.bbox = None
128
129 self.shapetype = ogrlib_shapetypes[self.shapetype]
130
131 def OGRLayer(self):
132 """Return the OGRLayer object"""
133 return self.ogrlayer
134
135 def FileName(self):
136 """Return the filename used to open the file"""
137 return self.filename
138
139 def FileType(self):
140 """Return the filetype. This is always the string 'ogr-file'"""
141 return "ogr-file"
142
143 def ShapeType(self):
144 """Return the type of the shapes in the shapestore.
145
146 This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.
147 """
148 return self.shapetype
149
150 def RawShapeFormat(self):
151 """Return the raw data format of the shape data, i.e. RAW_OGRSHAPES"""
152 return RAW_OGRSHAPES
153
154 def NumShapes(self):
155 """Return the number of shapes in the shape store"""
156 return self.numshapes
157
158 def BoundingBox(self):
159 """Return the bounding box of the shapes in the shapestore.
160 """
161 return self.bbox
162
163 def ShapesInRegion(self, bbox):
164 """Return an iterable over the shapes that overlap the bounding box.
165
166 The bbox parameter should be the bounding box as a tuple in the
167 form (minx, miny, maxx, maxy) in the coordinate system of the
168 shape store.
169
170 The method GetFID() returns feature IDs starting from 0. In Thuban feature IDs start with 1.
171 """
172 # Bind a few globals to locals to make it a bit faster
173 cls = OGRShape
174 ogrlayer = self.ogrlayer
175
176 left, bottom, right, top = bbox
177
178 # create a geometry which can be passed to the layer as spatial filter
179 bboxpolygon = ogr.CreateGeometryFromWkt('Polygon((%s %s, %s %s, %s %s, %s %s))'
180 %(left, bottom, left, top, right, top, right, bottom))
181 bboxpolygon.CloseRings()
182
183 if ogrlayer.GetSpatialRef():
184 bboxpolygon.AssignSpatialReference(ogrlayer.GetSpatialRef())
185
186 ogrlayer.ResetReading()
187 ogrlayer.SetSpatialFilter(bboxpolygon)
188 numFeatures = ogrlayer.GetFeatureCount()
189 for feature in range(numFeatures):
190 nextFeature = ogrlayer.GetNextFeature()
191 yield cls(ogrlayer, nextFeature.GetFID())
192 ogrlayer.SetSpatialFilter(None)
193 bboxpolygon.Destroy()
194
195 def AllShapes(self):
196 """Return an iterable over the shapes in the shape store."""
197 for i in xrange(self.NumShapes()):
198 yield OGRShape(self.ogrlayer, i)
199
200 def Shape(self, index):
201 """Return the shape with index index"""
202 return OGRShape(self.ogrlayer, index)
203
204 def Table(self):
205 """Return the table containing the attribute data"""
206 return self.table
207
208 def Dependencies(self):
209 """Return the empty tuple."""
210 return ()
211
212 def OrigShapeStore(self):
213 """Return None."""
214 return None
215
216
217 class OGRTable:
218
219 """A Table for an ogr file
220 """
221
222 def __init__(self, ds, layer):
223 """Initialize the OGRTable.
224
225 ds should be an instance of OGRDatasource.
226 layer should be an instance of OGRLayer.
227 """
228
229 self.datasource = ds
230 self.layer = layer
231 self.tablename = layer.GetName()
232
233 # Map column names and indices to column objects.
234 self.column_map = {}
235
236 self._fetch_table_information()
237
238 def _fetch_table_information(self):
239 """Internal: Update information about the table"""
240 self.columns = []
241
242 layerdefn = self.layer.GetLayerDefn()
243 for i in range(layerdefn.GetFieldCount()):
244 fielddef = layerdefn.GetFieldDefn(i)
245 fieldname = fielddef.GetName()
246 fieldtype = fieldtype_map[fielddef.GetType()]
247 fieldindex = layerdefn.GetFieldIndex(fieldname)
248 col = OGRColumn(fieldname, fieldtype, fieldindex)
249 if col is not None:
250 self.columns.append(col)
251
252 for col in self.columns:
253 self.column_map[col.name] = col
254 self.column_map[col.index] = col
255
256 def TableName(self):
257 """Return the name of the table, which is the name of the layer"""
258 return self.tablename
259
260 def Title(self):
261 """Return the title of the table.
262
263 The title is currently fixed and equal to the tablename
264 """
265 return self.tablename
266
267 def Dependencies(self):
268 """Return an empty tuple."""
269 return ()
270
271 def NumColumns(self):
272 """Return the number of columns."""
273 return len(self.columns)
274
275 def Columns(self):
276 """Return all columns."""
277 return self.columns
278
279 def Column(self, col):
280 """Return the column col. col can be either a string or an integer."""
281 return self.column_map[col]
282
283 def HasColumn(self, col):
284 """Return if column col exists. col can be either a string or an integer."""
285 return self.column_map.has_key(col)
286
287 def NumRows(self):
288 """Return the number of rows in the table, which equals the number of features in the layer."""
289 return self.layer.GetFeatureCount()
290
291 def RowIdToOrdinal(self, gid):
292 """Return the row ordinal given its id"""
293 return self.layer.GetFeature(gid).GetFID()
294
295 def RowOrdinalToId(self, num):
296 """Return the rowid for given its ordinal"""
297 return self.layer.GetFeature(num).GetFID()
298
299 def ReadRowAsDict(self, row, row_is_ordinal = 0):
300 """Return a dictionary which contains all the fields."""
301 layerdef = self.layer.GetLayerDefn()
302 feature = self.layer.GetFeature(row)
303 result = {}
304 for i in range(feature.GetFieldCount()):
305 fielddef = layerdef.GetFieldDefn(i)
306 result[fielddef.GetName()] = feature.GetField(i)
307 return result
308
309 def ReadValue(self, row, col, row_is_ordinal = 0):
310 """Return the requested value."""
311 if col is None:
312 return None
313 else:
314 feature = self.layer.GetFeature(row)
315 return feature.GetField(col)
316
317 def ValueRange(self, col):
318 """Return the value range of the given column (given as string)."""
319 result = self.datasource.ExecuteSQL("SELECT min(%s), max(%s) FROM %s"
320 %(col, col, self.layer.GetName()))
321 result.ResetReading()
322 feature = result.GetNextFeature()
323 try:
324 min = feature.GetField(0)
325 max = feature.GetField(1)
326 except:
327 min = 0
328 max = 0
329 self.datasource.ReleaseResultSet(result)
330 return (min, max)
331
332 def UniqueValues(self, col):
333 """Return all the values being found in the column (given as string)."""
334 result = self.datasource.ExecuteSQL("SELECT DISTINCT %s FROM %s ORDER BY %s" %(col, self.layer.GetName(),col))
335 values = []
336 while 1:
337 feature = result.GetNextFeature()
338 if feature is None:
339 break
340 values.append(feature.GetField(0))
341 self.datasource.ReleaseResultSet(result)
342 return values
343
344 def SimpleQuery(self, left, comparison, right):
345 """Return the FIDs resulting from the given query."""
346 if comparison not in ("==", "!=", "<", "<=", ">=", ">"):
347 raise ValueError("Comparison operator %r not allowed" % comparison)
348
349 if comparison == "==":
350 comparison = "="
351
352 if isinstance(right, OGRColumn):
353 right_template = right.name
354 else:
355 right_template = right
356
357 query = "SELECT FID FROM %s WHERE '%s' %s %s ORDER BY FID" %(self.tablename, left.name, comparison, right_template)
358
359 lay = self.datasource.ExecuteSQL(query)
360 result = []
361 while 1:
362 feature = lay.GetNextFeature()
363 if feature is None:
364 break
365 result.append(feature.GetField(0))
366 self.datasource.ReleaseResultSet(lay)
367 return result
368
369
370 class OGRColumn:
371
372 """Column description for a table for an ogr file
373 """
374
375 def __init__(self, name, type, index):
376 self.name = name
377 self.type = type
378 self.index = index

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26