/[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 1593 - (show annotations)
Fri Aug 15 14:10:27 2003 UTC (21 years, 6 months ago) by bh
Original Path: trunk/thuban/Thuban/Model/data.py
File MIME type: text/x-python
File size: 9113 byte(s)
Change the way shapes are returned by a shape store. The
ShapesInRegion method returns an iterator over actual shape
objects instead of a list of shape ids.

* Thuban/Model/data.py (ShapefileShape.ShapeID): New. Return shape
id.
(ShapefileStore.ShapesInRegion): Return an iterator over the
shapes which yields shape objects instead of returning a list of
shape ids
(ShapefileStore.AllShapes): New. Return an iterator over all
shapes in the shape store
(DerivedShapeStore.AllShapes): New. Like in ShapefileStore

* Thuban/Model/layer.py (Layer.ShapesInRegion): Update
doc-string.

* Thuban/UI/baserenderer.py
(BaseRenderer.layer_ids, BaseRenderer.layer_shapes): Rename to
layer_shapes and make it return an iterator containg shapes
instead of a list of ids.
(BaseRenderer.draw_shape_layer): Update doc-string; Adapt to
layer_shapes() change

* Thuban/UI/renderer.py (ScreenRenderer.layer_ids)
(ScreenRenderer.layer_shapes): Rename as in BaseRenderer

* Thuban/UI/viewport.py (ViewPort._find_shape_in_layer): Adapt to
changes in the ShapesInRegion return value.
(ViewPort._get_hit_tester): Remove commented out code

* test/mockgeo.py (SimpleShapeStore.ShapesInRegion): Adapt to the
new return value.
(SimpleShapeStore.AllShapes): New. Implement this method too.

* test/test_layer.py (TestLayer.test_arc_layer)
(TestLayer.test_polygon_layer, TestLayer.test_point_layer)
(TestLayer.test_point_layer_with_projection)
(TestLayer.test_derived_store): Adapt to changes in the
ShapesInRegion return value.

* test/test_shapefilestore.py
(TestShapefileStoreArc.test_shapes_in_region)
(TestShapefileStorePolygon.test_shapes_in_region)
(TestShapefileStorePoint.test_shapes_in_region): Adapt to changes
in the ShapesInRegion return value.
(TestShapefileStorePoint.test_all_shapes)
(TestShapefileStoreArc.test_shape_shapeid): New tests for the new
methods

* test/test_derivedshapestore.py
(TestDerivedShapeStore.test_shapes_in_region): Adapt to changes in
the ShapesInRegion return value.
(TestDerivedShapeStore.test_all_shapes)
(TestDerivedShapeStore.test_shape_shapeid): New tests for the new
methods

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