/[thuban]/branches/WIP-pyshapelib-bramz/test/test_layer.py
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/test/test_layer.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1768 - (show annotations)
Thu Oct 2 15:15:04 2003 UTC (21 years, 5 months ago) by bh
Original Path: trunk/thuban/test/test_layer.py
File MIME type: text/x-python
File size: 18797 byte(s)
(TestLayer.test_empty_layer): Explicitly
close the dbf file we create so that it's contents have been
written properly.

1 # Copyright (c) 2002, 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 Thuban for details.
7
8 """
9 Test the Layer class
10 """
11
12 __version__ = "$Revision$"
13 # $Source$
14 # $Id$
15
16 import os
17 import unittest
18
19 import mockgeo
20 import support
21 support.initthuban()
22
23 import shapelib
24 import dbflib
25
26 from Thuban.Model.session import Session
27 from Thuban.Model.layer import BaseLayer, Layer, RasterLayer
28 from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT
29 from Thuban.Model.messages import LAYER_LEGEND_CHANGED, \
30 LAYER_VISIBILITY_CHANGED, LAYER_SHAPESTORE_REPLACED, LAYER_CHANGED
31 from Thuban.Model.table import FIELDTYPE_DOUBLE, FIELDTYPE_STRING, MemoryTable
32 from Thuban.Model.proj import Projection
33 from Thuban.Model.data import DerivedShapeStore
34 from Thuban.Model.classification import Classification, ClassGroupSingleton, \
35 ClassGroupRange
36
37 import Thuban.Model.resource
38
39 class TestLayer(unittest.TestCase, support.FileTestMixin,
40 support.FloatComparisonMixin):
41
42 """Test cases for different layer (shape) types"""
43
44 def setUp(self):
45 """Create a session self.session and initialize self.layer to None"""
46 self.session = Session("Test session for %s" % self.__class__)
47 self.layer = None
48
49 def tearDown(self):
50 """Call the layer's Destroy method and set session and layer to None"""
51 self.session.Destroy()
52 self.session = None
53 if self.layer is not None:
54 self.layer.Destroy()
55 self.layer = None
56
57 def build_path(self, filename):
58 return os.path.join("..", "Data", "iceland", filename)
59
60 def open_shapefile(self, filename):
61 """Open and return a shapestore for filename in the iceland data set"""
62 return self.session.OpenShapefile(self.build_path(filename))
63
64 def test_base_layer(self):
65 layer = self.layer = BaseLayer("Test BaseLayer")
66 self.assertEquals(layer.Title(), "Test BaseLayer")
67 self.failUnless(layer.Visible())
68
69 # toggle visibility
70 layer.SetVisible(False)
71 self.failIf(layer.Visible())
72
73 layer.SetVisible(True)
74 self.failUnless(layer.Visible())
75
76 self.failIf(layer.HasClassification())
77 self.failIf(layer.HasShapes())
78
79 self.assertEquals(layer.GetProjection(), None)
80
81 # set/get projection
82 proj = Projection(["proj=utm", "zone=26", "ellps=clrk66"])
83
84 layer.SetProjection(proj)
85 self.failUnless(layer.GetProjection() is proj)
86
87 # __init__ with other arguments
88 layer = BaseLayer("Test BaseLayer", False, proj)
89 self.failIf(layer.Visible())
90 self.failUnless(layer.GetProjection() is proj)
91
92 def test_arc_layer(self):
93 """Test Layer with arc shapes"""
94 layer = self.layer = Layer("Test Layer",
95 self.open_shapefile("roads-line.shp"))
96 self.failUnless(layer.HasClassification())
97 self.failUnless(layer.HasShapes())
98 self.assertEquals(layer.ShapeType(), SHAPETYPE_ARC)
99 self.assertEquals(layer.NumShapes(), 839)
100 shape = layer.Shape(32)
101 self.assertPointListEquals(shape.Points(),
102 [[(-15.082174301147461, 66.27738189697265),
103 (-15.026350021362305, 66.27339172363281)]])
104 self.assertFloatSeqEqual(layer.BoundingBox(),
105 [-24.450359344482422, 63.426830291748047,
106 -13.55668830871582, 66.520111083984375])
107 shapes = layer.ShapesInRegion((-24.0, 64.0, -23.75, 64.25))
108 self.assertEquals([s.ShapeID() for s in shapes],
109 [613, 726, 838])
110
111 self.assertFloatSeqEqual(layer.ShapesBoundingBox([32]),
112 [-15.082174301147461, 66.27339172363281,
113 -15.026350021362305, 66.27738189697265])
114
115 shape = layer.Shape(33)
116 self.assertPointListEquals(shape.Points(),
117 [[(-22.24850654602050, 66.30645751953125),
118 (-22.23273086547851, 66.29407501220703),
119 (-22.23158073425293, 66.2876892089843),
120 (-22.24631881713867, 66.27006530761718)]])
121
122 self.assertFloatSeqEqual(layer.ShapesBoundingBox([32, 33]),
123 [-22.248506546020508, 66.270065307617188,
124 -15.026350021362305, 66.30645751953125])
125
126 self.assertEquals(layer.ShapesBoundingBox([]), None)
127 self.assertEquals(layer.ShapesBoundingBox(None), None)
128
129 def test_polygon_layer(self):
130 """Test Layer with polygon shapes"""
131 layer = self.layer = Layer("Test Layer",
132 self.open_shapefile("political.shp"))
133 self.failUnless(layer.HasClassification())
134 self.failUnless(layer.HasShapes())
135 self.assertEquals(layer.ShapeType(), SHAPETYPE_POLYGON)
136 self.assertEquals(layer.NumShapes(), 156)
137 shape = layer.Shape(4)
138 self.assertPointListEquals(shape.Points(),
139 [[(-22.40639114379882, 64.714111328125),
140 (-22.41621208190918, 64.7160034179687),
141 (-22.40605163574218, 64.719200134277),
142 (-22.40639114379882, 64.714111328125)]])
143 self.assertFloatSeqEqual(layer.BoundingBox(),
144 [-24.546524047851562, 63.286754608154297,
145 -13.495815277099609, 66.563774108886719])
146 shapes = layer.ShapesInRegion((-24.0, 64.0, -23.9, 64.1))
147 self.assertEquals([s.ShapeID() for s in shapes],
148 [91, 92, 144, 146, 148, 150, 152, 153])
149
150 def test_point_layer(self):
151 """Test Layer with point shapes"""
152 layer = self.layer = Layer("Test Layer",
153 self.open_shapefile("cultural_landmark-point.shp"))
154 self.failUnless(layer.HasClassification())
155 self.failUnless(layer.HasShapes())
156 self.assertEquals(layer.ShapeType(), SHAPETYPE_POINT)
157 self.assertEquals(layer.NumShapes(), 34)
158 shape = layer.Shape(0)
159 self.assertPointListEquals(shape.Points(),
160 [[(-22.711074829101562, 66.36572265625)]])
161 self.assertFloatSeqEqual(layer.BoundingBox(),
162 [-23.806047439575195, 63.405960083007812,
163 -15.12291431427002, 66.36572265625])
164 shapes = layer.ShapesInRegion((-24.0, 64.0, -23.80, 64.1))
165 self.assertEquals([s.ShapeID() for s in shapes],
166 [0, 1, 2, 3, 4, 5, 27, 28, 29, 30, 31])
167
168 def test_point_layer_with_projection(self):
169 """Test Layer with point shapes and a projection"""
170 # We use mock data here so that we have precise control over the
171 # values
172 table = MemoryTable([("FOO", FIELDTYPE_STRING)], [("bla",)])
173 store = mockgeo.SimpleShapeStore(SHAPETYPE_POINT, [[[(10,10)]]], table)
174 layer = self.layer = Layer("Test Layer", store)
175
176 # Rotation by 45 degrees counter clockwise. This detects a bug
177 # in the ShapesInRegion method which transforms the bounding box
178 # by only transforming two opposite corners because they have
179 # the same x or y coordinates after application of the
180 # projection or its inverse.
181 proj = mockgeo.AffineProjection((1, 1, -1, 1, 0, 0))
182 layer.SetProjection(proj)
183
184 self.assertEquals(layer.BoundingBox(), (10, 10, 10, 10))
185 self.assertEquals(layer.LatLongBoundingBox(), (10.0, 0.0, 10.0, 0.0))
186 shapes = layer.ShapesInRegion((0, 0, 20, 20))
187 self.assertEquals([s.ShapeID() for s in shapes], [0])
188
189 def test_empty_layer(self):
190 """Test Layer with empty shape file"""
191 # create an empty shape file
192 shapefilename = self.temp_file_name("layer_empty.shp")
193 shp = shapelib.create(shapefilename, shapelib.SHPT_POLYGON)
194 shp.close()
195 # create an empty DBF file too because Thuban can't cope yet
196 # with missing DBF file.
197 dbffilename = self.temp_file_name("layer_empty.dbf")
198 dbf = dbflib.create(dbffilename)
199 dbf.add_field("NAME", dbflib.FTString, 20, 0)
200 dbf.close()
201
202 # Now try to open it.
203 layer = self.layer = Layer("Empty Layer",
204 self.session.OpenShapefile(shapefilename))
205 self.assertEquals(layer.BoundingBox(), None)
206 self.assertEquals(layer.LatLongBoundingBox(), None)
207 self.assertEquals(layer.NumShapes(), 0)
208
209 def test_get_field_type(self):
210 """Test Layer.GetFieldType()"""
211 layer = self.layer = Layer("Test Layer",
212 self.open_shapefile("roads-line.shp"))
213 self.assertEquals(layer.GetFieldType("LENGTH"), FIELDTYPE_DOUBLE)
214 self.assertEquals(layer.GetFieldType("non existing"), None)
215
216 def test_raster_layer(self):
217 if not Thuban.Model.resource.has_gdal_support():
218 raise support.SkipTest("No gdal support")
219
220 filename = self.build_path("island.tif")
221 layer = RasterLayer("Test RasterLayer", filename)
222 self.failIf(layer.HasClassification())
223 self.failIf(layer.HasShapes())
224 self.assertEquals(layer.GetImageFilename(), os.path.abspath(filename))
225 self.assertFloatSeqEqual(layer.BoundingBox(),
226 [-24.5500000, 63.2833330,
227 -13.4916670, 66.5666670])
228 self.assertFloatSeqEqual(layer.LatLongBoundingBox(),
229 [-24.5500000, 63.2833330,
230 -13.4916670, 66.5666670])
231
232 def test_derived_store(self):
233 """Test layer with derived store"""
234 layer = self.layer = Layer("Test Layer",
235 self.open_shapefile("roads-line.shp"))
236 try:
237 store = layer.ShapeStore()
238 derived = DerivedShapeStore(store, store.Table())
239 layer.SetShapeStore(derived)
240 self.assert_(layer.ShapeStore() is derived)
241
242 self.assertEquals(layer.ShapeType(), SHAPETYPE_ARC)
243 self.assertEquals(layer.NumShapes(), 839)
244 shape = layer.Shape(32)
245 self.assertPointListEquals(shape.Points(),
246 [[(-15.082174301147, 66.277381896972),
247 (-15.026350021362, 66.273391723632)]])
248 self.assertFloatSeqEqual(layer.BoundingBox(),
249 [-24.450359344482422, 63.426830291748047,
250 -13.55668830871582, 66.520111083984375])
251 shapes = layer.ShapesInRegion((-24.0, 64.0, -23.75, 64.25))
252 self.assertEquals([s.ShapeID() for s in shapes],
253 [613, 726, 838])
254
255 self.assertFloatSeqEqual(layer.ShapesBoundingBox([32]),
256 [-15.082174301147461, 66.27339172363281,
257 -15.026350021362305, 66.27738189697265])
258
259 finally:
260 store = derived = None
261
262
263 class SetShapeStoreTests(unittest.TestCase, support.SubscriberMixin):
264
265 def setUp(self):
266 """Create a layer with a classification as self.layer"""
267 self.clear_messages()
268 self.session = Session("Test session for %s" % self.__class__)
269 self.shapefilename = os.path.join("..", "Data", "iceland",
270 "cultural_landmark-point.dbf")
271 self.store = self.session.OpenShapefile(self.shapefilename)
272 self.layer = Layer("test layer", self.store)
273 self.classification = Classification()
274 self.classification.AppendGroup(ClassGroupSingleton("FARM"))
275 self.layer.SetClassificationColumn("CLPTLABEL")
276 self.layer.SetClassification(self.classification)
277 self.layer.UnsetModified()
278 self.layer.Subscribe(LAYER_SHAPESTORE_REPLACED,
279 self.subscribe_with_params,
280 LAYER_SHAPESTORE_REPLACED)
281 self.layer.Subscribe(LAYER_CHANGED,
282 self.subscribe_with_params, LAYER_CHANGED)
283
284 def tearDown(self):
285 self.clear_messages()
286 self.layer.Destroy()
287 self.session.Destroy()
288 self.session = self.layer = self.store = self.classification = None
289
290 def test_sanity(self):
291 """SetShapeStoreTests sanity check
292
293 Test the initial state of the test case instances after setUp.
294 """
295 cls = self.layer.GetClassification()
296 self.assert_(cls is self.classification)
297 field = self.layer.GetClassificationColumn()
298 self.assertEquals(field, "CLPTLABEL")
299 self.assertEquals(self.layer.GetFieldType(field), FIELDTYPE_STRING)
300 self.assertEquals(self.layer.GetClassification().GetNumGroups(), 1)
301 self.failIf(self.layer.WasModified())
302
303 def test_set_shape_store_modified_flag(self):
304 """Test whether Layer.SetShapeStore() sets the modified flag"""
305 memtable = MemoryTable([("FOO", FIELDTYPE_STRING)],
306 [("bla",)] * self.layer.ShapeStore().Table().NumRows())
307 self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
308
309 self.assert_(self.layer.WasModified())
310
311 def test_set_shape_store_different_field_name(self):
312 """Test Layer.SetShapeStore() with different column name"""
313 memtable = MemoryTable([("FOO", FIELDTYPE_STRING)],
314 [("bla",)] * self.layer.ShapeStore().Table().NumRows())
315 self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
316 # The classification should contain only the default group now.
317 self.assertEquals(self.layer.GetClassification().GetNumGroups(), 0)
318 self.check_messages([(self.layer, LAYER_CHANGED),
319 (self.layer, LAYER_SHAPESTORE_REPLACED)])
320
321 def test_set_shape_store_same_field(self):
322 """Test Layer.SetShapeStore() with same column name and type"""
323 memtable = MemoryTable([("CLPTLABEL", FIELDTYPE_STRING)],
324 [("bla",)] * self.layer.ShapeStore().Table().NumRows())
325 self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
326 # The classification should be the same as before
327 self.assert_(self.layer.GetClassification() is self.classification)
328 self.check_messages([(self.layer, LAYER_SHAPESTORE_REPLACED)])
329
330 def test_set_shape_store_same_field_different_type(self):
331 """Test Layer.SetShapeStore() with same column name but different type
332 """
333 memtable = MemoryTable([("CLPTLABEL", FIELDTYPE_DOUBLE)],
334 [(0.0,)] * self.layer.ShapeStore().Table().NumRows())
335 self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
336 # The classification should contain only the default group now.
337 self.assertEquals(self.layer.GetClassification().GetNumGroups(), 0)
338 self.check_messages([(self.layer, LAYER_CHANGED),
339 (self.layer, LAYER_SHAPESTORE_REPLACED)])
340
341
342 class TestLayerModification(unittest.TestCase, support.SubscriberMixin):
343
344 """Test cases for Layer method that modify the layer.
345 """
346
347 def setUp(self):
348 """Clear the list of received messages and create a layer and a session
349
350 The layer is bound to self.layer and the session to self.session.
351 """
352 self.clear_messages()
353 self.session = Session("Test session for %s" % self.__class__)
354 filename = os.path.join("..", "Data", "iceland", "political.shp")
355 self.layer = Layer("Test Layer",
356 self.session.OpenShapefile(filename))
357 self.layer.Subscribe(LAYER_LEGEND_CHANGED, self.subscribe_with_params,
358 LAYER_LEGEND_CHANGED)
359 self.layer.Subscribe(LAYER_VISIBILITY_CHANGED,
360 self.subscribe_with_params,
361 LAYER_VISIBILITY_CHANGED)
362 self.layer.Subscribe(LAYER_CHANGED, self.subscribe_with_params,
363 LAYER_CHANGED)
364
365 def tearDown(self):
366 """Clear the list of received messages and explictly destroy self.layer
367 """
368 self.layer.Destroy()
369 self.layer = None
370 self.session.Destroy()
371 self.session = None
372 self.clear_messages()
373
374 def test_sanity(self):
375 """TestLayerModification Sanity Checks"""
376 # test default settings
377 self.failIf(self.layer.WasModified())
378 self.assertEquals(self.layer.Visible(), 1)
379 # no messages should have been produced
380 self.check_messages([])
381
382 def test_visibility(self):
383 """Test Layer visibility"""
384 self.layer.SetVisible(0)
385 self.assertEquals(self.layer.Visible(), 0)
386 self.check_messages([(self.layer, LAYER_VISIBILITY_CHANGED)])
387
388 # currently, modifying the visibility doesn't count as changing
389 # the layer.
390 self.failIf(self.layer.WasModified())
391
392 def test_set_classification(self):
393 """Test Layer.SetClassification"""
394 classification = Classification()
395 classification.AppendGroup(ClassGroupRange((0.0, 0.1)))
396
397 self.layer.SetClassification(classification)
398 self.layer.SetClassificationColumn("AREA")
399
400 self.check_messages([(self.layer, LAYER_CHANGED),
401 (self.layer, LAYER_CHANGED)])
402 self.failUnless(self.layer.WasModified())
403
404 self.clear_messages()
405 self.layer.UnsetModified()
406
407 # change only the classification column. This should issue a
408 # LAYER_CHANGED message as well.
409 self.layer.SetClassificationColumn("PERIMETER")
410
411 self.check_messages([(self.layer, LAYER_CHANGED)])
412 self.failUnless(self.layer.WasModified())
413
414
415 #
416 # the tree info now contains Color objects which are difficult to test
417 #
418 # def test_tree_info(self):
419 # """Test Layer.TreeInfo"""
420 # self.assertEquals(self.layer.TreeInfo(),
421 # ("Layer 'Test Layer'",
422 # ['Shown',
423 # 'Shapes: 156',
424 # ('Extent (lat-lon):'
425 # ' (-24.5465, 63.2868, -13.4958, 66.5638)'),
426 # 'Shapetype: Polygon',
427 # 'Fill: None',
428 # 'Outline: (0.000, 0.000, 0.000)']))
429
430
431 if __name__ == "__main__":
432 support.run_tests()

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26