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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1587 - (hide 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 bh 599 # Copyright (c) 2002, 2003 by Intevation GmbH
2 bh 331 # 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 bh 1587 import mockgeo
20 bh 331 import support
21     support.initthuban()
22    
23     import shapelib
24 bh 336 import dbflib
25 bh 331
26 bh 723 from Thuban.Model.session import Session
27 bh 1538 from Thuban.Model.layer import BaseLayer, Layer, RasterLayer
28     from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT
29 bh 331 from Thuban.Model.messages import LAYER_LEGEND_CHANGED, \
30 bh 1142 LAYER_VISIBILITY_CHANGED, LAYER_SHAPESTORE_REPLACED, LAYER_CHANGED
31 bh 1088 from Thuban.Model.table import FIELDTYPE_DOUBLE, FIELDTYPE_STRING, MemoryTable
32 jonathan 947 from Thuban.Model.proj import Projection
33 bh 996 from Thuban.Model.data import DerivedShapeStore
34 bh 1452 from Thuban.Model.classification import Classification, ClassGroupSingleton, \
35     ClassGroupRange
36 bh 331
37 jonathan 1174 import Thuban.Model.resource
38    
39 bh 331 class TestLayer(unittest.TestCase, support.FileTestMixin,
40     support.FloatComparisonMixin):
41    
42     """Test cases for different layer (shape) types"""
43    
44 bh 723 def setUp(self):
45 bh 996 """Create a session self.session and initialize self.layer to None"""
46 bh 723 self.session = Session("Test session for %s" % self.__class__)
47 bh 996 self.layer = None
48 bh 723
49     def tearDown(self):
50 bh 996 """Call the layer's Destroy method and set session and layer to None"""
51 bh 723 self.session = None
52 bh 996 if self.layer is not None:
53     self.layer.Destroy()
54     self.layer = None
55 bh 723
56 jonathan 947 def build_path(self, filename):
57     return os.path.join("..", "Data", "iceland", filename)
58 bh 996
59 bh 839 def open_shapefile(self, filename):
60     """Open and return a shapestore for filename in the iceland data set"""
61 jonathan 947 return self.session.OpenShapefile(self.build_path(filename))
62 bh 839
63 jonathan 947 def test_base_layer(self):
64 bh 996 layer = self.layer = BaseLayer("Test BaseLayer")
65 jonathan 947 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 jonathan 1278 self.failIf(layer.HasShapes())
77    
78 jonathan 947 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 bh 331 def test_arc_layer(self):
92     """Test Layer with arc shapes"""
93 bh 996 layer = self.layer = Layer("Test Layer",
94     self.open_shapefile("roads-line.shp"))
95 jonathan 1278 self.failUnless(layer.HasClassification())
96     self.failUnless(layer.HasShapes())
97 bh 331 self.assertEquals(layer.ShapeType(), SHAPETYPE_ARC)
98     self.assertEquals(layer.NumShapes(), 839)
99     shape = layer.Shape(32)
100 bh 1551 self.assertPointListEquals(shape.Points(),
101     [[(-15.082174301147461, 66.27738189697265),
102     (-15.026350021362305, 66.27339172363281)]])
103 bh 331 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 jonathan 832
109     self.assertFloatSeqEqual(layer.ShapesBoundingBox([32]),
110     [-15.082174301147461, 66.27339172363281,
111     -15.026350021362305, 66.27738189697265])
112    
113     shape = layer.Shape(33)
114 bh 1551 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 jonathan 832
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 bh 331 def test_polygon_layer(self):
128     """Test Layer with polygon shapes"""
129 bh 996 layer = self.layer = Layer("Test Layer",
130     self.open_shapefile("political.shp"))
131 jonathan 1278 self.failUnless(layer.HasClassification())
132     self.failUnless(layer.HasShapes())
133 bh 331 self.assertEquals(layer.ShapeType(), SHAPETYPE_POLYGON)
134     self.assertEquals(layer.NumShapes(), 156)
135     shape = layer.Shape(4)
136 bh 1551 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 bh 331 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 bh 996 layer = self.layer = Layer("Test Layer",
150     self.open_shapefile("cultural_landmark-point.shp"))
151 jonathan 1278 self.failUnless(layer.HasClassification())
152     self.failUnless(layer.HasShapes())
153 bh 331 self.assertEquals(layer.ShapeType(), SHAPETYPE_POINT)
154     self.assertEquals(layer.NumShapes(), 34)
155     shape = layer.Shape(0)
156 bh 1551 self.assertPointListEquals(shape.Points(),
157     [[(-22.711074829101562, 66.36572265625)]])
158 bh 331 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 bh 1587 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 bh 331 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 bh 336 # 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 bh 331
196 bh 336 # Now try to open it.
197 bh 996 layer = self.layer = Layer("Empty Layer",
198     self.session.OpenShapefile(shapefilename))
199 bh 331 self.assertEquals(layer.BoundingBox(), None)
200     self.assertEquals(layer.LatLongBoundingBox(), None)
201     self.assertEquals(layer.NumShapes(), 0)
202    
203 bh 839 def test_get_field_type(self):
204     """Test Layer.GetFieldType()"""
205 bh 996 layer = self.layer = Layer("Test Layer",
206     self.open_shapefile("roads-line.shp"))
207 bh 839 self.assertEquals(layer.GetFieldType("LENGTH"), FIELDTYPE_DOUBLE)
208     self.assertEquals(layer.GetFieldType("non existing"), None)
209 bh 331
210 jonathan 947 def test_raster_layer(self):
211 jonathan 1174 if not Thuban.Model.resource.has_gdal_support():
212 bh 1555 raise support.SkipTest("No gdal support")
213 jonathan 1174
214 jonathan 947 filename = self.build_path("island.tif")
215     layer = RasterLayer("Test RasterLayer", filename)
216 jonathan 1278 self.failIf(layer.HasClassification())
217     self.failIf(layer.HasShapes())
218 jonathan 947 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 bh 839
226 bh 996 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 jonathan 1262
236 bh 1538 self.assertEquals(layer.ShapeType(), SHAPETYPE_ARC)
237     self.assertEquals(layer.NumShapes(), 839)
238     shape = layer.Shape(32)
239 bh 1551 self.assertPointListEquals(shape.Points(),
240     [[(-15.082174301147, 66.277381896972),
241     (-15.026350021362, 66.273391723632)]])
242 bh 1538 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 jonathan 1262
249 bh 1538 self.assertFloatSeqEqual(layer.ShapesBoundingBox([32]),
250     [-15.082174301147461, 66.27339172363281,
251     -15.026350021362305, 66.27738189697265])
252    
253 bh 996 finally:
254     store = derived = None
255 jonathan 947
256 bh 996
257 bh 1142 class SetShapeStoreTests(unittest.TestCase, support.SubscriberMixin):
258 bh 1088
259     def setUp(self):
260     """Create a layer with a classification as self.layer"""
261 bh 1142 self.clear_messages()
262 bh 1088 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 jonathan 1438 self.classification = Classification()
268 bh 1088 self.classification.AppendGroup(ClassGroupSingleton("FARM"))
269 bh 1452 self.layer.SetClassificationColumn("CLPTLABEL")
270 bh 1088 self.layer.SetClassification(self.classification)
271 bh 1142 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 bh 1088
278     def tearDown(self):
279 bh 1142 self.clear_messages()
280 bh 1088 self.layer.Destroy()
281     self.session.Destroy()
282     self.session = self.layer = self.store = self.classification = None
283    
284     def test_sanity(self):
285 bh 1142 """SetShapeStoreTests sanity check
286    
287     Test the initial state of the test case instances after setUp.
288     """
289 bh 1088 cls = self.layer.GetClassification()
290     self.assert_(cls is self.classification)
291 bh 1452 field = self.layer.GetClassificationColumn()
292 jonathan 1438 self.assertEquals(field, "CLPTLABEL")
293     self.assertEquals(self.layer.GetFieldType(field), FIELDTYPE_STRING)
294 bh 1088 self.assertEquals(self.layer.GetClassification().GetNumGroups(), 1)
295 bh 1142 self.failIf(self.layer.WasModified())
296 bh 1088
297 bh 1142 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 bh 1088 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 bh 1142 self.check_messages([(self.layer, LAYER_CHANGED),
313     (self.layer, LAYER_SHAPESTORE_REPLACED)])
314 bh 1088
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 bh 1142 self.check_messages([(self.layer, LAYER_SHAPESTORE_REPLACED)])
323 bh 1088
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 bh 1142 self.check_messages([(self.layer, LAYER_CHANGED),
333     (self.layer, LAYER_SHAPESTORE_REPLACED)])
334 bh 1088
335    
336 bh 1452 class TestLayerModification(unittest.TestCase, support.SubscriberMixin):
337 bh 331
338     """Test cases for Layer method that modify the layer.
339     """
340    
341     def setUp(self):
342 bh 723 """Clear the list of received messages and create a layer and a session
343 bh 331
344 bh 723 The layer is bound to self.layer and the session to self.session.
345 bh 331 """
346     self.clear_messages()
347 bh 723 self.session = Session("Test session for %s" % self.__class__)
348     filename = os.path.join("..", "Data", "iceland", "political.shp")
349 bh 331 self.layer = Layer("Test Layer",
350 bh 723 self.session.OpenShapefile(filename))
351 bh 331 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 bh 1452 self.layer.Subscribe(LAYER_CHANGED, self.subscribe_with_params,
357     LAYER_CHANGED)
358 bh 331
359     def tearDown(self):
360     """Clear the list of received messages and explictly destroy self.layer
361     """
362     self.layer.Destroy()
363 bh 723 self.layer = None
364     self.session.Destroy()
365     self.session = None
366 bh 331 self.clear_messages()
367    
368 bh 1452 def test_sanity(self):
369     """TestLayerModification Sanity Checks"""
370 bh 331 # 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 bh 1452 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 jonathan 395 #
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 bh 331
424    
425     if __name__ == "__main__":
426 bh 599 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