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

Contents of /branches/WIP-pyshapelib-bramz/test/test_baserenderer.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1552 - (show annotations)
Wed Aug 6 17:21:32 2003 UTC (21 years, 7 months ago) by bh
Original Path: trunk/thuban/test/test_baserenderer.py
File MIME type: text/x-python
File size: 16450 byte(s)
* Thuban/UI/renderer.py (MapRenderer): Most of the code/methods in
this class is now in BaseRenderer. This class is now practically
only a specialization of BaseRenderer for rendering to an actual
wx DC.
(ScreenRenderer.draw_shape_layer): Use self.low_level_renderer()
to get the shapetype specific rendering functions.

* test/test_baserenderer.py: New. Test cases for BaseRenderer

* Thuban/UI/view.py (MapCanvas.__init__): New instance variable
error_on_redraw to guard agains endless loops and stack overflows
when there's a bug in the rendering code that raises exceptions.
(MapCanvas.OnIdle, MapCanvas._do_redraw): Split the actual
rendering into a separate method _do_redraw so that error handling
is a bit easier. When an exception occurs, set error_on_redraw to
true. When it's true on entry to OnIdle do nothing and return
immediately.

1 # Copyright (C) 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 the software for details.
7
8 """Test Thuban.Model.baserenderer"""
9
10 __version__ = "$Revision$"
11 # $Source$
12 # $Id$
13
14 import os
15 import binascii
16 import unittest
17
18 import support
19 support.initthuban()
20
21 from Thuban.Model.color import Transparent, Color
22 from Thuban.Model.data import Shape, SHAPETYPE_ARC, SHAPETYPE_POLYGON, \
23 SHAPETYPE_POINT
24 from Thuban.Model.map import Map
25 from Thuban.Model.layer import Layer, RasterLayer
26 from Thuban.Model.table import MemoryTable, \
27 FIELDTYPE_DOUBLE, FIELDTYPE_INT, FIELDTYPE_STRING
28
29 from Thuban.UI.baserenderer import BaseRenderer
30
31
32 class MockDC:
33
34 def __init__(self, size = None):
35 self.calls = []
36 self.size = size
37
38 def GetSizeTuple(self):
39 return self.size
40
41 def __getattr__(self, attr):
42 def method(*args):
43 self.calls.append((attr,) + args)
44 return method
45
46 class P:
47
48 """A simple point"""
49
50 def __init__(self, x, y):
51 self.x = x
52 self.y = y
53
54 def __eq__(self, other):
55 return self.x == other.x and self.y == other.y
56
57 def __ne__(self, other):
58 return self.x != other.x and self.y != other.y
59
60 def __repr__(self):
61 return "P(%r, %r)" % (self.x, self.y)
62
63
64 class SimpleRenderer(BaseRenderer):
65
66 TRANSPARENT_PEN = ("pen", Transparent)
67 TRANSPARENT_BRUSH = ("brush", Transparent)
68
69 def make_point(self, x, y):
70 return P(x, y)
71
72 def tools_for_property(self, prop):
73 fill = prop.GetFill()
74 brush = ("brush", fill)
75
76 stroke = prop.GetLineColor()
77 stroke_width = prop.GetLineWidth()
78 if stroke is Transparent:
79 pen = ("pen", Transparent)
80 else:
81 pen = ("pen", stroke, stroke_width)
82
83 return pen, brush
84
85 def label_font(self):
86 return "label font"
87
88 def draw_raster_data(self, data):
89 self.raster_data = data
90
91 class SimpleShapeStore:
92
93 def __init__(self, shapetype, shapes, table):
94 self.shapetype = shapetype
95 self.shapes = shapes
96 self.table = table
97 assert table.NumRows() == len(shapes)
98
99 def ShapeType(self):
100 return self.shapetype
101
102 def Table(self):
103 return self.table
104
105 def NumShapes(self):
106 return len(self.shapes)
107
108 def Shape(self, index):
109 return Shape(self.shapes[index])
110
111
112 class MockProjection:
113
114 """Objects that look like projections but simply apply non-uniform scalings
115 """
116
117 def __init__(self, xscale, yscale):
118 self.xscale = float(xscale)
119 self.yscale = float(yscale)
120
121 def Forward(self, x, y):
122 return (x * self.xscale, y * self.yscale)
123
124 def Inverse(self, x, y):
125 return (x / self.xscale, y / self.yscale)
126
127
128 class TestBaseRenderer(unittest.TestCase):
129
130 def setUp(self):
131 """Set self.to_destroy to an empty list
132
133 Test should put all objects whose Destroy should be called atunittest.main
134 the end into this list so that they're destroyed in tearDown
135 """
136 self.to_destroy = []
137
138 def tearDown(self):
139 for obj in self.to_destroy:
140 obj.Destroy()
141
142 def test_arc_no_projection(self):
143 """Test BaseRenderer with arc layer and no projections"""
144 table = MemoryTable([("type", FIELDTYPE_STRING),
145 ("value", FIELDTYPE_DOUBLE),
146 ("code", FIELDTYPE_INT)],
147 [("UNKNOWN", 0.0, 0)])
148 shapes = [[[(0, 0), (10, 10)]]]
149 store = SimpleShapeStore(SHAPETYPE_ARC, shapes, table)
150
151 map = Map("TestBaseRenderer")
152 self.to_destroy.append(map)
153 layer = Layer("arc layer", store)
154 map.AddLayer(layer)
155
156 dc = MockDC()
157 renderer = SimpleRenderer(dc, 2, (10, 10))
158
159 renderer.render_map(map)
160
161 self.assertEquals(dc.calls,
162 [('BeginDrawing',),
163 ('SetBrush', ('brush', Transparent)),
164 ('SetPen', ('pen', Color(0, 0, 0), 1)),
165 ('DrawLines', [P(10, 10), P(30, -10)]),
166 ('SetFont', "label font"),
167 ('EndDrawing',)])
168
169 def test_polygon_no_projection(self):
170 """Test BaseRenderer with polygon layer and no projections"""
171 table = MemoryTable([("type", FIELDTYPE_STRING),
172 ("value", FIELDTYPE_DOUBLE),
173 ("code", FIELDTYPE_INT)],
174 [("UNKNOWN", 0.0, 0)])
175 shapes = [[[(0, 0), (10, 10), (10, 0), (0, 0)]]]
176 store = SimpleShapeStore(SHAPETYPE_POLYGON, shapes, table)
177
178 map = Map("TestBaseRenderer")
179 layer = Layer("polygon layer", store)
180 prop = layer.GetClassification().GetDefaultGroup().GetProperties()
181 prop.SetFill(Color(1, 1, 1))
182
183 map.AddLayer(layer)
184 self.to_destroy.append(map)
185
186 dc = MockDC()
187 renderer = SimpleRenderer(dc, 2, (10, 10))
188
189 renderer.render_map(map)
190
191 self.assertEquals(dc.calls,
192 [('BeginDrawing',),
193 ('SetBrush', ('brush', Color(1, 1, 1))),
194 ('SetPen', ('pen', Transparent)),
195 ('DrawPolygon', [P(10, 10), P(30, -10), P(30, 10),
196 P(10, 10)]),
197 ('SetBrush', ('brush', Transparent)),
198 ('SetPen', ('pen', Color(0, 0, 0), 1)),
199 ('DrawLines', [P(10, 10), P(30, -10), P(30, 10),
200 P(10, 10)]),
201 ('SetFont', "label font"),
202 ('EndDrawing',)])
203
204 def test_complex_polygon(self):
205 """Test BaseRenderer with complex polygon and no projections"""
206 # A square inside a sqare. This has to be drawn with at least a
207 # draw polygon call and two draw lines calls.
208 shapes = [[[(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)],
209 [(2, 2), (8, 2), (8, 8), (2, 8), (2, 2)]]]
210
211 table = MemoryTable([("type", FIELDTYPE_STRING),
212 ("value", FIELDTYPE_DOUBLE),
213 ("code", FIELDTYPE_INT)],
214 [("UNKNOWN", 0.0, 0)])
215 store = SimpleShapeStore(SHAPETYPE_POLYGON, shapes, table)
216
217 map = Map("TestBaseRenderer")
218 layer = Layer("polygon layer", store)
219 prop = layer.GetClassification().GetDefaultGroup().GetProperties()
220 prop.SetFill(Color(1, 1, 1))
221
222 map.AddLayer(layer)
223 self.to_destroy.append(map)
224
225 dc = MockDC()
226 renderer = SimpleRenderer(dc, 2, (10, 10))
227
228 renderer.render_map(map)
229
230 self.assertEquals(dc.calls,
231 [('BeginDrawing',),
232 ('SetBrush', ('brush', Color(1, 1, 1))),
233 ('SetPen', ('pen', Transparent)),
234 ('DrawPolygon',
235 [P(10, 10), P(10, -10), P(30, -10), P(30, 10),
236 P(10, 10),
237 P(14, 6), P(26, 6), P(26, -6), P(14, -6),
238 P(14, 6),
239 P(10, 10)]),
240 ('SetBrush', ('brush', Transparent)),
241 ('SetPen', ('pen', Color(0, 0, 0), 1)),
242 ('DrawLines', [P(10, 10), P(10, -10), P(30, -10),
243 P(30, 10), P(10, 10)]),
244 ('DrawLines', [P(14, 6), P(26, 6), P(26, -6),
245 P(14, -6), P(14, 6)]),
246 ('SetFont', "label font"),
247 ('EndDrawing',)])
248
249 def test_point_no_projection(self):
250 """Test BaseRenderer with point layer and no projections"""
251 table = MemoryTable([("type", FIELDTYPE_STRING),
252 ("value", FIELDTYPE_DOUBLE),
253 ("code", FIELDTYPE_INT)],
254 [("UNKNOWN", 0.0, 0),
255 ("UNKNOWN", 0.0, 1)])
256 shapes = [[[(0, 0)]], [[(10, 10)]]]
257 store = SimpleShapeStore(SHAPETYPE_POINT, shapes, table)
258
259 map = Map("TestBaseRenderer")
260 layer = Layer("point layer", store)
261 map.AddLayer(layer)
262 self.to_destroy.append(map)
263
264 dc = MockDC()
265 renderer = SimpleRenderer(dc, 2, (10, 10))
266
267 renderer.render_map(map)
268
269 self.assertEquals(dc.calls,
270 [('BeginDrawing',),
271 ('SetBrush', ('brush', Transparent)),
272 ('SetPen', ('pen', Color(0, 0, 0), 1)),
273 ('DrawEllipse', 5, 5, 10, 10),
274 ('SetBrush', ('brush', Transparent)),
275 ('SetPen', ('pen', Color(0, 0, 0), 1)),
276 ('DrawEllipse', 25, -15, 10, 10),
277 ('SetFont', "label font"),
278 ('EndDrawing',)])
279
280 def test_raster_no_projection(self):
281 """Test BaseRenderer with raster layer and no projections
282
283 This test is very simple minded and perhaps can easily fail due
284 to round-off errors. It simply compares the complete BMP file
285 returned by gdalwarp.ProjectRasterFile to a BMP file data.
286 """
287 map = Map("TestBaseRenderer")
288
289 layer = RasterLayer("raster layer",
290 os.path.join("..", "Data", "iceland",
291 "island.tif"))
292 map.AddLayer(layer)
293 self.to_destroy.append(map)
294
295 dc = MockDC(size = (20, 20))
296 renderer = SimpleRenderer(dc, 34, (800, 2250))
297
298 renderer.render_map(map)
299
300 # The following commented out code block can be used to generate
301 # the base64 coded reference image data
302 #hexed = binascii.b2a_base64(renderer.raster_data)
303 #while hexed:
304 # print repr(hexed[:65])
305 # hexed = hexed[65:]
306
307 # The reference data as a base64 coded BMP image
308 raw_data = binascii.a2b_base64(
309 'Qk3GBQAAAAAAADYEAAAoAAAAFAAAABQAAAABAAgAAAAAAJABAAAAAAAAAAAAAAABA'
310 'AAAAAAAApYOAALGAgAGfjoAHmZyACZ2egAujo4AArICAE66GgACngIA5mZSAJqONg'
311 'ACzgIAAoIyABZqZgAO4uYAAtICAAKqAgAScloAAtYCADKepgAS2t4AAooiAALaAgA'
312 'CtgIAHsbOAAp2TgACogIAFtbaACqOigAidnoAAuICADKaogACfjoAAr4CAAKSFgAm'
313 'fnoAAo4eABrS1gAibnoAHsbKAAp6SgACmg4AGs7SACLCxgAqioIAAoYqAAZ6RgACm'
314 'goAKrK6AALmAgAC3gIAApIaABZqagACngYAAo4iAAKmAgAivsYAJoJ6AALCAgACyg'
315 'IAAq4CAAKWEgAOclYALpqeAAK6AgACgjYAEm5eAAKKKgAGekIAHmp6ABpmcgAChi4'
316 'ALpaaACJyegAClhYAEnJeAAZ+QgAqhoIADnZSAB5mdgACiiYAJnp6ACqGegAqrrYA'
317 'GmpuAB5megACkh4ALqqyAA52VgAulpYAAoI6AAZ+PgASbmIALpKWAA7m5gAWbmYAG'
318 'mpyAC6SjgAqioYADnZOAA7q6gAianoALqauABpqagAqgnoAEnJWAAp6RgAWbmIACu'
319 '7uACqGfgAqiooAMqauAAby8gAmusIAMp6qAC6WngAyoqoABvb2AC6SkgAS3uIAJra'
320 '+AB7KzgAynqIALq62ADKirgAC+voAGsrSABLi4gAG8vYADubqAC6qtgAuprIABvb6'
321 'ACLCygAW2t4AKra+AAru8gAS4uYACuruAAry8gAG+voAAEBAAFhkZABAQEAABp6fA'
322 'EBACAAAgPwAAPu/AJE9CgBACAAALj1BAEAICAAGPAAAQAgAAAY8+gBACL8AJTxXAA'
323 'gIQAAAPEAAAAgIAAY8QABACAgAAGQAAABAAAAALpoAAEBAAAAALgAAAEAABkAGAEA'
324 'IQAD2AEAAvwAIAJAu2ABAQEAALmQ5AEBAQAAAnp8AAEAIAAD4+gAAv78An5rDAEBA'
325 'QAAuhAcAQEBAAAb8AABAvwAAAGQKAABAAABpLksAQEAIAC4ACwBAAAAAAPkGAAC/Q'
326 'AD2APoAvwC/AJ0umgBAQEAAAGRkAABAQAAGnp8AQEAIAPcA/AC/AL8A7D0GAEAIQA'
327 'D4hAAAv0AAAAD8QAAAvwgA92T6AL9AvwDsLlcAQEBAAC4AQABAAAgA+EAAAL8IAAA'
328 '8AAAACAAAAJ8uVgBAQEAAAGQ5AABAQAAAnpcAAEBAAPYAQAC/AAgAnQsGAEAAQAAA'
329 'hG0AAEBAAB38PQAIv0AA9mT6AL9AvwAJLmwAZUBAAB0AQAAIAAgAHUAAAAgIAAAAA'
330 'AAAAAAAAACzbAAAQEAA//k5AH+/QAAGb5cAQEBAAACy5AAAQAgAAIpAAABACAAAAA'
331 'AAAAAAAAkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQk'
332 'JCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJ'
333 'CQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJC'
334 'QkJCQkJCQkJCQkJCQkJCQkJCQkyEi8aQCEJCQkJCQkJCQkJCQkJCTI7OwgILzsyCg'
335 'kJCQkJCQkJCQkJCzcJFggvADwGEDc3EhYAMgkJCQkJEjcVJDohGj0LGgYAPT0hCT0'
336 'LDyI3CQoBLwAaFgkyEC9AJAE8OgsIMjoABi8kCx4JCQkJCQkeGko8KTcLCxIyNwkJ'
337 'CQkWEjwWNUAQPCEAMwgJCQkJCQkSQBcvEkAPAQkyN0AMCQkJCQhBFyEvNy89JCIkM'
338 'yItGQwJCQo9RxozIgkyCQoPFxAtDBkgIgkJCQkJCQkJMRoQECJQNi9EIAAgCQkJCQ'
339 'kSUA88UAYeBjELICA8HiI=\n')
340 self.assertEquals(renderer.raster_data, raw_data)
341
342 self.assertEquals(dc.calls,
343 [('BeginDrawing',),
344 ('SetFont', "label font"),
345 ('EndDrawing',)])
346
347 def test_point_map_projection(self):
348 """Test BaseRenderer with point layer and map projection"""
349 table = MemoryTable([("type", FIELDTYPE_STRING),
350 ("value", FIELDTYPE_DOUBLE),
351 ("code", FIELDTYPE_INT)],
352 [("UNKNOWN", 0.0, 0)])
353 shapes = [[[(10, 10)]]]
354 store = SimpleShapeStore(SHAPETYPE_POINT, shapes, table)
355
356 map = Map("TestBaseRenderer")
357 map.SetProjection(MockProjection(-3, 3))
358 layer = Layer("point layer", store)
359 map.AddLayer(layer)
360 self.to_destroy.append(map)
361
362 dc = MockDC()
363 renderer = SimpleRenderer(dc, 2, (10, 10))
364
365 renderer.render_map(map)
366
367 self.assertEquals(dc.calls,
368 [('BeginDrawing',),
369 ('SetBrush', ('brush', Transparent)),
370 ('SetPen', ('pen', Color(0, 0, 0), 1)),
371 ('DrawEllipse', -55, -55, 10, 10),
372 ('SetFont', "label font"),
373 ('EndDrawing',)])
374
375 def test_point_layer_projection(self):
376 """Test BaseRenderer with point layer and layer projection"""
377 table = MemoryTable([("type", FIELDTYPE_STRING),
378 ("value", FIELDTYPE_DOUBLE),
379 ("code", FIELDTYPE_INT)],
380 [("UNKNOWN", 0.0, 0)])
381 shapes = [[[(9, 9)]]]
382 store = SimpleShapeStore(SHAPETYPE_POINT, shapes, table)
383
384 map = Map("TestBaseRenderer")
385 layer = Layer("point layer", store)
386 layer.SetProjection(MockProjection(3, -3))
387 map.AddLayer(layer)
388 self.to_destroy.append(map)
389
390 dc = MockDC()
391 renderer = SimpleRenderer(dc, 2, (10, 10))
392
393 renderer.render_map(map)
394
395 self.assertEquals(dc.calls,
396 [('BeginDrawing',),
397 ('SetBrush', ('brush', Transparent)),
398 ('SetPen', ('pen', Color(0, 0, 0), 1)),
399 ('DrawEllipse', 11, 11, 10, 10),
400 ('SetFont', "label font"),
401 ('EndDrawing',)])
402
403 def test_point_layer_and_map_projection(self):
404 """Test BaseRenderer with point layer and layer and map projection"""
405 table = MemoryTable([("type", FIELDTYPE_STRING),
406 ("value", FIELDTYPE_DOUBLE),
407 ("code", FIELDTYPE_INT)],
408 [("UNKNOWN", 0.0, 0)])
409 shapes = [[[(9, 9)]]]
410 store = SimpleShapeStore(SHAPETYPE_POINT, shapes, table)
411
412 map = Map("TestBaseRenderer")
413 map.SetProjection(MockProjection(-3, 3))
414 layer = Layer("point layer", store)
415 layer.SetProjection(MockProjection(3, -3))
416 map.AddLayer(layer)
417 self.to_destroy.append(map)
418
419 dc = MockDC()
420 renderer = SimpleRenderer(dc, 2, (10, 10))
421
422 renderer.render_map(map)
423
424 self.assertEquals(dc.calls,
425 [('BeginDrawing',),
426 ('SetBrush', ('brush', Transparent)),
427 ('SetPen', ('pen', Color(0, 0, 0), 1)),
428 ('DrawEllipse', -13, 23, 10, 10),
429 ('SetFont', "label font"),
430 ('EndDrawing',)])
431
432
433
434 if __name__ == "__main__":
435 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