/[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 1927 - (show annotations)
Mon Nov 10 16:57:35 2003 UTC (21 years, 4 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 12122 byte(s)
(raster_format_map): New. Mapping form the
strings of the format parameter of draw_raster_data method to wx
constants
(MapRenderer.draw_raster_data): Add the format parameter and use
raster_format_map to map it to the right wxwindows constant for
wxImageFromStream

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26