/[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 1551 - (show annotations)
Wed Aug 6 17:21:07 2003 UTC (21 years, 7 months ago) by bh
Original Path: trunk/thuban/Thuban/Model/data.py
File MIME type: text/x-python
File size: 7776 byte(s)
* Thuban/Model/data.py (ShapefileStore.Shape): For consistency, a
Shape object will always have the coordinates as a list of list of
coordinate pairs (tuples).
(Shape.compute_bbox): Adapt to new representation.

* Thuban/UI/viewport.py (ViewPort.find_shape_at)
(ViewPort.LabelShapeAt): Adapt to new coordinate representation in
Shape objects.

* test/test_shapefilestore.py
(ShapefileStoreTests.assertFloatTuplesEqual)
(ShapefileStoreTests.assertPointListEquals): Rename to
assertPointListEquals and change purpose to checking equality of
the lists returned by Shape.Points().
(TestShapefileStoreArc.test_shape)
(TestShapefileStorePolygon.test_shape)
(TestShapefileStorePoint.test_shape): Use the new
assertPointListEquals instead of assertFloatTuplesEqual

* test/test_layer.py (TestLayer.assertFloatTuplesEqual)
(TestLayer.assertPointListEquals): Rename to assertPointListEquals
and change purpose to checking equality of the lists returned by
Shape.Points().
(TestLayer.test_arc_layer, TestLayer.test_arc_layer)
(TestLayer.test_polygon_layer, TestLayer.test_point_layer)
(TestLayer.test_derived_store): Use the new assertPointListEquals
instead of assertFloatTuplesEqual

* test/test_derivedshapestore.py
(TestDerivedShapeStore.assertFloatTuplesEqual)
(TestDerivedShapeStore.assertPointListEquals): Rename to
assertPointListEquals and change purpose to checking equality of
the lists returned by Shape.Points().
(TestDerivedShapeStore.test_shape): Use the new
assertPointListEquals instead of assertFloatTuplesEqual

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