1
# Copyright (C) 2003 by Intevation GmbH
3
# Bernhard Herzog <bh@intevation.de>
5
# This program is free software under the GPL (>=v2)
6
# Read the file COPYING coming with the software for details.
8
"""Test Thuban.Model.baserenderer"""
10
__version__ = "$Revision: 1.7 $"
11
# $Source: /thubanrepository/thuban/test/test_baserenderer.py,v $
12
# $Id: test_baserenderer.py,v 1.7 2003/11/10 16:57:43 bh Exp $
18
from mockgeo import SimpleShapeStore
22
from Thuban.Model.color import Transparent, Color
23
from Thuban.Model.data import SHAPETYPE_ARC, SHAPETYPE_POLYGON, SHAPETYPE_POINT
24
from Thuban.Model.map import Map
25
from Thuban.Model.layer import BaseLayer, Layer, RasterLayer
26
from Thuban.Model.table import MemoryTable, \
27
FIELDTYPE_DOUBLE, FIELDTYPE_INT, FIELDTYPE_STRING
28
from Thuban.Model.classification import ClassGroupSingleton
29
import Thuban.Model.resource
32
from Thuban.UI.baserenderer import BaseRenderer, \
33
add_renderer_extension, init_renderer_extensions
38
def __init__(self, size = None):
42
def GetSizeTuple(self):
45
def __getattr__(self, attr):
47
self.calls.append((attr,) + args)
54
def __init__(self, x, y):
58
def __eq__(self, other):
59
return self.x == other.x and self.y == other.y
61
def __ne__(self, other):
62
return self.x != other.x and self.y != other.y
65
return "P(%r, %r)" % (self.x, self.y)
68
class SimpleRenderer(BaseRenderer):
70
TRANSPARENT_PEN = ("pen", Transparent)
71
TRANSPARENT_BRUSH = ("brush", Transparent)
73
def make_point(self, x, y):
76
def tools_for_property(self, prop):
78
brush = ("brush", fill)
80
stroke = prop.GetLineColor()
81
stroke_width = prop.GetLineWidth()
82
if stroke is Transparent:
83
pen = ("pen", Transparent)
85
pen = ("pen", stroke, stroke_width)
92
def draw_raster_data(self, data, format='BMP'):
93
self.raster_data = data
94
self.raster_format = format
99
"""Objects that look like projections but simply apply non-uniform scalings
102
def __init__(self, xscale, yscale):
103
self.xscale = float(xscale)
104
self.yscale = float(yscale)
106
def Forward(self, x, y):
107
return (x * self.xscale, y * self.yscale)
109
def Inverse(self, x, y):
110
return (x / self.xscale, y / self.yscale)
113
class TestBaseRenderer(unittest.TestCase):
116
"""Set self.to_destroy to an empty list
118
Test should put all objects whose Destroy should be called atunittest.main
119
the end into this list so that they're destroyed in tearDown
124
for obj in self.to_destroy:
127
def test_arc_no_projection(self):
128
"""Test BaseRenderer with arc layer and no projections"""
129
table = MemoryTable([("type", FIELDTYPE_STRING),
130
("value", FIELDTYPE_DOUBLE),
131
("code", FIELDTYPE_INT)],
132
[("UNKNOWN", 0.0, 0)])
133
shapes = [[[(0, 0), (10, 10)]]]
134
store = SimpleShapeStore(SHAPETYPE_ARC, shapes, table)
136
map = Map("TestBaseRenderer")
137
self.to_destroy.append(map)
138
layer = Layer("arc layer", store)
142
renderer = SimpleRenderer(dc, map, 2, (10, 10))
144
renderer.render_map()
146
self.assertEquals(dc.calls,
148
('SetBrush', ('brush', Transparent)),
149
('SetPen', ('pen', Color(0, 0, 0), 1)),
150
('DrawLines', [P(10, 10), P(30, -10)]),
151
('SetFont', "label font"),
154
def test_polygon_no_projection(self):
155
"""Test BaseRenderer with polygon layer and no projections"""
156
table = MemoryTable([("type", FIELDTYPE_STRING),
157
("value", FIELDTYPE_DOUBLE),
158
("code", FIELDTYPE_INT)],
159
[("UNKNOWN", 0.0, 0)])
160
shapes = [[[(0, 0), (10, 10), (10, 0), (0, 0)]]]
161
store = SimpleShapeStore(SHAPETYPE_POLYGON, shapes, table)
163
map = Map("TestBaseRenderer")
164
layer = Layer("polygon layer", store)
165
prop = layer.GetClassification().GetDefaultGroup().GetProperties()
166
prop.SetFill(Color(1, 1, 1))
169
self.to_destroy.append(map)
172
renderer = SimpleRenderer(dc, map, 2, (10, 10))
174
renderer.render_map()
176
self.assertEquals(dc.calls,
178
('SetBrush', ('brush', Color(1, 1, 1))),
179
('SetPen', ('pen', Transparent)),
180
('DrawPolygon', [P(10, 10), P(30, -10), P(30, 10),
182
('SetBrush', ('brush', Transparent)),
183
('SetPen', ('pen', Color(0, 0, 0), 1)),
184
('DrawLines', [P(10, 10), P(30, -10), P(30, 10),
186
('SetFont', "label font"),
189
def test_complex_polygon(self):
190
"""Test BaseRenderer with complex polygon and no projections"""
191
# A square inside a sqare. This has to be drawn with at least a
192
# draw polygon call and two draw lines calls.
193
shapes = [[[(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)],
194
[(2, 2), (8, 2), (8, 8), (2, 8), (2, 2)]]]
196
table = MemoryTable([("type", FIELDTYPE_STRING),
197
("value", FIELDTYPE_DOUBLE),
198
("code", FIELDTYPE_INT)],
199
[("UNKNOWN", 0.0, 0)])
200
store = SimpleShapeStore(SHAPETYPE_POLYGON, shapes, table)
202
map = Map("TestBaseRenderer")
203
layer = Layer("polygon layer", store)
204
prop = layer.GetClassification().GetDefaultGroup().GetProperties()
205
prop.SetFill(Color(1, 1, 1))
208
self.to_destroy.append(map)
211
renderer = SimpleRenderer(dc, map, 2, (10, 10))
213
renderer.render_map()
215
self.assertEquals(dc.calls,
217
('SetBrush', ('brush', Color(1, 1, 1))),
218
('SetPen', ('pen', Transparent)),
220
[P(10, 10), P(10, -10), P(30, -10), P(30, 10),
222
P(14, 6), P(26, 6), P(26, -6), P(14, -6),
225
('SetBrush', ('brush', Transparent)),
226
('SetPen', ('pen', Color(0, 0, 0), 1)),
227
('DrawLines', [P(10, 10), P(10, -10), P(30, -10),
228
P(30, 10), P(10, 10)]),
229
('DrawLines', [P(14, 6), P(26, 6), P(26, -6),
230
P(14, -6), P(14, 6)]),
231
('SetFont', "label font"),
234
def test_point_no_projection(self):
235
"""Test BaseRenderer with point layer and no projections"""
236
table = MemoryTable([("type", FIELDTYPE_STRING),
237
("value", FIELDTYPE_DOUBLE),
238
("code", FIELDTYPE_INT)],
239
[("UNKNOWN", 0.0, 0),
240
("UNKNOWN", 0.0, 1)])
241
shapes = [[[(0, 0)]], [[(10, 10)]]]
242
store = SimpleShapeStore(SHAPETYPE_POINT, shapes, table)
244
map = Map("TestBaseRenderer")
245
layer = Layer("point layer", store)
247
self.to_destroy.append(map)
250
renderer = SimpleRenderer(dc, map, 2, (10, 10))
252
renderer.render_map()
254
self.assertEquals(dc.calls,
256
('SetBrush', ('brush', Transparent)),
257
('SetPen', ('pen', Color(0, 0, 0), 1)),
258
('DrawEllipse', 5, 5, 10, 10),
259
('SetBrush', ('brush', Transparent)),
260
('SetPen', ('pen', Color(0, 0, 0), 1)),
261
('DrawEllipse', 25, -15, 10, 10),
262
('SetFont', "label font"),
265
def test_raster_no_projection(self):
266
"""Test BaseRenderer with raster layer and no projections
268
This test is very simple minded and perhaps can easily fail due
269
to round-off errors. It simply compares the complete BMP file
270
returned by gdalwarp.ProjectRasterFile to a BMP file data.
272
if not Thuban.Model.resource.has_gdal_support():
273
raise support.SkipTest("No gdal support")
275
map = Map("TestBaseRenderer")
277
layer = RasterLayer("raster layer",
278
os.path.join("..", "Data", "iceland",
281
self.to_destroy.append(map)
283
dc = MockDC(size = (20, 20))
284
renderer = SimpleRenderer(dc, map, 34, (800, 2250))
286
renderer.render_map()
288
# The following commented out code block can be used to generate
289
# the base64 coded reference image data
290
#hexed = binascii.b2a_base64(renderer.raster_data)
292
# print repr(hexed[:65])
295
# The reference data as a base64 coded BMP image
296
raw_data = binascii.a2b_base64(
297
'Qk3GBQAAAAAAADYEAAAoAAAAFAAAABQAAAABAAgAAAAAAJABAAAAAAAAAAAAAAABA'
298
'AAAAAAAApYOAALGAgAGfjoAHmZyACZ2egAujo4AArICAE66GgACngIA5mZSAJqONg'
299
'ACzgIAAoIyABZqZgAO4uYAAtICAAKqAgAScloAAtYCADKepgAS2t4AAooiAALaAgA'
300
'CtgIAHsbOAAp2TgACogIAFtbaACqOigAidnoAAuICADKaogACfjoAAr4CAAKSFgAm'
301
'fnoAAo4eABrS1gAibnoAHsbKAAp6SgACmg4AGs7SACLCxgAqioIAAoYqAAZ6RgACm'
302
'goAKrK6AALmAgAC3gIAApIaABZqagACngYAAo4iAAKmAgAivsYAJoJ6AALCAgACyg'
303
'IAAq4CAAKWEgAOclYALpqeAAK6AgACgjYAEm5eAAKKKgAGekIAHmp6ABpmcgAChi4'
304
'ALpaaACJyegAClhYAEnJeAAZ+QgAqhoIADnZSAB5mdgACiiYAJnp6ACqGegAqrrYA'
305
'GmpuAB5megACkh4ALqqyAA52VgAulpYAAoI6AAZ+PgASbmIALpKWAA7m5gAWbmYAG'
306
'mpyAC6SjgAqioYADnZOAA7q6gAianoALqauABpqagAqgnoAEnJWAAp6RgAWbmIACu'
307
'7uACqGfgAqiooAMqauAAby8gAmusIAMp6qAC6WngAyoqoABvb2AC6SkgAS3uIAJra'
308
'+AB7KzgAynqIALq62ADKirgAC+voAGsrSABLi4gAG8vYADubqAC6qtgAuprIABvb6'
309
'ACLCygAW2t4AKra+AAru8gAS4uYACuruAAry8gAG+voAAEBAAFhkZABAQEAABp6fA'
310
'EBACAAAgPwAAPu/AJE9CgBACAAALj1BAEAICAAGPAAAQAgAAAY8+gBACL8AJTxXAA'
311
'gIQAAAPEAAAAgIAAY8QABACAgAAGQAAABAAAAALpoAAEBAAAAALgAAAEAABkAGAEA'
312
'IQAD2AEAAvwAIAJAu2ABAQEAALmQ5AEBAQAAAnp8AAEAIAAD4+gAAv78An5rDAEBA'
313
'QAAuhAcAQEBAAAb8AABAvwAAAGQKAABAAABpLksAQEAIAC4ACwBAAAAAAPkGAAC/Q'
314
'AD2APoAvwC/AJ0umgBAQEAAAGRkAABAQAAGnp8AQEAIAPcA/AC/AL8A7D0GAEAIQA'
315
'D4hAAAv0AAAAD8QAAAvwgA92T6AL9AvwDsLlcAQEBAAC4AQABAAAgA+EAAAL8IAAA'
316
'8AAAACAAAAJ8uVgBAQEAAAGQ5AABAQAAAnpcAAEBAAPYAQAC/AAgAnQsGAEAAQAAA'
317
'hG0AAEBAAB38PQAIv0AA9mT6AL9AvwAJLmwAZUBAAB0AQAAIAAgAHUAAAAgIAAAAA'
318
'AAAAAAAAACzbAAAQEAA//k5AH+/QAAGb5cAQEBAAACy5AAAQAgAAIpAAABACAAAAA'
319
'AAAAAAAAkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQk'
320
'JCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJ'
321
'CQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJC'
322
'QkJCQkJCQkJCQkJCQkJCQkJCQkyEi8aQCEJCQkJCQkJCQkJCQkJCTI7OwgILzsyCg'
323
'kJCQkJCQkJCQkJCzcJFggvADwGEDc3EhYAMgkJCQkJEjcVJDohGj0LGgYAPT0hCT0'
324
'LDyI3CQoBLwAaFgkyEC9AJAE8OgsIMjoABi8kCx4JCQkJCQkeGko8KTcLCxIyNwkJ'
325
'CQkWEjwWNUAQPCEAMwgJCQkJCQkSQBcvEkAPAQkyN0AMCQkJCQhBFyEvNy89JCIkM'
326
'yItGQwJCQo9RxozIgkyCQoPFxAtDBkgIgkJCQkJCQkJMRoQECJQNi9EIAAgCQkJCQ'
327
'kSUA88UAYeBjELICA8HiI=\n')
328
self.assertEquals(renderer.raster_data, raw_data)
329
self.assertEquals(renderer.raster_format, "BMP")
331
self.assertEquals(dc.calls,
333
('SetFont', "label font"),
336
def test_point_map_projection(self):
337
"""Test BaseRenderer with point layer and map projection"""
338
table = MemoryTable([("type", FIELDTYPE_STRING),
339
("value", FIELDTYPE_DOUBLE),
340
("code", FIELDTYPE_INT)],
341
[("UNKNOWN", 0.0, 0)])
342
shapes = [[[(10, 10)]]]
343
store = SimpleShapeStore(SHAPETYPE_POINT, shapes, table)
345
map = Map("TestBaseRenderer")
346
map.SetProjection(MockProjection(-3, 3))
347
layer = Layer("point layer", store)
349
self.to_destroy.append(map)
352
renderer = SimpleRenderer(dc, map, 2, (10, 10))
354
renderer.render_map()
356
self.assertEquals(dc.calls,
358
('SetBrush', ('brush', Transparent)),
359
('SetPen', ('pen', Color(0, 0, 0), 1)),
360
('DrawEllipse', -55, -55, 10, 10),
361
('SetFont', "label font"),
364
def test_point_layer_projection(self):
365
"""Test BaseRenderer with point layer and layer projection"""
366
table = MemoryTable([("type", FIELDTYPE_STRING),
367
("value", FIELDTYPE_DOUBLE),
368
("code", FIELDTYPE_INT)],
369
[("UNKNOWN", 0.0, 0)])
370
shapes = [[[(9, 9)]]]
371
store = SimpleShapeStore(SHAPETYPE_POINT, shapes, table)
373
map = Map("TestBaseRenderer")
374
layer = Layer("point layer", store)
375
layer.SetProjection(MockProjection(3, -3))
377
self.to_destroy.append(map)
380
renderer = SimpleRenderer(dc, map, 2, (10, 10))
382
renderer.render_map()
384
self.assertEquals(dc.calls,
386
('SetBrush', ('brush', Transparent)),
387
('SetPen', ('pen', Color(0, 0, 0), 1)),
388
('DrawEllipse', 11, 11, 10, 10),
389
('SetFont', "label font"),
392
def test_point_layer_and_map_projection(self):
393
"""Test BaseRenderer with point layer and layer and map projection"""
394
table = MemoryTable([("type", FIELDTYPE_STRING),
395
("value", FIELDTYPE_DOUBLE),
396
("code", FIELDTYPE_INT)],
397
[("UNKNOWN", 0.0, 0)])
398
shapes = [[[(9, 9)]]]
399
store = SimpleShapeStore(SHAPETYPE_POINT, shapes, table)
401
map = Map("TestBaseRenderer")
402
map.SetProjection(MockProjection(-3, 3))
403
layer = Layer("point layer", store)
404
layer.SetProjection(MockProjection(3, -3))
406
self.to_destroy.append(map)
409
renderer = SimpleRenderer(dc, map, 2, (10, 10))
411
renderer.render_map()
413
self.assertEquals(dc.calls,
415
('SetBrush', ('brush', Transparent)),
416
('SetPen', ('pen', Color(0, 0, 0), 1)),
417
('DrawEllipse', -13, 23, 10, 10),
418
('SetFont', "label font"),
422
def test_point_with_classification(self):
423
"""Test BaseRenderer with point layer and classification"""
424
table = MemoryTable([("type", FIELDTYPE_STRING),
425
("value", FIELDTYPE_DOUBLE),
426
("code", FIELDTYPE_INT)],
427
[("UNKNOWN", 0.0, 0),
428
("UNKNOWN", 0.0, 1)])
429
shapes = [[[(0, 0)]], [[(10, 10)]]]
430
store = SimpleShapeStore(SHAPETYPE_POINT, shapes, table)
432
map = Map("TestBaseRenderer")
433
layer = Layer("point layer", store)
434
group = ClassGroupSingleton(1)
435
group.GetProperties().SetFill(Color(0, 0, 1))
436
layer.GetClassification().AppendGroup(group)
437
layer.SetClassificationColumn("code")
440
self.to_destroy.append(map)
443
renderer = SimpleRenderer(dc, map, 2, (10, 10))
445
renderer.render_map()
447
self.assertEquals(dc.calls,
449
('SetBrush', ('brush', Transparent)),
450
('SetPen', ('pen', Color(0, 0, 0), 1)),
451
('DrawEllipse', 5, 5, 10, 10),
452
('SetBrush', ('brush', Color(0, 0, 1))),
453
('SetPen', ('pen', Color(0, 0, 0), 1)),
454
('DrawEllipse', 25, -15, 10, 10),
455
('SetFont', "label font"),
459
def test_renderer_extension(self):
460
"""Test renderer with a renderer extension"""
461
class MyLayer(BaseLayer):
465
def my_renderer(renderer, layer):
466
calls.append((renderer, layer))
469
add_renderer_extension(MyLayer, my_renderer)
472
map = Map("test_renderer_extension")
473
layer = MyLayer("my layer")
475
self.to_destroy.append(map)
478
renderer = SimpleRenderer(dc, map, 2, (10, 10))
479
renderer.render_map()
481
init_renderer_extensions()
483
self.assertEquals(calls, [(renderer, layer)])
486
if __name__ == "__main__":