/[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 1937 - (hide 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 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 bh 1866 from __future__ import generators
11    
12 bh 6 __version__ = "$Revision$"
13 bh 1866 # $Source$
14     # $Id$
15 bh 6
16 jonathan 938 import cStringIO
17    
18 jonathan 882 from Thuban import _
19    
20 bh 1552 from wxPython.wx import wxPoint, wxRect, wxPen, wxBrush, wxFont, \
21 frank 909 wxTRANSPARENT_PEN, wxTRANSPARENT_BRUSH, \
22 bh 1552 wxBLACK_PEN, wxBLACK, wxSOLID, wxCROSS_HATCH, wxSWISS, wxNORMAL, \
23 bh 1927 wxBitmapFromImage, wxImageFromStream, wxBITMAP_TYPE_BMP, wxBITMAP_TYPE_JPEG
24 bh 6
25 jonathan 676 from wxproj import draw_polygon_shape, draw_polygon_init
26 bh 6
27 jonathan 882 from Thuban.UI.common import Color2wxColour
28 frank 909 from Thuban.UI.classifier import ClassDataPreviewer
29     from Thuban.UI.scalebar import ScaleBar
30 jan 374
31 bh 1562 from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \
32     SHAPETYPE_POINT, RAW_SHAPEFILE
33 bh 6
34 jonathan 1343 from Thuban.Model.color import Transparent
35 jonathan 1165 import Thuban.Model.resource
36 bh 6
37 bh 1552 from baserenderer import BaseRenderer
38 jonathan 1234
39 bh 1927
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 bh 1552 class MapRenderer(BaseRenderer):
48 bh 6
49     """Class to render a map onto a wxDC"""
50    
51 bh 1552 TRANSPARENT_PEN = wxTRANSPARENT_PEN
52     TRANSPARENT_BRUSH = wxTRANSPARENT_BRUSH
53 bh 6
54 bh 1937 def make_point(self, x, y):
55     return wxPoint(int(round(x)), int(round(y)))
56 bh 6
57 bh 1552 def tools_for_property(self, prop):
58     fill = prop.GetFill()
59     if fill is Transparent:
60     brush = self.TRANSPARENT_BRUSH
61 jonathan 798 else:
62 bh 1552 brush = wxBrush(Color2wxColour(fill), wxSOLID)
63 bh 1219
64 bh 1552 stroke = prop.GetLineColor()
65     if stroke is Transparent:
66     pen = self.TRANSPARENT_PEN
67 jonathan 938 else:
68 bh 1552 pen = wxPen(Color2wxColour(stroke), prop.GetLineWidth(), wxSOLID)
69     return pen, brush
70 jonathan 938
71 bh 1552 def low_level_renderer(self, layer):
72     """Override inherited method to provide more efficient renderers
73 bh 686
74 bh 1562 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 bh 144 """
82 bh 1562 if (layer.ShapeStore().RawShapeFormat() == RAW_SHAPEFILE
83     and layer.ShapeType() in (SHAPETYPE_ARC, SHAPETYPE_POLYGON)):
84 bh 1552 offx, offy = self.offset
85 bh 1591 return (True, draw_polygon_shape,
86 bh 1562 draw_polygon_init(layer.ShapeStore().Shapefile(),
87     self.dc, self.map.projection,
88 bh 1552 layer.projection,
89 bh 1562 self.scale, -self.scale, offx, offy))
90     else:
91     return BaseRenderer.low_level_renderer(self, layer)
92 bh 6
93 bh 1552 def label_font(self):
94 bh 1937 return wxFont(int(round(self.resolution * 10)), wxSWISS, wxNORMAL,
95     wxNORMAL)
96 bh 6
97 bh 1927 def draw_raster_data(self, data, format = 'BMP'):
98 bh 1552 stream = cStringIO.StringIO(data)
99 bh 1927 image = wxImageFromStream(stream, raster_format_map[format])
100 bh 1552 bitmap = wxBitmapFromImage(image)
101     self.dc.DrawBitmap(bitmap, 0, 0)
102 jonathan 588
103    
104 bh 6 class ScreenRenderer(MapRenderer):
105    
106     # On the screen we want to see only visible layers by default
107     honor_visibility = 1
108 bh 1552
109 bh 1866 def RenderMap(self, selected_layer, selected_shapes):
110 bh 144 """Render the map.
111    
112 bh 148 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 bh 535 shapes given by the ids in selected_shapes in the
115     selected_layer.
116 bh 144 """
117 bh 6 self.selected_layer = selected_layer
118 bh 535 self.selected_shapes = selected_shapes
119 bh 1866 self.render_map()
120 bh 6
121 bh 1866 def RenderMapIncrementally(self):
122     """Render the map.
123 bh 535
124 bh 1866 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 bh 535
131 bh 1866 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 bh 1593 def layer_shapes(self, layer):
151 bh 144 """Return the shapeids covered by the region that has to be redrawn
152 bh 6
153 bh 144 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 bh 1866 x, y, width, height = self.region
172 bh 144 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 frank 909 class ExportRenderer(ScreenRenderer):
189 bh 6
190 frank 909 honor_visibility = 1
191 bh 1552
192 bh 1866 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 frank 909 """Render the map.
206 bh 6
207 frank 909 The rendering device has been specified during initialisation.
208 bh 1866 The device border distance was set in
209     Thuban.UI.viewport.output_transform().
210 bh 1552
211 frank 909 RenderMap renders a frame set (one page frame, one around
212 bh 1866 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 frank 909 """
217 bh 1552
218 frank 909 self.selected_layer = selected_layer
219     self.selected_shapes = selected_shapes
220    
221 bh 1552 # Get some dimensions
222 bh 1866 llx, lly, urx, ury = self.region
223     mminx, mminy, mmaxx, mmaxy = self.destination_region
224 frank 909
225 bh 1552 # Manipulate the offset to position the map
226 frank 909 offx, offy = self.offset
227     # 1. Shift to corner of map drawing area
228 bh 1552 offx = offx + mminx
229 frank 909 offy = offy + mminy
230    
231     # 2. Center the map on the map drawing area:
232 bh 1552 # region identifies the region on the canvas view:
233 frank 909 # 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 bh 1552 self.dc.SetClippingRegion(mminx+self.shiftx, mminy+self.shifty,
243 frank 909 urx, ury)
244 bh 1866 self.render_map()
245 frank 909 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 bh 1866 self.render_frame()
256     self.render_legend()
257     self.render_scalebar()
258 frank 909 self.dc.EndDrawing()
259    
260 bh 1866 def render_frame(self):
261 frank 909 """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 bh 1866 mminx, mminy, mmaxx, mmaxy = self.destination_region
270 frank 909
271     # Page Frame
272     dc.DrawRectangle(15,15,width-30, (mmaxy-mminy)+10)
273 bh 1552
274 frank 909 # Map Frame
275 bh 1866 llx, lly, urx, ury = self.region
276 frank 909 dc.DrawRectangle(mminx + self.shiftx, mminy + self.shifty, urx, ury)
277 bh 1552
278 frank 909 # 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 bh 1866 def render_legend(self):
286 frank 909 """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 bh 1866 mminx, mminy, mmaxx, mmaxy = self.destination_region
296 frank 909 textwidth, textheight = dc.GetTextExtent("0")
297     iconwidth = textheight
298     iconheight = textheight
299     stepy = textheight+3
300     dx = 10
301 bh 1552 posx = mmaxx + 10 + 5 # 10 pix distance mapframe/legend frame,
302 frank 909 # 5 pix inside legend frame
303     posy = mminy + 5 # 5 pix inside legend frame
304 bh 1552
305 frank 909 # Render the legend
306     dc.SetTextForeground(wxBLACK)
307 bh 1866 if self.map.HasLayers():
308     layers = self.map.Layers()[:]
309 frank 1324 layers.reverse()
310     for l in layers:
311 frank 909 if l.Visible():
312     # Render title
313     dc.DrawText(l.Title(), posx, posy)
314     posy+=stepy
315 jonathan 1298 if l.HasClassification():
316     # Render classification
317     clazz = l.GetClassification()
318     shapeType = l.ShapeType()
319     for g in clazz:
320     if g.IsVisible():
321 bh 1552 previewer.Draw(dc,
322     wxRect(posx+dx, posy,
323     iconwidth, iconheight),
324 jonathan 1298 g.GetProperties(), shapeType)
325 bh 1552 dc.DrawText(g.GetDisplayText(),
326 jonathan 1298 posx+2*dx+iconwidth, posy)
327     posy+=stepy
328 bh 1552
329 bh 1866 def render_scalebar(self):
330 frank 909 """Render the scalebar."""
331    
332 bh 1866 scalebar = ScaleBar(self.map)
333 frank 909
334     # Dimension stuff
335     width, height = self.dc.GetSizeTuple()
336 bh 1866 mminx, mminy, mmaxx, mmaxy = self.destination_region
337 bh 1552
338 frank 909 # Render the scalebar
339 bh 1552 scalebar.DrawScaleBar(self.scale, self.dc,
340 frank 909 (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