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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2435 - (hide 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 nhueffme 2435 # 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