/[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 1605 - (show annotations)
Tue Aug 19 11:00:40 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: 9171 byte(s)
Add very basic postgis database support and the corresponding test
cases. The test cases require a PostgreSQL + postgis installation
but no existing database. The database will be created
automatically by the test cases

* test/README: Add note about skipped tests and the requirements
of the postgis tests.

* Thuban/Model/postgisdb.py: New. Basic postgis database support.

* test/test_postgis_db.py: New. Test cases for the postgis
support.

* Thuban/Model/wellknowntext.py: New. Parser for well-known-text
format

* test/test_wellknowntext.py: New. Test cases for the
wellknowntext parser

* test/postgissupport.py: New. Support module for tests involving
a postgis database.

* test/support.py (execute_as_testsuite): Shut down the postmaster
if it's still running after the tests

* Thuban/Model/data.py (RAW_WKT): New constant for raw data in
well known text format

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.shapefile = shapelib.ShapeFile(self.filename)
128 self.dbftable = table.DBFTable(filename)
129 self.table = ShapeTable(self, session.TransientDB(), self.dbftable)
130
131 self.numshapes, shapetype, mins, maxs = self.shapefile.info()
132 if self.numshapes:
133 self.bbox = mins[:2] + maxs[:2]
134 else:
135 self.bbox = None
136 self.shapetype = shapelib_shapetypes[shapetype]
137
138 # estimate a good depth for the quad tree. Each depth multiplies
139 # the number of nodes by four, therefore we basically take the
140 # base 4 logarithm of the number of shapes.
141 if self.numshapes < 4:
142 maxdepth = 1
143 else:
144 maxdepth = int(ceil(log(self.numshapes / 4.0) / log(4)))
145
146 self.shapetree = shptree.SHPTree(self.shapefile.cobject(), 2,
147 maxdepth)
148
149 def Table(self):
150 """Return the table containing the attribute data"""
151 return self.table
152
153 def Shapefile(self):
154 """Return the shapefile object"""
155 return self.shapefile
156
157 def FileName(self):
158 """Return the filename used to open the shapefile"""
159 return self.filename
160
161 def FileType(self):
162 """Return the filetype. This is always the string 'shapefile'"""
163 return "shapefile"
164
165 def ShapeType(self):
166 """Return the type of the shapes in the shapestore.
167
168 This is either SHAPETYPE_POINT, SHAPETYPE_ARC or SHAPETYPE_POLYGON.
169 """
170 return self.shapetype
171
172 def RawShapeFormat(self):
173 """Return the raw data format of the shape data, i.e. RAW_SHAPEFILE"""
174 return RAW_SHAPEFILE
175
176 def NumShapes(self):
177 """Return the number of shapes in the shape store"""
178 return self.numshapes
179
180 def Dependencies(self):
181 """Return the empty tuple.
182
183 The ShapefileStore doesn't depend on anything else.
184 """
185 return ()
186
187 def OrigShapeStore(self):
188 """Return None.
189
190 The ShapefileStore was not derived from another shapestore.
191 """
192 return None
193
194 def BoundingBox(self):
195 """Return the bounding box of the shapes in the shapestore.
196
197 The coordinate system used is whatever was used in the shapefile.
198 If the shapefile is empty, return None.
199 """
200 return self.bbox
201
202 def ShapesInRegion(self, bbox):
203 """Return an iterable over the shapes that overlap the bounding box.
204
205 The bbox parameter should be the bounding box as a tuple in the
206 form (minx, miny, maxx, maxy) in the coordinate system of the
207 shape store.
208 """
209 left, bottom, right, top = bbox
210 for i in self.shapetree.find_shapes((left, bottom), (right, top)):
211 yield ShapefileShape(self.shapefile, i)
212
213 def AllShapes(self):
214 """Return an iterable over the shapes in the shape store."""
215 for i in xrange(self.NumShapes()):
216 yield ShapefileShape(self.shapefile, i)
217
218 def Shape(self, index):
219 """Return the shape with index index"""
220 return ShapefileShape(self.shapefile, index)
221
222
223
224 class DerivedShapeStore:
225
226 """A ShapeStore derived from other shapestores or tables"""
227
228 def __init__(self, shapestore, table):
229 """Initialize the derived shapestore.
230
231 The arguments are a shapestore for the shapedata and a table for
232 the tabular data.
233
234 Raises ValueError if the number of shapes in the shapestore
235 is different from the number of rows in the table.
236 """
237
238 numShapes = shapestore.Shapefile().info()[0]
239 if numShapes != table.NumRows():
240 raise ValueError(_("Table not compatible with shapestore."))
241
242 self.shapestore = shapestore
243 self.table = table
244
245 def Table(self):
246 """Return the table"""
247 return self.table
248
249 def Shapefile(self):
250 """Return the shapefile of the underlying shapestore"""
251 return self.shapestore.Shapefile()
252
253 def Dependencies(self):
254 """Return a tuple containing the shapestore and the table"""
255 return (self.shapestore, self.table)
256
257 def OrigShapeStore(self):
258 """
259 Return the original shapestore the derived store was instantiated with
260 """
261 return self.shapestore
262
263 def Shape(self, index):
264 """Return the shape with index index"""
265 return self.shapestore.Shape(index)
266
267 def ShapesInRegion(self, bbox):
268 """Return the ids of the shapes that overlap the box.
269
270 This method is simply delegated to the shapestore the
271 DerivedShapeStore was instantiated with.
272 """
273 return self.shapestore.ShapesInRegion(bbox)
274
275 def AllShapes(self):
276 """Return an iterable over the shapes in the shape store.
277
278 This method is simply delegated to the shapestore the
279 DerivedShapeStore was instantiated with.
280 """
281 return self.shapestore.AllShapes()
282
283 def ShapeType(self):
284 """Return the type of the shapes in the layer.
285
286 This method is simply delegated to the shapestore the
287 DerivedShapeStore was instantiated with.
288 """
289 return self.shapestore.ShapeType()
290
291 def RawShapeFormat(self):
292 """Return the raw data format of the shapes.
293
294 This method is simply delegated to the shapestore the
295 DerivedShapeStore was instantiated with.
296 """
297 return self.shapestore.RawShapeFormat()
298
299 def NumShapes(self):
300 """Return the number of shapes in the shapestore."""
301 return self.shapestore.NumShapes()
302
303 def BoundingBox(self):
304 """Return the bounding box of the shapes in the shapestore.
305
306 This method is simply delegated to the shapestore the
307 DerivedShapeStore was instantiated with.
308 """
309 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