/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/renderer.py
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/Thuban/UI/renderer.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2431 - (show annotations)
Sun Dec 5 15:05:02 2004 UTC (20 years, 3 months ago) by joey
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 13611 byte(s)
Added PNG, TIFF and GIF as supported bitmap image formats (helpful
for the WMS extension)

1 # Copyright (c) 2001-2004 by Intevation GmbH
2 # Authors:
3 # Bernhard Herzog <[email protected]> (2001-2003)
4 # Jonathan Coles <[email protected]> (2003)
5 # Frank Koormann <[email protected]> (2003)
6 # Jan-Oliver Wagner <[email protected]> (2003, 2004)
7 #
8 # This program is free software under the GPL (>=v2)
9 # Read the file COPYING coming with Thuban for details.
10
11 from __future__ import generators
12
13 __version__ = "$Revision$"
14 # $Source$
15 # $Id$
16
17 import cStringIO
18
19 from Thuban import _
20
21 from wxPython.wx import wxPoint, wxRect, wxPen, wxBrush, wxFont, \
22 wxTRANSPARENT_PEN, wxTRANSPARENT_BRUSH, \
23 wxBLACK_PEN, wxBLACK, wxSOLID, wxCROSS_HATCH, wxSWISS, wxNORMAL, \
24 wxBitmapFromImage, wxImageFromStream, wxBITMAP_TYPE_BMP, \
25 wxBITMAP_TYPE_JPEG, wxBITMAP_TYPE_PNG, wxBITMAP_TYPE_TIF, wxBITMAP_TYPE_GIF
26
27 from wxproj import draw_polygon_shape, draw_polygon_init
28
29 from Thuban.UI.common import Color2wxColour
30 from Thuban.UI.classifier import ClassDataPreviewer
31 from Thuban.UI.scalebar import ScaleBar
32
33 from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \
34 SHAPETYPE_POINT, RAW_SHAPEFILE
35
36 from Thuban.Model.color import Transparent
37 import Thuban.Model.resource
38
39 from baserenderer import BaseRenderer
40
41
42 # Map the strings used for the format parameter of the draw_raster_data
43 # method to the appropriate wxWindows constants
44 raster_format_map = {
45 "BMP": wxBITMAP_TYPE_BMP,
46 "JPEG": wxBITMAP_TYPE_JPEG,
47 "PNG": wxBITMAP_TYPE_PNG,
48 "TIFF": wxBITMAP_TYPE_TIF,
49 "GIF": wxBITMAP_TYPE_GIF,
50 }
51
52 class MapRenderer(BaseRenderer):
53
54 """Class to render a map onto a wxDC"""
55
56 TRANSPARENT_PEN = wxTRANSPARENT_PEN
57 TRANSPARENT_BRUSH = wxTRANSPARENT_BRUSH
58
59 def make_point(self, x, y):
60 return wxPoint(int(round(x)), int(round(y)))
61
62 def tools_for_property(self, prop):
63 fill = prop.GetFill()
64 if fill is Transparent:
65 brush = self.TRANSPARENT_BRUSH
66 else:
67 brush = wxBrush(Color2wxColour(fill), wxSOLID)
68
69 stroke = prop.GetLineColor()
70 if stroke is Transparent:
71 pen = self.TRANSPARENT_PEN
72 else:
73 pen = wxPen(Color2wxColour(stroke), prop.GetLineWidth(), wxSOLID)
74 return pen, brush
75
76 def low_level_renderer(self, layer):
77 """Override inherited method to provide more efficient renderers
78
79 If the underlying data format is not a shapefile or the layer
80 contains points shapes, simply use what the inherited method
81 returns.
82
83 Otherwise, i.e. for arc and polygon use the more efficient
84 wxproj.draw_polygon_shape and its corresponding parameter
85 created with wxproj.draw_polygon_init.
86 """
87 if (layer.ShapeStore().RawShapeFormat() == RAW_SHAPEFILE
88 and layer.ShapeType() in (SHAPETYPE_ARC, SHAPETYPE_POLYGON)):
89 offx, offy = self.offset
90 return (True, draw_polygon_shape,
91 draw_polygon_init(layer.ShapeStore().Shapefile(),
92 self.dc, self.map.projection,
93 layer.projection,
94 self.scale, -self.scale, offx, offy))
95 else:
96 return BaseRenderer.low_level_renderer(self, layer)
97
98 def label_font(self):
99 return wxFont(int(round(self.resolution * 10)), wxSWISS, wxNORMAL,
100 wxNORMAL)
101
102 def draw_raster_data(self, data, format = 'BMP'):
103 stream = cStringIO.StringIO(data)
104 image = wxImageFromStream(stream, raster_format_map[format])
105 bitmap = wxBitmapFromImage(image)
106 self.dc.DrawBitmap(bitmap, 0, 0)
107
108
109 class ScreenRenderer(MapRenderer):
110
111 # On the screen we want to see only visible layers by default
112 honor_visibility = 1
113
114 def RenderMap(self, selected_layer, selected_shapes):
115 """Render the map.
116
117 Only the given region (a tuple in window coordinates as returned
118 by a wxrect's asTuple method) needs to be redrawn. Highlight the
119 shapes given by the ids in selected_shapes in the
120 selected_layer.
121 """
122 self.selected_layer = selected_layer
123 self.selected_shapes = selected_shapes
124 self.render_map()
125
126 def RenderMapIncrementally(self):
127 """Render the map.
128
129 Only the given region (a tuple in window coordinates as returned
130 by a wxrect's asTuple method) needs to be redrawn. Highlight the
131 shapes given by the ids in selected_shapes in the
132 selected_layer.
133 """
134 return self.render_map_incrementally()
135
136 def draw_selection_incrementally(self, layer, selected_shapes):
137 """Draw the selected shapes in a emphasized way (i.e.
138 with a special pen and brush.
139 The drawing is performed incrementally, that means every
140 n shapes, the user can have interactions with the map.
141 n is currently fixed to 500.
142
143 layer -- the layer where the shapes belong to.
144 selected_shapes -- a list of the shape-ids representing the
145 selected shapes for the given layer.
146 """
147 pen = wxPen(wxBLACK, 3, wxSOLID)
148 brush = wxBrush(wxBLACK, wxCROSS_HATCH)
149
150 shapetype = layer.ShapeType()
151 useraw, func, param = self.low_level_renderer(layer)
152 args = (pen, brush)
153
154 # for point shapes we need to find out the properties
155 # to determine the size. Based on table and field,
156 # we can find out the properties for object - see below.
157 if shapetype == SHAPETYPE_POINT:
158 lc = layer.GetClassification()
159 field = layer.GetClassificationColumn()
160 table = layer.ShapeStore().Table()
161
162 count = 0
163 for index in selected_shapes:
164 count += 1
165 shape = layer.Shape(index)
166
167 # Get the size of the specific property for this
168 # point
169 if shapetype == SHAPETYPE_POINT:
170 value = table.ReadValue(shape.ShapeID(), field)
171 group = lc.FindGroup(value)
172 size = group.GetProperties().GetSize()
173 args = (pen, brush, size)
174
175 if useraw:
176 data = shape.RawData()
177 else:
178 data = shape.Points()
179 func(param, data, *args)
180 if count % 500 == 0:
181 yield True
182
183 def layer_shapes(self, layer):
184 """Return the shapeids covered by the region that has to be redrawn
185
186 Call the layer's ShapesInRegion method to determine the ids so
187 that it can use the quadtree.
188 """
189 # FIXME: the quad-tree should be built from the projected
190 # coordinates not the lat-long ones because it's not trivial to
191 # determine an appropriate rectangle in lat-long for a given
192 # rectangle in projected coordinates which we have to start from
193 # here.
194 proj = self.map.projection
195 if proj is not None:
196 inverse = proj.Inverse
197 else:
198 inverse = None
199
200 scale = self.scale
201 offx, offy = self.offset
202 xs = []
203 ys = []
204 x, y, width, height = self.region
205 for winx, winy in ((x, y), (x + width, y),
206 (x + width, y + height), (x, y + height)):
207 px = (winx - offx) / scale
208 py = -(winy - offy) / scale
209 if inverse:
210 px, py = inverse(px, py)
211 xs.append(px)
212 ys.append(py)
213 left = min(xs)
214 right = max(xs)
215 top = max(ys)
216 bottom = min(ys)
217
218 return layer.ShapesInRegion((left, bottom, right, top))
219
220
221 class ExportRenderer(ScreenRenderer):
222
223 honor_visibility = 1
224
225 def __init__(self, *args, **kw):
226 """Initialize the ExportRenderer.
227
228 In addition to all parameters of the the ScreenRender
229 constructor, this class requires and additional keyword argument
230 destination_region with a tuple (minx, miny, maxx, maxy) giving
231 the region in dc coordinates which is to contain the map.
232 """
233 self.destination_region = kw["destination_region"]
234 del kw["destination_region"]
235 ScreenRenderer.__init__(self, *args, **kw)
236
237 def RenderMap(self, selected_layer, selected_shapes):
238 """Render the map.
239
240 The rendering device has been specified during initialisation.
241 The device border distance was set in
242 Thuban.UI.viewport.output_transform().
243
244 RenderMap renders a frame set (one page frame, one around
245 legend/scalebar and one around the map), the map, the legend and
246 the scalebar on the given DC. The map is rendered with the
247 region displayed in the canvas view, centered on the area
248 available for map display.
249 """
250
251 self.selected_layer = selected_layer
252 self.selected_shapes = selected_shapes
253
254 # Get some dimensions
255 llx, lly, urx, ury = self.region
256 mminx, mminy, mmaxx, mmaxy = self.destination_region
257
258 # Manipulate the offset to position the map
259 offx, offy = self.offset
260 # 1. Shift to corner of map drawing area
261 offx = offx + mminx
262 offy = offy + mminy
263
264 # 2. Center the map on the map drawing area:
265 # region identifies the region on the canvas view:
266 # center of map drawing area - half the size of region: rendering origin
267 self.shiftx = (mmaxx - mminx)*0.5 - (urx - llx)*0.5
268 self.shifty = (mmaxy - mminy)*0.5 - (ury - lly)*0.5
269
270 self.offset = (offx+self.shiftx, offy+self.shifty)
271
272 # Draw the map
273 self.dc.BeginDrawing()
274 self.dc.DestroyClippingRegion()
275 self.dc.SetClippingRegion(mminx+self.shiftx, mminy+self.shifty,
276 urx, ury)
277 self.render_map()
278 self.dc.EndDrawing()
279
280 # Draw the rest (frames, legend, scalebar)
281 self.dc.BeginDrawing()
282 self.dc.DestroyClippingRegion()
283
284 # Force the font for Legend drawing
285 font = wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)
286 self.dc.SetFont(font)
287
288 self.render_frame()
289 self.render_legend()
290 self.render_scalebar()
291 self.dc.EndDrawing()
292
293 def render_frame(self):
294 """Render the frames for map and legend/scalebar."""
295
296 dc = self.dc
297 dc.SetPen(wxBLACK_PEN)
298 dc.SetBrush(wxTRANSPARENT_BRUSH)
299
300 # Dimension stuff
301 width, height = dc.GetSizeTuple()
302 mminx, mminy, mmaxx, mmaxy = self.destination_region
303
304 # Page Frame
305 dc.DrawRectangle(15,15,width-30, (mmaxy-mminy)+10)
306
307 # Map Frame
308 llx, lly, urx, ury = self.region
309 dc.DrawRectangle(mminx + self.shiftx, mminy + self.shifty, urx, ury)
310
311 # Legend Frame
312 dc.DrawRectangle(mmaxx+10,mminy,(width-20) - (mmaxx+10), mmaxy-mminy)
313
314 dc.DestroyClippingRegion()
315 dc.SetClippingRegion(mmaxx+10,mminy,
316 (width-20) - (mmaxx+10), mmaxy-mminy)
317
318 def render_legend(self):
319 """Render the legend on the Map."""
320
321 previewer = ClassDataPreviewer()
322 dc = self.dc
323 dc.SetPen(wxBLACK_PEN)
324 dc.SetBrush(wxTRANSPARENT_BRUSH)
325
326 # Dimension stuff
327 width, height = dc.GetSizeTuple()
328 mminx, mminy, mmaxx, mmaxy = self.destination_region
329 textwidth, textheight = dc.GetTextExtent("0")
330 iconwidth = textheight
331 iconheight = textheight
332 stepy = textheight+3
333 dx = 10
334 posx = mmaxx + 10 + 5 # 10 pix distance mapframe/legend frame,
335 # 5 pix inside legend frame
336 posy = mminy + 5 # 5 pix inside legend frame
337
338 # Render the legend
339 dc.SetTextForeground(wxBLACK)
340 if self.map.HasLayers():
341 layers = self.map.Layers()[:]
342 layers.reverse()
343 for l in layers:
344 if l.Visible():
345 # Render title
346 dc.DrawText(l.Title(), posx, posy)
347 posy+=stepy
348 if l.HasClassification():
349 # Render classification
350 clazz = l.GetClassification()
351 shapeType = l.ShapeType()
352 for g in clazz:
353 if g.IsVisible():
354 previewer.Draw(dc,
355 wxRect(posx+dx, posy,
356 iconwidth, iconheight),
357 g.GetProperties(), shapeType)
358 dc.DrawText(g.GetDisplayText(),
359 posx+2*dx+iconwidth, posy)
360 posy+=stepy
361
362 def render_scalebar(self):
363 """Render the scalebar."""
364
365 scalebar = ScaleBar(self.map)
366
367 # Dimension stuff
368 width, height = self.dc.GetSizeTuple()
369 mminx, mminy, mmaxx, mmaxy = self.destination_region
370
371 # Render the scalebar
372 scalebar.DrawScaleBar(self.scale, self.dc,
373 (mmaxx+10+5, mmaxy-25),
374 ((width-15-5) - (mmaxx+10+5),20)
375 )
376 # 10 pix between map and legend frame, 5 pix inside legend frame
377 # 25 pix from the legend frame bottom line
378 # Width: 15 pix from DC border, 5 pix inside frame, 10, 5 as above
379 # Height: 20
380
381 class PrinterRenderer(ExportRenderer):
382
383 # Printing as well as Export / Screen display only the visible layer.
384 honor_visibility = 1
385

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26