/[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 2734 - (show annotations)
Thu Mar 1 12:42:59 2007 UTC (18 years ago) by bramz
File MIME type: text/x-python
File size: 22831 byte(s)
made a copy
1 # Copyright (c) 2002, 2003, 2004, 2005 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, ClassGroupPattern
36 from Thuban.Model.color import Color
37
38 import Thuban.Model.resource
39
40 class TestLayer(unittest.TestCase, support.FileTestMixin,
41 support.FloatComparisonMixin):
42
43 """Test cases for different layer (shape) types"""
44
45 def setUp(self):
46 """Create a session self.session and initialize self.layer to None"""
47 self.session = Session("Test session for %s" % self.__class__)
48 self.layer = None
49
50 def tearDown(self):
51 """Call the layer's Destroy method and set session and layer to None"""
52 self.session.Destroy()
53 self.session = None
54 if self.layer is not None:
55 self.layer.Destroy()
56 self.layer = None
57
58 def build_path(self, filename):
59 return os.path.join("..", "Data", "iceland", filename)
60
61 def open_shapefile(self, filename):
62 """Open and return a shapestore for filename in the iceland data set"""
63 return self.session.OpenShapefile(self.build_path(filename))
64
65 def test_base_layer(self):
66 layer = self.layer = BaseLayer("Test BaseLayer")
67 self.assertEquals(layer.Title(), "Test BaseLayer")
68 self.failUnless(layer.Visible())
69
70 # toggle visibility
71 layer.SetVisible(False)
72 self.failIf(layer.Visible())
73
74 layer.SetVisible(True)
75 self.failUnless(layer.Visible())
76
77 self.failIf(layer.HasClassification())
78 self.failIf(layer.HasShapes())
79
80 self.assertEquals(layer.GetProjection(), None)
81
82 # set/get projection
83 proj = Projection(["proj=utm", "zone=26", "ellps=clrk66"])
84
85 layer.SetProjection(proj)
86 self.failUnless(layer.GetProjection() is proj)
87
88 # __init__ with other arguments
89 layer = BaseLayer("Test BaseLayer", False, proj)
90 self.failIf(layer.Visible())
91 self.failUnless(layer.GetProjection() is proj)
92
93 def test_arc_layer(self):
94 """Test Layer with arc shapes"""
95 layer = self.layer = Layer("Test Layer",
96 self.open_shapefile("roads-line.shp"))
97 self.failUnless(layer.HasClassification())
98 self.failUnless(layer.HasShapes())
99 self.assertEquals(layer.ShapeType(), SHAPETYPE_ARC)
100 self.assertEquals(layer.NumShapes(), 839)
101 shape = layer.Shape(32)
102 self.assertPointListEquals(shape.Points(),
103 [[(-15.082174301147461, 66.27738189697265),
104 (-15.026350021362305, 66.27339172363281)]])
105 self.assertFloatSeqEqual(layer.BoundingBox(),
106 [-24.450359344482422, 63.426830291748047,
107 -13.55668830871582, 66.520111083984375])
108 shapes = layer.ShapesInRegion((-24.0, 64.0, -23.75, 64.25))
109 self.assertEquals([s.ShapeID() for s in shapes],
110 [613, 726, 838])
111
112 self.assertFloatSeqEqual(layer.ShapesBoundingBox([32]),
113 [-15.082174301147461, 66.27339172363281,
114 -15.026350021362305, 66.27738189697265])
115
116 shape = layer.Shape(33)
117 self.assertPointListEquals(shape.Points(),
118 [[(-22.24850654602050, 66.30645751953125),
119 (-22.23273086547851, 66.29407501220703),
120 (-22.23158073425293, 66.2876892089843),
121 (-22.24631881713867, 66.27006530761718)]])
122
123 self.assertFloatSeqEqual(layer.ShapesBoundingBox([32, 33]),
124 [-22.248506546020508, 66.270065307617188,
125 -15.026350021362305, 66.30645751953125])
126
127 self.assertEquals(layer.ShapesBoundingBox([]), None)
128 self.assertEquals(layer.ShapesBoundingBox(None), None)
129
130 def test_polygon_layer(self):
131 """Test Layer with polygon shapes"""
132 layer = self.layer = Layer("Test Layer",
133 self.open_shapefile("political.shp"))
134 self.failUnless(layer.HasClassification())
135 self.failUnless(layer.HasShapes())
136 self.assertEquals(layer.ShapeType(), SHAPETYPE_POLYGON)
137 self.assertEquals(layer.NumShapes(), 156)
138 shape = layer.Shape(4)
139 self.assertPointListEquals(shape.Points(),
140 [[(-22.40639114379882, 64.714111328125),
141 (-22.41621208190918, 64.7160034179687),
142 (-22.40605163574218, 64.719200134277),
143 (-22.40639114379882, 64.714111328125)]])
144 self.assertFloatSeqEqual(layer.BoundingBox(),
145 [-24.546524047851562, 63.286754608154297,
146 -13.495815277099609, 66.563774108886719])
147 shapes = layer.ShapesInRegion((-24.0, 64.0, -23.9, 64.1))
148 self.assertEquals([s.ShapeID() for s in shapes],
149 [91, 92, 144, 146, 148, 150, 152, 153])
150
151 def test_point_layer(self):
152 """Test Layer with point shapes"""
153 layer = self.layer = Layer("Test Layer",
154 self.open_shapefile("cultural_landmark-point.shp"))
155 self.failUnless(layer.HasClassification())
156 self.failUnless(layer.HasShapes())
157 self.assertEquals(layer.ShapeType(), SHAPETYPE_POINT)
158 self.assertEquals(layer.NumShapes(), 34)
159 shape = layer.Shape(0)
160 self.assertPointListEquals(shape.Points(),
161 [[(-22.711074829101562, 66.36572265625)]])
162 self.assertFloatSeqEqual(layer.BoundingBox(),
163 [-23.806047439575195, 63.405960083007812,
164 -15.12291431427002, 66.36572265625])
165 shapes = layer.ShapesInRegion((-24.0, 64.0, -23.80, 64.1))
166 self.assertEquals([s.ShapeID() for s in shapes],
167 [0, 1, 2, 3, 4, 5, 27, 28, 29, 30, 31])
168
169 def test_arc_layer_with_projection(self):
170 """Test Layer with point shapes and a projection"""
171 # We use mock data here so that we have precise control over the
172 # values
173 table = MemoryTable([("FOO", FIELDTYPE_STRING)], [("bla",)])
174 store = mockgeo.SimpleShapeStore(SHAPETYPE_ARC,
175 [[[(9884828.7209840547, 5607720.9774499247),
176 (11298336.04640449, 9287823.2044059951)]]],
177 table)
178 layer = self.layer = Layer("Test Layer", store)
179
180 proj = Projection(["proj=lcc", "lon_0=0", "lat_1=20n", "lat_2=60n",
181 "ellps=clrk66"])
182 layer.SetProjection(proj)
183
184 self.assertFloatSeqEqual(layer.BoundingBox(),
185 (9884828.7209840547, 5607720.9774499247,
186 11298336.04640449, 9287823.2044059951))
187 self.assertFloatSeqEqual(layer.LatLongBoundingBox(),
188 (90.0, -8.90043373, 120, 11.1616263))
189 shapes = layer.ShapesInRegion((100, -10, 150, +10))
190 self.assertEquals([s.ShapeID() for s in shapes], [0])
191 self.assertFloatSeqEqual(layer.ShapesBoundingBox([0]),
192 (90.0, -8.90043373, 120, 11.1616263))
193
194 # Test a very large bounding box in the query. Naive inverse
195 # projection will create infs instead of proper coordinate
196 # values and a different result (an empty list instead of [0])
197 shapes = layer.ShapesInRegion((-180, -170, 200, +120))
198 self.assertEquals([s.ShapeID() for s in shapes],[0])
199
200 def test_empty_layer(self):
201 """Test Layer with empty shape file"""
202 # create an empty shape file
203 shapefilename = self.temp_file_name("layer_empty.shp")
204 shp = shapelib.create(shapefilename, shapelib.SHPT_POLYGON)
205 shp.close()
206 # create an empty DBF file too because Thuban can't cope yet
207 # with missing DBF file.
208 dbffilename = self.temp_file_name("layer_empty.dbf")
209 dbf = dbflib.create(dbffilename)
210 dbf.add_field("NAME", dbflib.FTString, 20, 0)
211 dbf.close()
212
213 # Now try to open it.
214 layer = self.layer = Layer("Empty Layer",
215 self.session.OpenShapefile(shapefilename))
216 self.assertEquals(layer.BoundingBox(), None)
217 self.assertEquals(layer.LatLongBoundingBox(), None)
218 self.assertEquals(layer.NumShapes(), 0)
219
220 def test_get_field_type(self):
221 """Test Layer.GetFieldType()"""
222 layer = self.layer = Layer("Test Layer",
223 self.open_shapefile("roads-line.shp"))
224 self.assertEquals(layer.GetFieldType("LENGTH"), FIELDTYPE_DOUBLE)
225 self.assertEquals(layer.GetFieldType("non existing"), None)
226
227 def test_raster_layer(self):
228 if not Thuban.Model.resource.has_gdal_support():
229 raise support.SkipTest("No gdal support")
230
231 filename = self.build_path("island.tif")
232 layer = RasterLayer("Test RasterLayer", filename)
233 self.failIf(layer.HasClassification())
234 self.failIf(layer.HasShapes())
235 self.assertEquals(layer.MaskType(), layer.MASK_BIT)
236 self.assertEquals(layer.GetImageFilename(), os.path.abspath(filename))
237 self.assertFloatSeqEqual(layer.BoundingBox(),
238 [-24.5500000, 63.2833330,
239 -13.4916670, 66.5666670])
240 self.assertFloatSeqEqual(layer.LatLongBoundingBox(),
241 [-24.5500000, 63.2833330,
242 -13.4916670, 66.5666670])
243
244 info = layer.ImageInfo()
245 self.failIf(info is None)
246 self.failUnless(info.has_key("nBands"))
247 self.failUnless(info.has_key("Size"))
248 self.failUnless(info.has_key("Driver"))
249 self.failUnless(info.has_key("BandData"))
250
251 self.assertEquals(info["nBands"], 1)
252 self.assertEquals(info["Size"], (5002, 394))
253 self.assertEquals(info["Driver"], "GTiff")
254 self.assertEquals(info["BandData"], [(0.0, 140.0)])
255
256 def test_derived_store(self):
257 """Test layer with derived store"""
258 layer = self.layer = Layer("Test Layer",
259 self.open_shapefile("roads-line.shp"))
260 try:
261 store = layer.ShapeStore()
262 derived = DerivedShapeStore(store, store.Table())
263 layer.SetShapeStore(derived)
264 self.assert_(layer.ShapeStore() is derived)
265
266 self.assertEquals(layer.ShapeType(), SHAPETYPE_ARC)
267 self.assertEquals(layer.NumShapes(), 839)
268 shape = layer.Shape(32)
269 self.assertPointListEquals(shape.Points(),
270 [[(-15.082174301147, 66.277381896972),
271 (-15.026350021362, 66.273391723632)]])
272 self.assertFloatSeqEqual(layer.BoundingBox(),
273 [-24.450359344482422, 63.426830291748047,
274 -13.55668830871582, 66.520111083984375])
275 shapes = layer.ShapesInRegion((-24.0, 64.0, -23.75, 64.25))
276 self.assertEquals([s.ShapeID() for s in shapes],
277 [613, 726, 838])
278
279 self.assertFloatSeqEqual(layer.ShapesBoundingBox([32]),
280 [-15.082174301147461, 66.27339172363281,
281 -15.026350021362305, 66.27738189697265])
282
283 finally:
284 store = derived = None
285
286
287 class SetShapeStoreTests(unittest.TestCase, support.SubscriberMixin):
288
289 def setUp(self):
290 """Create a layer with a classification as self.layer"""
291 self.clear_messages()
292 self.session = Session("Test session for %s" % self.__class__)
293 self.shapefilename = os.path.join("..", "Data", "iceland",
294 "cultural_landmark-point.dbf")
295 self.store = self.session.OpenShapefile(self.shapefilename)
296 self.layer = Layer("test layer", self.store)
297 self.classification = Classification()
298 self.classification.AppendGroup(ClassGroupSingleton("FARM"))
299 self.layer.SetClassificationColumn("CLPTLABEL")
300 self.layer.SetClassification(self.classification)
301 self.layer.UnsetModified()
302 self.layer.Subscribe(LAYER_SHAPESTORE_REPLACED,
303 self.subscribe_with_params,
304 LAYER_SHAPESTORE_REPLACED)
305 self.layer.Subscribe(LAYER_CHANGED,
306 self.subscribe_with_params, LAYER_CHANGED)
307
308 def tearDown(self):
309 self.clear_messages()
310 self.layer.Destroy()
311 self.session.Destroy()
312 self.session = self.layer = self.store = self.classification = None
313
314 def test_sanity(self):
315 """SetShapeStoreTests sanity check
316
317 Test the initial state of the test case instances after setUp.
318 """
319 cls = self.layer.GetClassification()
320 self.assert_(cls is self.classification)
321 field = self.layer.GetClassificationColumn()
322 self.assertEquals(field, "CLPTLABEL")
323 self.assertEquals(self.layer.GetFieldType(field), FIELDTYPE_STRING)
324 self.assertEquals(self.layer.GetClassification().GetNumGroups(), 1)
325 self.failIf(self.layer.WasModified())
326
327 def test_set_shape_store_modified_flag(self):
328 """Test whether Layer.SetShapeStore() sets the modified flag"""
329 memtable = MemoryTable([("FOO", FIELDTYPE_STRING)],
330 [("bla",)] * self.layer.ShapeStore().Table().NumRows())
331 self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
332
333 self.assert_(self.layer.WasModified())
334
335 def test_set_shape_store_different_field_name(self):
336 """Test Layer.SetShapeStore() with different column name"""
337 memtable = MemoryTable([("FOO", FIELDTYPE_STRING)],
338 [("bla",)] * self.layer.ShapeStore().Table().NumRows())
339 self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
340 # The classification should contain only the default group now.
341 self.assertEquals(self.layer.GetClassification().GetNumGroups(), 0)
342 self.check_messages([(self.layer, LAYER_CHANGED),
343 (self.layer, LAYER_SHAPESTORE_REPLACED)])
344
345 def test_set_shape_store_same_field(self):
346 """Test Layer.SetShapeStore() with same column name and type"""
347 memtable = MemoryTable([("CLPTLABEL", FIELDTYPE_STRING)],
348 [("bla",)] * self.layer.ShapeStore().Table().NumRows())
349 self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
350 # The classification should be the same as before
351 self.assert_(self.layer.GetClassification() is self.classification)
352 self.check_messages([(self.layer, LAYER_SHAPESTORE_REPLACED)])
353
354 def test_set_shape_store_same_field_different_type(self):
355 """Test Layer.SetShapeStore() with same column name but different type
356 """
357 memtable = MemoryTable([("CLPTLABEL", FIELDTYPE_DOUBLE)],
358 [(0.0,)] * self.layer.ShapeStore().Table().NumRows())
359 self.layer.SetShapeStore(DerivedShapeStore(self.store, memtable))
360 # The classification should contain only the default group now.
361 self.assertEquals(self.layer.GetClassification().GetNumGroups(), 0)
362 self.check_messages([(self.layer, LAYER_CHANGED),
363 (self.layer, LAYER_SHAPESTORE_REPLACED)])
364
365
366 class TestLayerModification(unittest.TestCase, support.SubscriberMixin):
367
368 """Test cases for Layer method that modify the layer.
369 """
370
371 def setUp(self):
372 """Clear the list of received messages and create a layer and a session
373
374 The layer is bound to self.layer and the session to self.session.
375 """
376 self.clear_messages()
377 self.session = Session("Test session for %s" % self.__class__)
378 self.filename = os.path.join("..", "Data", "iceland", "political.shp")
379 self.layer = Layer("Test Layer",
380 self.session.OpenShapefile(self.filename))
381 self.layer.Subscribe(LAYER_LEGEND_CHANGED, self.subscribe_with_params,
382 LAYER_LEGEND_CHANGED)
383 self.layer.Subscribe(LAYER_VISIBILITY_CHANGED,
384 self.subscribe_with_params,
385 LAYER_VISIBILITY_CHANGED)
386 self.layer.Subscribe(LAYER_CHANGED, self.subscribe_with_params,
387 LAYER_CHANGED)
388
389 def tearDown(self):
390 """Clear the list of received messages and explictly destroy self.layer
391 """
392 self.layer.Destroy()
393 self.layer = None
394 self.session.Destroy()
395 self.session = None
396 self.clear_messages()
397
398 def build_path(self, filename):
399 return os.path.join("..", "Data", "iceland", filename)
400
401 def test_sanity(self):
402 """TestLayerModification Sanity Checks"""
403 # test default settings
404 self.failIf(self.layer.WasModified())
405 self.assertEquals(self.layer.Visible(), 1)
406 # no messages should have been produced
407 self.check_messages([])
408
409 def test_visibility(self):
410 """Test Layer visibility"""
411 self.layer.SetVisible(0)
412 self.assertEquals(self.layer.Visible(), 0)
413 self.check_messages([(self.layer, LAYER_VISIBILITY_CHANGED)])
414
415 # currently, modifying the visibility doesn't count as changing
416 # the layer.
417 self.failIf(self.layer.WasModified())
418
419 def test_set_classification_numerical(self):
420 """Test Layer.SetClassification numerical"""
421 classification = Classification()
422 classification.AppendGroup(ClassGroupRange((0.0, 0.1)))
423
424 self.layer.SetClassification(classification)
425 self.layer.SetClassificationColumn("AREA")
426
427 self.check_messages([(self.layer, LAYER_CHANGED),
428 (self.layer, LAYER_CHANGED)])
429 self.failUnless(self.layer.WasModified())
430
431 self.clear_messages()
432 self.layer.UnsetModified()
433
434 # change only the classification column. This should issue a
435 # LAYER_CHANGED message as well.
436 self.layer.SetClassificationColumn("PERIMETER")
437
438 self.check_messages([(self.layer, LAYER_CHANGED)])
439 self.failUnless(self.layer.WasModified())
440
441 def test_set_classification_textual(self):
442 """Test Layer.SetClassification textual"""
443 classification = Classification()
444 classification.AppendGroup(ClassGroupPattern("I"))
445
446 self.layer.SetClassification(classification)
447 self.layer.SetClassificationColumn("POPYCOUN")
448
449 self.check_messages([(self.layer, LAYER_CHANGED),
450 (self.layer, LAYER_CHANGED)])
451 self.failUnless(self.layer.WasModified())
452
453 self.clear_messages()
454 self.layer.UnsetModified()
455
456 # change only the classification column. This should issue a
457 # LAYER_CHANGED message as well.
458 self.layer.SetClassificationColumn("POPYREG")
459
460 self.check_messages([(self.layer, LAYER_CHANGED)])
461 self.failUnless(self.layer.WasModified())
462
463
464 def test_tree_info(self):
465 """Test Layer.TreeInfo"""
466 self.assertEquals(self.layer.TreeInfo(),
467 ("Layer 'Test Layer'",
468 ['Filename: %s' % os.path.abspath(self.filename),
469 'Shown',
470 'Shapes: 156',
471 'Extent (lat-lon): (-24.5465, 63.2868, -13.4958, 66.5638)',
472 'Shapetype: Polygon',
473 self.layer.GetClassification()]))
474
475 def test_raster_layer(self):
476 if not Thuban.Model.resource.has_gdal_support():
477 raise support.SkipTest("No gdal support")
478
479
480 filename = self.build_path("island.tif")
481 layer = RasterLayer("Test RasterLayer", filename)
482
483 layer.Subscribe(LAYER_CHANGED, self.subscribe_with_params,
484 LAYER_CHANGED)
485
486 self.assertEquals(layer.MaskType(), layer.MASK_BIT)
487
488 layer.SetMaskType(layer.MASK_NONE)
489 self.failIf(layer.MaskType() != layer.MASK_NONE)
490 self.check_messages([(layer, LAYER_CHANGED)])
491 self.clear_messages()
492
493 layer.SetMaskType(layer.MASK_NONE)
494 self.failIf(layer.MaskType() != layer.MASK_NONE)
495 self.check_messages([])
496 self.clear_messages()
497
498 layer.SetMaskType(layer.MASK_BIT)
499 self.failIf(layer.MaskType() != layer.MASK_BIT)
500 self.check_messages([(layer, LAYER_CHANGED)])
501 self.clear_messages()
502
503 layer.SetMaskType(layer.MASK_BIT)
504 self.failIf(layer.MaskType() != layer.MASK_BIT)
505 self.check_messages([])
506 self.clear_messages()
507
508 layer.SetMaskType(layer.MASK_ALPHA)
509 self.failIf(layer.MaskType() != layer.MASK_ALPHA)
510
511 layer.SetOpacity(0)
512 self.assertEquals(layer.Opacity(), 0)
513 layer.SetOpacity(0.5)
514 self.assertEquals(layer.Opacity(), 0.5)
515
516 self.clear_messages()
517 layer.SetOpacity(1)
518 self.assertEquals(layer.Opacity(), 1)
519 self.check_messages([(layer, LAYER_CHANGED)])
520 self.clear_messages()
521
522 self.assertRaises(ValueError, layer.SetOpacity, -0.1)
523 self.assertRaises(ValueError, layer.SetOpacity, 1.1)
524
525 layer.SetMaskType(layer.MASK_NONE)
526 self.clear_messages()
527 self.assertEquals(layer.Opacity(), 1)
528 self.check_messages([])
529 self.clear_messages()
530
531 self.assertRaises(ValueError, layer.SetMaskType, -1)
532 self.assertRaises(ValueError, layer.SetMaskType, 4)
533
534
535 if __name__ == "__main__":
536 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