/[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 2552 - (hide annotations)
Fri Jan 28 15:54:00 2005 UTC (20 years, 1 month ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 14414 byte(s)
Make layer's use_mask flag default to true. Support a bit array describing
the mask to use. Improve error handling in ProjectRasterFile (also addresses
RT #2947).

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26