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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2289 - (hide annotations)
Fri Jul 16 19:47:29 2004 UTC (20 years, 7 months ago) by bh
Original Path: trunk/thuban/test/test_viewport.py
File MIME type: text/x-python
File size: 18935 byte(s)
* test/test_viewport.py
(ViewPortTest.test_changing_map_projection): Check that changing
the projection of an empty map shown in a viewport doesn't lead to
exceptions in the viewport's handler for the
MAP_PROJECTION_CHANGED messages

* Thuban/UI/viewport.py (ViewPort.map_projection_changed): Only
try to keep the same region visible when the map actually contains
something

1 bh 2289 # Copyright (c) 2003, 2004 by Intevation GmbH
2 jonathan 1440 # Authors:
3     # Jonathan Coles <[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 interaction with the view
10     """
11    
12     __version__ = "$Revision$"
13     # $Source$
14     # $Id$
15    
16     import os
17     import unittest
18    
19 bh 1608 import postgissupport
20 jonathan 1440 import support
21     support.initthuban()
22    
23     from Thuban.UI.viewport import ViewPort, ZoomInTool, ZoomOutTool, \
24     PanTool, IdentifyTool, LabelTool
25    
26     from Thuban.Model.map import Map
27     from Thuban.Model.proj import Projection
28     from Thuban.Model.layer import Layer
29     from Thuban.Model.session import Session
30     from Thuban.Model.color import Color
31 bh 1608 from Thuban.Model.postgisdb import PostGISConnection
32 bh 1464 from Thuban.UI.messages import SCALE_CHANGED, MAP_REPLACED
33 bh 1781 from Thuban.Model.messages import TITLE_CHANGED
34 jonathan 1440
35 bh 1462 class Event:
36     pass
37 jonathan 1440
38 bh 1462
39 bh 1772 class MockView(ViewPort):
40    
41     def GetTextExtent(self, text):
42     """Mock implementation so that the test cases work"""
43     # arbitrary numbers, really just so the tests pass
44     return 40, 20
45    
46    
47    
48 bh 1462 class SimpleViewPortTest(unittest.TestCase):
49    
50 bh 1464 """Simple ViewPort tests"""
51    
52 bh 1462 def test_default_size(self):
53 bh 1464 """Test ViewPort default size and scale"""
54 bh 1462 port = ViewPort()
55     try:
56     self.assertEquals(port.GetPortSizeTuple(), (400, 300))
57     self.assertEquals(port.scale, 1.0)
58     self.assertEquals(port.offset, (0, 0))
59     finally:
60     port.Destroy()
61    
62 bh 1774 def test_init_with_size(self):
63     """Test ViewPort(<size>)"""
64     port = ViewPort((1001, 1001))
65     try:
66     self.assertEquals(port.GetPortSizeTuple(), (1001, 1001))
67     finally:
68     port.Destroy()
69 bh 1464
70 bh 1774
71 jonathan 1440 class ViewPortTest(unittest.TestCase, support.SubscriberMixin,
72 bh 1608 support.FloatComparisonMixin):
73 jonathan 1440
74     def build_path(self, filename):
75     return os.path.join("..", "Data", "iceland", filename)
76 bh 1462
77 jonathan 1440 def open_shapefile(self, filename):
78     """Open and return a shapestore for filename in the iceland data set"""
79     return self.session.OpenShapefile(self.build_path(filename))
80    
81     def setUp(self):
82     self.session = Session("Test session for %s" % self.__class__)
83    
84     # make view port 1001x1001 so we have an exact center
85 bh 1772 self.port = MockView((1001, 1001))
86 jonathan 1440
87     proj = Projection(["proj=latlong",
88     "to_meter=.017453292519943",
89     "ellps=clrk66"])
90    
91 bh 1464 self.map = map = Map("title", proj)
92 jonathan 1440 layer = Layer("Polygon", self.open_shapefile("political.shp"))
93 bh 1462 layer.GetClassification().GetDefaultGroup()\
94     .GetProperties().SetFill(Color(0,0,0))
95 jonathan 1440 map.AddLayer(layer)
96 bh 1462 layer = Layer("Point",
97     self.open_shapefile("cultural_landmark-point.shp"))
98     layer.GetClassification().GetDefaultGroup()\
99     .GetProperties().SetFill(Color(0,0,0))
100 jonathan 1440 map.AddLayer(layer)
101     layer = Layer("Arc", self.open_shapefile("roads-line.shp"))
102 bh 1462 layer.GetClassification().GetDefaultGroup()\
103     .GetProperties().SetFill(Color(0,0,0))
104 jonathan 1440 map.AddLayer(layer)
105     self.session.AddMap(map)
106    
107     self.layer = layer
108    
109 bh 1464 self.port.SetMap(map)
110 bh 1781 for msg in (SCALE_CHANGED, MAP_REPLACED, TITLE_CHANGED):
111     self.port.Subscribe(msg, self.subscribe_with_params, msg)
112 bh 1464 self.clear_messages()
113 jonathan 1440
114     def tearDown(self):
115     self.port.Destroy()
116     self.session.Destroy()
117 bh 1464 self.map = self.session = self.port = self.layer = None
118 jonathan 1440
119 bh 1462 def test_inital_settings(self):
120     self.failIf(self.port.HasSelectedLayer())
121     self.failIf(self.port.HasSelectedShapes())
122 jonathan 1440
123 bh 1462 def test_win_to_proj(self):
124     self.assertFloatSeqEqual(self.port.win_to_proj(0, 0),
125     (-24.546524047851978, 70.450618743897664))
126     self.assertFloatSeqEqual(self.port.win_to_proj(100, 0),
127     (-23.442557137686929, 70.450618743897664))
128     self.assertFloatSeqEqual(self.port.win_to_proj(0, 100),
129     (-24.546524047851978, 69.346651833732622))
130 jonathan 1440
131 bh 1462 def test_proj_to_win(self):
132     self.assertFloatSeqEqual(self.port.proj_to_win(-24.546524047851978,
133     70.450618743897664),
134     (0, 0))
135     self.assertFloatSeqEqual(self.port.proj_to_win(-23.442557137686929,
136     70.450618743897664),
137     (100, 0))
138     self.assertFloatSeqEqual(self.port.proj_to_win(-24.546524047851978,
139     69.346651833732622),
140     (0, 100))
141    
142 bh 1464 def test_set_map(self):
143     """Test ViewPort.SetMap()"""
144     # The port already has a map. So we set it to None before we set
145     # it to self.map again.
146    
147     # Setting the map to None does not change the scale, but it will
148     # issue a MAP_REPLACED message.
149     self.port.SetMap(None)
150     self.check_messages([(MAP_REPLACED,)])
151    
152     self.clear_messages()
153    
154     self.port.SetMap(self.map)
155     self.check_messages([(90.582425142660739, SCALE_CHANGED),
156     (MAP_REPLACED,)])
157    
158 bh 2289 def test_changing_map_projection(self):
159     """Test ViewPort behavior when changing the map's projection
160    
161     The viewport subscribe's to the map's MAP_PROJECTION_CHANGED
162     messages and tries to adjust the viewport when the projection
163     changes to make sure the map is still visible in the window.
164     There was a bug at one point where the viewport couldn't cope
165     with the map not having a meaningful bounding box in this
166     situation.
167     """
168     # Create a projection and an empty map. We can't use self.map
169     # here because we do need an empty one.
170     themap = Map("title", Projection(["proj=latlong",
171     "to_meter=.017453292519943",
172     "ellps=clrk66"]))
173     # Add the map to self.session so that it's properly destroyed in
174     # tearDown()
175     self.session.AddMap(themap)
176    
177     # Add the map to the view port and clear the messages. Then
178     # we're set for the actual test.
179     self.port.SetMap(themap)
180     self.clear_messages()
181    
182     # The test: set another projection. The viewport tries to
183     # adjust the view so that the currently visible region stays
184     # visible. The viewport has to take into account that the map
185     # is empty, which it didn't in Thuban/UI/viewport.py rev <= 1.16.
186     # This part of the test is OK when the SetProjection call does
187     # not lead to an exception.
188     themap.SetProjection(Projection(["proj=latlong",
189     "to_meter=.017453292519943",
190     "ellps=clrk66"]))
191    
192     # If the map weren't empty the viewport might send SCALE_CHANGED
193     # messages, but it must no do so in this case because the scale
194     # doesn't change.
195     self.check_messages([])
196    
197 jonathan 1440 def testFitRectToWindow(self):
198     rect = self.port.win_to_proj(9, 990) + self.port.win_to_proj(990, 9)
199     self.port.FitRectToWindow(rect)
200 bh 1462 self.assertFloatSeqEqual(rect, self.port.win_to_proj(0, 1000)
201     + self.port.win_to_proj(1000, 0), 1e-1)
202 jonathan 1440
203     def testZoomFactor(self):
204     self.port.FitMapToWindow()
205     rect = self.port.win_to_proj(9, 990) + self.port.win_to_proj(990, 9)
206 bh 1462 proj_rect = self.port.win_to_proj(0,1000)+self.port.win_to_proj(1000,0)
207 jonathan 1440 self.port.ZoomFactor(2)
208     self.port.ZoomFactor(.5)
209 bh 1462 self.assertFloatSeqEqual(rect,
210     self.port.win_to_proj(0, 1000)
211     + self.port.win_to_proj(1000, 0), 1)
212 jonathan 1440
213     point = self.port.win_to_proj(600, 600)
214     self.port.ZoomFactor(2, (600, 600))
215 bh 1462 self.assertFloatSeqEqual(point, self.port.win_to_proj(500, 500), 1e-3)
216     self.port.FitMapToWindow()
217 jonathan 1440
218 bh 1462 proj_rect = self.port.win_to_proj(-499, 1499)\
219     + self.port.win_to_proj(1499, -499)
220 jonathan 1440 self.port.ZoomFactor(.5)
221 bh 1462 self.assertFloatSeqEqual(proj_rect,
222     self.port.win_to_proj(0, 1000)
223     + self.port.win_to_proj(1000, 0), 1)
224 jonathan 1440
225     def testZoomOutToRect(self):
226     self.port.FitMapToWindow()
227     rect = self.port.win_to_proj(9, 990) + self.port.win_to_proj(990, 9)
228 bh 1462 rectTo = self.port.win_to_proj(0, 1000) + self.port.win_to_proj(1000,
229     0)
230 jonathan 1440 self.port.ZoomOutToRect(rect)
231     self.assertFloatSeqEqual(rect, rectTo, 1)
232    
233     def testTranslate(self):
234     self.port.FitMapToWindow()
235 bh 1462 orig_rect = self.port.win_to_proj(0,1000)+self.port.win_to_proj(1000,0)
236 jonathan 1440 for delta in [(0, 0), (5, 0), (0, 5), (5,5),
237     (-5, 0), (0, -5), (-5, -5)]:
238     rect = self.port.win_to_proj(0 + delta[0], 1000 + delta[1]) \
239     + self.port.win_to_proj(1000 + delta[0], 0 + delta[1])
240     self.port.Translate(delta[0], delta[1])
241 bh 1462 self.assertFloatSeqEqual(rect,
242     self.port.win_to_proj(0, 1000)
243     + self.port.win_to_proj(1000, 0), 1)
244 jonathan 1440 self.port.Translate(-delta[0], -delta[1])
245     self.assertFloatSeqEqual(rect, orig_rect, 1)
246    
247     def test_unprojected_rect_around_point(self):
248     rect = self.port.unprojected_rect_around_point(500, 500, 5)
249 bh 1462 self.assertFloatSeqEqual(rect,
250     (-19.063379161960469, 64.924498140752377,
251     -18.95455127948528, 65.033326023227573),
252     1e-1)
253 jonathan 1440
254     def test_find_shape_at(self):
255     eq = self.assertEquals
256     x, y = self.port.proj_to_win(-18, 64.81418571)
257 bh 1462 eq(self.port.find_shape_at(x, y, searched_layer=self.layer),
258     (None, None))
259 jonathan 1440
260     x, y = self.port.proj_to_win(-18.18776318, 64.81418571)
261 bh 1462 eq(self.port.find_shape_at(x, y, searched_layer=self.layer),
262     (self.layer, 610))
263 jonathan 1440
264     def testLabelShapeAt(self):
265     eq = self.assertEquals
266    
267     # select a road
268     x, y = self.port.proj_to_win(-18.18776318, 64.81418571)
269     eq(self.port.LabelShapeAt(x, y), False) # nothing to do
270     eq(self.port.LabelShapeAt(x, y, "Hello world"), True) # add
271     eq(self.port.LabelShapeAt(x, y), True) # remove
272    
273     # select a point
274     x, y = self.port.proj_to_win(-19.140, 63.4055717)
275     eq(self.port.LabelShapeAt(x, y), False) # nothing to do
276     eq(self.port.LabelShapeAt(x, y, "Hello world"), True) # add
277     eq(self.port.LabelShapeAt(x, y), True) # remove
278    
279     # select a polygon
280     x, y = self.port.proj_to_win(-16.75286628, 64.67807745)
281     eq(self.port.LabelShapeAt(x, y), False) # nothing to do
282     eq(self.port.LabelShapeAt(x, y, "Hello world"), True) # add
283     # for polygons the coordinates will be different, so
284     # these numbers were copied
285     x, y = self.port.proj_to_win(-18.5939850348, 64.990607973)
286     eq(self.port.LabelShapeAt(x, y), True) # remove
287    
288    
289     def test_set_pos(self):
290     eq = self.assertEquals
291     # set_current_position / CurrentPosition
292     event = Event()
293     event.m_x, event.m_y = 5, 5
294     self.port.set_current_position(event)
295     eq(self.port.current_position, (5, 5))
296     eq(self.port.CurrentPosition(), self.port.win_to_proj(5, 5))
297     self.port.set_current_position(None)
298     eq(self.port.current_position, None)
299     eq(self.port.CurrentPosition(), None)
300    
301     event.m_x, event.m_y = 15, 15
302     self.port.MouseMove(event)
303     eq(self.port.current_position, (15, 15))
304     event.m_x, event.m_y = 25, 15
305     self.port.MouseLeftDown(event)
306     eq(self.port.current_position, (25, 15))
307     event.m_x, event.m_y = 15, 25
308     self.port.MouseLeftUp(event)
309     eq(self.port.current_position, (15, 25))
310    
311     def testTools(self):
312     eq = self.assertEquals
313     event = Event()
314     def test_tools(tool, shortcut):
315     self.port.SelectTool(tool)
316     eq(self.port.CurrentTool(), tool.Name())
317     self.port.SelectTool(None)
318     eq(self.port.CurrentTool(), None)
319     shortcut()
320     eq(self.port.CurrentTool(), tool.Name())
321    
322     test_tools(ZoomInTool(self.port), self.port.ZoomInTool)
323    
324     point = self.port.win_to_proj(600, 600)
325    
326     # one click zoom
327     event.m_x, event.m_y = 600, 600
328     self.port.MouseMove(event)
329     self.port.MouseLeftDown(event)
330     self.port.MouseLeftUp(event)
331 bh 1462 self.assertFloatSeqEqual(point, self.port.win_to_proj(500, 500), 1e-3)
332     self.port.FitMapToWindow()
333 jonathan 1440
334     # zoom rectangle
335     rect = self.port.win_to_proj(29, 970) + self.port.win_to_proj(970, 29)
336     event.m_x, event.m_y = 29, 29
337     self.port.MouseMove(event)
338     self.port.MouseLeftDown(event)
339     event.m_x, event.m_y = 970, 970
340     self.port.MouseMove(event)
341     self.port.MouseLeftUp(event)
342 bh 1462 self.assertFloatSeqEqual(rect,
343     self.port.win_to_proj(0, 1000)
344     + self.port.win_to_proj(1000, 0), 1e-1)
345     self.port.FitMapToWindow()
346 jonathan 1440
347     test_tools(ZoomOutTool(self.port), self.port.ZoomOutTool)
348    
349     # one click zoom out
350 bh 1462 proj_rect = self.port.win_to_proj(-499, 1499) \
351     + self.port.win_to_proj(1499, -499)
352 jonathan 1440 event.m_x, event.m_y = 500, 500
353     self.port.MouseMove(event)
354     self.port.MouseLeftDown(event)
355     self.port.MouseLeftUp(event)
356 bh 1462 self.assertFloatSeqEqual(proj_rect,
357     self.port.win_to_proj(0, 1000)
358     + self.port.win_to_proj(1000, 0),1e-1)
359     self.port.FitMapToWindow()
360 jonathan 1440
361     # zoom out rectangle
362     rect = self.port.win_to_proj(0, 1000) + self.port.win_to_proj(1000, 0)
363     event.m_x, event.m_y = 29, 29
364     self.port.MouseMove(event)
365     self.port.MouseLeftDown(event)
366     event.m_x, event.m_y = 970, 970
367     self.port.MouseMove(event)
368     self.port.MouseLeftUp(event)
369 bh 1462 self.assertFloatSeqEqual(rect,
370     self.port.win_to_proj(29, 970)
371     + self.port.win_to_proj(970, 29))
372     self.port.FitMapToWindow()
373 jonathan 1440
374     test_tools(PanTool(self.port), self.port.PanTool)
375    
376 bh 1462 rect = self.port.win_to_proj(-25, 975) + self.port.win_to_proj(975,-25)
377 jonathan 1440 event.m_x, event.m_y = 50, 50
378     self.port.MouseMove(event)
379     self.port.MouseLeftDown(event)
380     event.m_x, event.m_y = 75, 75
381     self.port.MouseMove(event)
382     self.port.MouseLeftUp(event)
383 bh 1462 self.assertFloatSeqEqual(rect,
384     self.port.win_to_proj(0, 1000)
385     + self.port.win_to_proj(1000, 0))
386 jonathan 1440
387     test_tools(IdentifyTool(self.port), self.port.IdentifyTool)
388    
389     event.m_x, event.m_y = self.port.proj_to_win(-18.18776318, 64.81418571)
390     self.port.MouseMove(event)
391     self.port.MouseLeftDown(event)
392     self.port.MouseLeftUp(event)
393     eq(self.port.SelectedShapes(), [610])
394 bh 1462
395 jonathan 1440 test_tools(LabelTool(self.port), self.port.LabelTool)
396    
397     # since adding a label requires use interaction with a dialog
398     # we will insert a label and then only test whether clicking
399     # removes the label
400    
401     x, y = self.port.proj_to_win(-19.140, 63.4055717)
402     self.port.LabelShapeAt(x, y, "Hello world")
403     event.m_x, event.m_y = x, y
404     self.port.MouseMove(event)
405     self.port.MouseLeftDown(event)
406     self.port.MouseLeftUp(event)
407     eq(self.port.LabelShapeAt(x, y), False) # should have done nothing
408    
409 bh 1781 def test_forwarding_title_changed(self):
410     """Test whether ViewPort forwards the TITLE_CHANGED message of the map
411     """
412     self.map.SetTitle(self.map.Title() + " something to make it different")
413     self.check_messages([(self.map, TITLE_CHANGED)])
414 jonathan 1440
415 bh 1781
416 bh 1608 class TestViewportWithPostGIS(unittest.TestCase):
417    
418     def setUp(self):
419     """Start the server and create a database.
420    
421     The database name will be stored in self.dbname, the server
422     object in self.server and the db object in self.db.
423     """
424     postgissupport.skip_if_no_postgis()
425     self.server = postgissupport.get_test_server()
426     self.dbref = self.server.get_default_static_data_db()
427     self.dbname = self.dbref.dbname
428     self.session = Session("PostGIS Session")
429     self.db = PostGISConnection(dbname = self.dbname,
430 bh 1634 **self.server.connection_params("user"))
431 bh 1608
432     proj = Projection(["proj=latlong",
433     "to_meter=.017453292519943",
434     "ellps=clrk66"])
435     self.map = Map("title", proj)
436    
437     self.port = ViewPort((1001, 1001))
438    
439     def tearDown(self):
440     self.session.Destroy()
441 bh 1781 self.port.Destroy()
442 bh 1608 self.map.Destroy()
443     self.map = self.port = None
444    
445     def test_find_shape_at_point(self):
446     """Test ViewPort.find_shape_at() with postgis point layer"""
447     layer = Layer("Point",
448     self.session.OpenDBShapeStore(self.db, "landmarks"))
449     prop = layer.GetClassification().GetDefaultGroup().GetProperties()
450     prop.SetFill(Color(0,0,0))
451     self.map.AddLayer(layer)
452    
453     self.port.SetMap(self.map)
454    
455     x, y = self.port.proj_to_win(-22.54335021, 66.30889129)
456 bh 1662 self.assertEquals(self.port.find_shape_at(x, y), (layer, 1001))
457 bh 1608
458     def test_find_shape_at_arc(self):
459     """Test ViewPort.find_shape_at() with postgis arc layer"""
460     layer = Layer("Arc", self.session.OpenDBShapeStore(self.db, "roads"))
461     self.map.AddLayer(layer)
462    
463     self.port.SetMap(self.map)
464    
465     x, y = self.port.proj_to_win(-18.18776318, 64.81418571)
466     self.assertEquals(self.port.find_shape_at(x, y), (layer, 610))
467    
468     def test_find_shape_at_polygon(self):
469     """Test ViewPort.find_shape_at() with postgis polygon layer"""
470     layer = Layer("Poly",
471     self.session.OpenDBShapeStore(self.db, "political"))
472     prop = layer.GetClassification().GetDefaultGroup().GetProperties()
473     prop.SetFill(Color(0,0,0))
474     self.map.AddLayer(layer)
475    
476     self.port.SetMap(self.map)
477    
478     x, y = self.port.proj_to_win(-19.78369, 65.1649143)
479     self.assertEquals(self.port.find_shape_at(x, y), (layer, 144))
480    
481    
482 jonathan 1440 if __name__ == "__main__":
483     unittest.main()
484    

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26