/[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 1587 - (show annotations)
Fri Aug 15 10:31:07 2003 UTC (21 years, 6 months ago) by bh
Original Path: trunk/thuban/test/test_layer.py
File MIME type: text/x-python
File size: 18526 byte(s)
* Thuban/Model/layer.py (Layer.ShapesInRegion): Apply the layer
projection to all corners of the bounding box to get a better
approximation of the projected bounding box

* test/test_layer.py (TestLayer.test_point_layer_with_projection):
New. Test coordinate handling of a layer with a projection.
Catches the bug fixed in Layer.ShapesInRegion

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