/[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 1937 - (show annotations)
Tue Nov 11 18:16:42 2003 UTC (21 years, 3 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 12216 byte(s)
Avoid warnings when run under Python 2.3

(MapRenderer.make_point): Turn this into a
real method so that we can convert to int.
(MapRenderer.label_font): The font size mist be an int.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26