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