/[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 2644 - (show annotations)
Tue Jul 5 16:30:51 2005 UTC (19 years, 8 months ago) by bh
Original Path: trunk/thuban/test/test_layer.py
File MIME type: text/x-python
File size: 21974 byte(s)
* Thuban/Model/layer.py (Layer.__mangle_bounding_box)
(Layer.ClipBoundingBox): Rename ClipBoundingBox to
__mangle_bounding_box.  See the comments in the code and RT #2845

* test/test_layer.py (TestLayer.test_arc_layer_with_projection):
Remove the explicit test of ClipBoundingBox.  The method isn't
public anymore and the direct call in the test wasn't necessary in
the first place.  If ClipBoundingBox (now __mangle_bounding_box)
isn't called, the return value of ShapesInRegion will be
different.

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
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(self):
420 """Test Layer.SetClassification"""
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
442 def test_tree_info(self):
443 """Test Layer.TreeInfo"""
444 self.assertEquals(self.layer.TreeInfo(),
445 ("Layer 'Test Layer'",
446 ['Filename: %s' % os.path.abspath(self.filename),
447 'Shown',
448 'Shapes: 156',
449 'Extent (lat-lon): (-24.5465, 63.2868, -13.4958, 66.5638)',
450 'Shapetype: Polygon',
451 self.layer.GetClassification()]))
452
453 def test_raster_layer(self):
454 if not Thuban.Model.resource.has_gdal_support():
455 raise support.SkipTest("No gdal support")
456
457
458 filename = self.build_path("island.tif")
459 layer = RasterLayer("Test RasterLayer", filename)
460
461 layer.Subscribe(LAYER_CHANGED, self.subscribe_with_params,
462 LAYER_CHANGED)
463
464 self.assertEquals(layer.MaskType(), layer.MASK_BIT)
465
466 layer.SetMaskType(layer.MASK_NONE)
467 self.failIf(layer.MaskType() != layer.MASK_NONE)
468 self.check_messages([(layer, LAYER_CHANGED)])
469 self.clear_messages()
470
471 layer.SetMaskType(layer.MASK_NONE)
472 self.failIf(layer.MaskType() != layer.MASK_NONE)
473 self.check_messages([])
474 self.clear_messages()
475
476 layer.SetMaskType(layer.MASK_BIT)
477 self.failIf(layer.MaskType() != layer.MASK_BIT)
478 self.check_messages([(layer, LAYER_CHANGED)])
479 self.clear_messages()
480
481 layer.SetMaskType(layer.MASK_BIT)
482 self.failIf(layer.MaskType() != layer.MASK_BIT)
483 self.check_messages([])
484 self.clear_messages()
485
486 layer.SetMaskType(layer.MASK_ALPHA)
487 self.failIf(layer.MaskType() != layer.MASK_ALPHA)
488
489 layer.SetOpacity(0)
490 self.assertEquals(layer.Opacity(), 0)
491 layer.SetOpacity(0.5)
492 self.assertEquals(layer.Opacity(), 0.5)
493
494 self.clear_messages()
495 layer.SetOpacity(1)
496 self.assertEquals(layer.Opacity(), 1)
497 self.check_messages([(layer, LAYER_CHANGED)])
498 self.clear_messages()
499
500 self.assertRaises(ValueError, layer.SetOpacity, -0.1)
501 self.assertRaises(ValueError, layer.SetOpacity, 1.1)
502
503 layer.SetMaskType(layer.MASK_NONE)
504 self.clear_messages()
505 self.assertEquals(layer.Opacity(), 1)
506 self.check_messages([])
507 self.clear_messages()
508
509 self.assertRaises(ValueError, layer.SetMaskType, -1)
510 self.assertRaises(ValueError, layer.SetMaskType, 4)
511
512
513 if __name__ == "__main__":
514 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