/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/data.py
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/Thuban/Model/data.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1972 - (show annotations)
Mon Nov 24 19:23:08 2003 UTC (21 years, 3 months ago) by bh
Original Path: trunk/thuban/Thuban/Model/data.py
File MIME type: text/x-python
File size: 9345 byte(s)
(ShapefileStore._open_shapefile)
(ShapefileStore.__init__): Factor opening the shapefile into a
separate method (the new _open_shapefile). This makes the code a
bit more readable but the real reason is that it makes some evil
hacks easier. :-)

1 # Copyright (C) 2003 by Intevation GmbH
2 # Authors:
3 # Bernhard Herzog <[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 """Data source abstractions"""
9
10 from __future__ import generators
11
12 __version__ = "$Revision$"
13 # $Source$
14 # $Id$
15
16 import os
17 import weakref
18 from math import ceil, log
19
20 import shapelib
21 import shptree
22 import table
23 import transientdb
24
25 from Thuban import _
26
27 # Shape type constants
28 SHAPETYPE_POLYGON = "polygon"
29 SHAPETYPE_ARC = "arc"
30 SHAPETYPE_POINT = "point"
31
32 # mapping from shapelib shapetype constants to our constants
33 shapelib_shapetypes = {shapelib.SHPT_POLYGON: SHAPETYPE_POLYGON,
34 shapelib.SHPT_ARC: SHAPETYPE_ARC,
35 shapelib.SHPT_POINT: SHAPETYPE_POINT}
36
37 #
38 # Raw shape data formats
39 #
40
41 # Raw data is the same as that returned by the points method.
42 RAW_PYTHON = "RAW_PYTHON"
43
44 # Raw data is a shapefile. The Shape object will use the shapeid as the
45 # raw data.
46 RAW_SHAPEFILE = "RAW_SHAPEFILE"
47
48 # Raw data in well-known text format
49 RAW_WKT = "RAW_WKT"
50
51
52 class ShapefileShape:
53
54 """Represent one shape of a shapefile"""
55
56 def __init__(self, shapefile, shapeid):
57 self.shapefile = shapefile
58 self.shapeid = shapeid
59
60 def compute_bbox(self):
61 """
62 Return the bounding box of the shape as a tuple (minx,miny,maxx,maxy)
63 """
64 xs = []
65 ys = []
66 for part in self.Points():
67 for x, y in part:
68 xs.append(x)
69 ys.append(y)
70 return (min(xs), min(ys), max(xs), max(ys))
71
72 def ShapeID(self):
73 return self.shapeid
74
75 def Points(self):
76 """Return the coordinates of the shape as a list of lists of pairs"""
77 shape = self.shapefile.read_object(self.shapeid)
78 points = shape.vertices()
79 if self.shapefile.info()[1] == shapelib.SHPT_POINT:
80 points = [points]
81 return points
82
83 def RawData(self):
84 """Return the shape id to use with the shapefile"""
85 return self.shapeid
86
87 def Shapefile(self):
88 """Return the shapefile object"""
89 return self.shapefile
90
91
92 class ShapeTable(transientdb.AutoTransientTable):
93
94 """A Table that depends on a ShapefileStore
95
96 Intended use is by the ShapefileStore for the table associated with
97 the shapefiles.
98 """
99
100 def __init__(self, store, db, table):
101 """Initialize the ShapeTable.
102
103 Parameters:
104 store -- the ShapefileStore the table is to depend on
105 db -- The transient database to use
106 table -- the table
107 """
108 transientdb.AutoTransientTable.__init__(self, db, table)
109 self.store = weakref.ref(store)
110
111 def Dependencies(self):
112 """Return a tuple containing the shapestore"""
113 return (self.store(),)
114
115
116 class ShapefileStore:
117
118 """Combine a shapefile and the corresponding DBF file into one object"""
119
120 def __init__(self, session, filename):
121 # Make the filename absolute. The filename will be
122 # interpreted relative to that anyway, but when saving a
123 # session we need to compare absolute paths and it's usually
124 # safer to always work with absolute paths.
125 self.filename = os.path.abspath(filename)
126
127 self.dbftable = table.DBFTable(filename)
128 self.table = ShapeTable(self, session.TransientDB(), self.dbftable)
129 self._open_shapefile()
130
131 def _open_shapefile(self):
132 self.shapefile = shapelib.ShapeFile(self.filename)
133 self.numshapes, shapetype, mins, maxs = self.shapefile.info()
134 if self.numshapes:
135 self.bbox = mins[:2] + maxs[:2]
136 else:
137 self.bbox = None
138 self.shapetype = shapelib_shapetypes[shapetype]
139
140 # estimate a good depth for the quad tree. Each depth multiplies
141 # the number of nodes by four, therefore we basically take the
142 # base 4 logarithm of the number of shapes.
143 if self.numshapes < 4:
144 maxdepth = 1
145 else:
146 maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))
147
148 self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,
149 maxdepth)
150
151 def Table(self):
152 """Return the table containing the attribute data"""
153 return self.table
154
155 def Shapefile(self):
156 """Return the shapefile object"""
157 return self.shapefile
158
159 def FileName(self):
160 """Return the filename used to open the shapefile"""
161 return self.filename
162
163 def FileType(self):
164 """Return the filetype. This is always the string 'shapefile'"""
165 return "shapefile"
166
167 def ShapeType(self):
168 """Return the type of the shapes in the shapestore.
169
170 This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.
171 """
172 return self.shapetype
173
174 def RawShapeFormat(self):
175 """Return the raw data format of the shape data, i.e. RAW_SHAPEFILE"""
176 return RAW_SHAPEFILE
177
178 def NumShapes(self):
179 """Return the number of shapes in the shape store"""
180 return self.numshapes
181
182 def Dependencies(self):
183 """Return the empty tuple.
184
185 The ShapefileStore doesn't depend on anything else.
186 """
187 return ()
188
189 def OrigShapeStore(self):
190 """Return None.
191
192 The ShapefileStore was not derived from another shapestore.
193 """
194 return None
195
196 def BoundingBox(self):
197 """Return the bounding box of the shapes in the shapestore.
198
199 The coordinate system used is whatever was used in the shapefile.
200 If the shapefile is empty, return None.
201 """
202 return self.bbox
203
204 def ShapesInRegion(self, bbox):
205 """Return an iterable over the shapes that overlap the bounding box.
206
207 The bbox parameter should be the bounding box as a tuple in the
208 form (minx, miny, maxx, maxy) in the coordinate system of the
209 shape store.
210 """
211 # Bind a few globals to locals to make it a bit faster
212 cls = ShapefileShape
213 shapefile = self.shapefile
214
215 left, bottom, right, top = bbox
216 for i in self.shapetree.find_shapes((left, bottom), (right, top)):
217 yield cls(shapefile, i)
218
219 def AllShapes(self):
220 """Return an iterable over the shapes in the shape store."""
221 for i in xrange(self.NumShapes()):
222 yield ShapefileShape(self.shapefile, i)
223
224 def Shape(self, index):
225 """Return the shape with index index"""
226 return ShapefileShape(self.shapefile, index)
227
228
229
230 class DerivedShapeStore:
231
232 """A ShapeStore derived from other shapestores or tables"""
233
234 def __init__(self, shapestore, table):
235 """Initialize the derived shapestore.
236
237 The arguments are a shapestore for the shapedata and a table for
238 the tabular data.
239
240 Raises ValueError if the number of shapes in the shapestore
241 is different from the number of rows in the table.
242 """
243
244 numShapes = shapestore.Shapefile().info()[0]
245 if numShapes != table.NumRows():
246 raise ValueError(_("Table not compatible with shapestore."))
247
248 self.shapestore = shapestore
249 self.table = table
250
251 def Table(self):
252 """Return the table"""
253 return self.table
254
255 def Shapefile(self):
256 """Return the shapefile of the underlying shapestore"""
257 return self.shapestore.Shapefile()
258
259 def Dependencies(self):
260 """Return a tuple containing the shapestore and the table"""
261 return (self.shapestore, self.table)
262
263 def OrigShapeStore(self):
264 """
265 Return the original shapestore the derived store was instantiated with
266 """
267 return self.shapestore
268
269 def Shape(self, index):
270 """Return the shape with index index"""
271 return self.shapestore.Shape(index)
272
273 def ShapesInRegion(self, bbox):
274 """Return the ids of the shapes that overlap the box.
275
276 This method is simply delegated to the shapestore the
277 DerivedShapeStore was instantiated with.
278 """
279 return self.shapestore.ShapesInRegion(bbox)
280
281 def AllShapes(self):
282 """Return an iterable over the shapes in the shape store.
283
284 This method is simply delegated to the shapestore the
285 DerivedShapeStore was instantiated with.
286 """
287 return self.shapestore.AllShapes()
288
289 def ShapeType(self):
290 """Return the type of the shapes in the layer.
291
292 This method is simply delegated to the shapestore the
293 DerivedShapeStore was instantiated with.
294 """
295 return self.shapestore.ShapeType()
296
297 def RawShapeFormat(self):
298 """Return the raw data format of the shapes.
299
300 This method is simply delegated to the shapestore the
301 DerivedShapeStore was instantiated with.
302 """
303 return self.shapestore.RawShapeFormat()
304
305 def NumShapes(self):
306 """Return the number of shapes in the shapestore."""
307 return self.shapestore.NumShapes()
308
309 def BoundingBox(self):
310 """Return the bounding box of the shapes in the shapestore.
311
312 This method is simply delegated to the shapestore the
313 DerivedShapeStore was instantiated with.
314 """
315 return self.shapestore.BoundingBox()

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26