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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26