/[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 2537 - (hide annotations)
Fri Jan 21 14:01:25 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: 14399 byte(s)
Improved rendering raster layers by changing the return format of
the ProjectRasterFile function.

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     wxBITMAP_TYPE_GIF, wxEmptyImage
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 2537 def draw_raster_data(self, x,y, data, format = 'BMP', mask = None):
108     if format == 'RAW':
109     image = wxEmptyImage(data[0], data[1])
110     image.SetData(data[2])
111     else:
112     stream = cStringIO.StringIO(data[2])
113     image = wxImageFromStream(stream, raster_format_map[format])
114    
115 bh 1552 bitmap = wxBitmapFromImage(image)
116 jonathan 588
117 jonathan 2537 if mask is None:
118     self.dc.DrawBitmap(bitmap, int(round(x)), int(round(y)), False)
119     else:
120     # if we are given a mask object, try to pass it to SetMaskColour,
121     # otherwise assume it's a mask image
122     try:
123     bitmap.SetMaskColour(mask);
124     self.dc.DrawBitmap(bitmap, int(round(x)), int(round(y)), True)
125     except (TypeError):
126     # implement using a mask image
127     raise NotImplementedError
128 jonathan 588
129 jonathan 2537
130 bh 6 class ScreenRenderer(MapRenderer):
131    
132     # On the screen we want to see only visible layers by default
133     honor_visibility = 1
134 bh 1552
135 bh 1866 def RenderMap(self, selected_layer, selected_shapes):
136 bh 144 """Render the map.
137    
138 bh 148 Only the given region (a tuple in window coordinates as returned
139     by a wxrect's asTuple method) needs to be redrawn. Highlight the
140 bh 535 shapes given by the ids in selected_shapes in the
141     selected_layer.
142 bh 144 """
143 bh 6 self.selected_layer = selected_layer
144 bh 535 self.selected_shapes = selected_shapes
145 bh 1866 self.render_map()
146 bh 6
147 bh 1866 def RenderMapIncrementally(self):
148     """Render the map.
149 bh 535
150 bh 1866 Only the given region (a tuple in window coordinates as returned
151     by a wxrect's asTuple method) needs to be redrawn. Highlight the
152     shapes given by the ids in selected_shapes in the
153     selected_layer.
154     """
155     return self.render_map_incrementally()
156 bh 535
157 bh 1866 def draw_selection_incrementally(self, layer, selected_shapes):
158 jan 2394 """Draw the selected shapes in a emphasized way (i.e.
159     with a special pen and brush.
160     The drawing is performed incrementally, that means every
161     n shapes, the user can have interactions with the map.
162     n is currently fixed to 500.
163    
164     layer -- the layer where the shapes belong to.
165     selected_shapes -- a list of the shape-ids representing the
166     selected shapes for the given layer.
167     """
168 bh 1866 pen = wxPen(wxBLACK, 3, wxSOLID)
169     brush = wxBrush(wxBLACK, wxCROSS_HATCH)
170    
171     shapetype = layer.ShapeType()
172     useraw, func, param = self.low_level_renderer(layer)
173     args = (pen, brush)
174 jan 2394
175     # for point shapes we need to find out the properties
176     # to determine the size. Based on table and field,
177     # we can find out the properties for object - see below.
178     if shapetype == SHAPETYPE_POINT:
179     lc = layer.GetClassification()
180     field = layer.GetClassificationColumn()
181     table = layer.ShapeStore().Table()
182    
183 bh 1866 count = 0
184     for index in selected_shapes:
185     count += 1
186     shape = layer.Shape(index)
187 jan 2394
188     # Get the size of the specific property for this
189     # point
190 frank 2514 if shapetype == SHAPETYPE_POINT and field is not None:
191 jan 2394 value = table.ReadValue(shape.ShapeID(), field)
192     group = lc.FindGroup(value)
193     size = group.GetProperties().GetSize()
194     args = (pen, brush, size)
195    
196 bh 1866 if useraw:
197     data = shape.RawData()
198     else:
199     data = shape.Points()
200     func(param, data, *args)
201     if count % 500 == 0:
202     yield True
203    
204 bh 1593 def layer_shapes(self, layer):
205 bh 144 """Return the shapeids covered by the region that has to be redrawn
206 bh 6
207 bh 144 Call the layer's ShapesInRegion method to determine the ids so
208     that it can use the quadtree.
209     """
210     # FIXME: the quad-tree should be built from the projected
211     # coordinates not the lat-long ones because it's not trivial to
212     # determine an appropriate rectangle in lat-long for a given
213     # rectangle in projected coordinates which we have to start from
214     # here.
215     proj = self.map.projection
216     if proj is not None:
217     inverse = proj.Inverse
218     else:
219     inverse = None
220    
221     scale = self.scale
222     offx, offy = self.offset
223     xs = []
224     ys = []
225 bh 1866 x, y, width, height = self.region
226 bh 144 for winx, winy in ((x, y), (x + width, y),
227     (x + width, y + height), (x, y + height)):
228     px = (winx - offx) / scale
229     py = -(winy - offy) / scale
230     if inverse:
231     px, py = inverse(px, py)
232     xs.append(px)
233     ys.append(py)
234     left = min(xs)
235     right = max(xs)
236     top = max(ys)
237     bottom = min(ys)
238    
239     return layer.ShapesInRegion((left, bottom, right, top))
240    
241    
242 frank 909 class ExportRenderer(ScreenRenderer):
243 bh 6
244 frank 909 honor_visibility = 1
245 bh 1552
246 bh 1866 def __init__(self, *args, **kw):
247     """Initialize the ExportRenderer.
248    
249     In addition to all parameters of the the ScreenRender
250     constructor, this class requires and additional keyword argument
251     destination_region with a tuple (minx, miny, maxx, maxy) giving
252     the region in dc coordinates which is to contain the map.
253     """
254     self.destination_region = kw["destination_region"]
255     del kw["destination_region"]
256     ScreenRenderer.__init__(self, *args, **kw)
257    
258     def RenderMap(self, selected_layer, selected_shapes):
259 frank 909 """Render the map.
260 bh 6
261 frank 909 The rendering device has been specified during initialisation.
262 bh 1866 The device border distance was set in
263     Thuban.UI.viewport.output_transform().
264 bh 1552
265 frank 909 RenderMap renders a frame set (one page frame, one around
266 bh 1866 legend/scalebar and one around the map), the map, the legend and
267     the scalebar on the given DC. The map is rendered with the
268     region displayed in the canvas view, centered on the area
269     available for map display.
270 frank 909 """
271 bh 1552
272 frank 909 self.selected_layer = selected_layer
273     self.selected_shapes = selected_shapes
274    
275 bh 1552 # Get some dimensions
276 bh 1866 llx, lly, urx, ury = self.region
277     mminx, mminy, mmaxx, mmaxy = self.destination_region
278 frank 909
279 bh 1552 # Manipulate the offset to position the map
280 frank 909 offx, offy = self.offset
281     # 1. Shift to corner of map drawing area
282 bh 1552 offx = offx + mminx
283 frank 909 offy = offy + mminy
284    
285     # 2. Center the map on the map drawing area:
286 bh 1552 # region identifies the region on the canvas view:
287 frank 909 # center of map drawing area - half the size of region: rendering origin
288     self.shiftx = (mmaxx - mminx)*0.5 - (urx - llx)*0.5
289     self.shifty = (mmaxy - mminy)*0.5 - (ury - lly)*0.5
290    
291     self.offset = (offx+self.shiftx, offy+self.shifty)
292 bh 2454 self.region = (llx + self.shiftx, lly + self.shifty, urx, ury)
293 frank 909
294     # Draw the map
295     self.dc.BeginDrawing()
296     self.dc.DestroyClippingRegion()
297 bh 1552 self.dc.SetClippingRegion(mminx+self.shiftx, mminy+self.shifty,
298 frank 909 urx, ury)
299 bh 1866 self.render_map()
300 frank 909 self.dc.EndDrawing()
301    
302     # Draw the rest (frames, legend, scalebar)
303     self.dc.BeginDrawing()
304     self.dc.DestroyClippingRegion()
305    
306     # Force the font for Legend drawing
307     font = wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)
308     self.dc.SetFont(font)
309    
310 bh 1866 self.render_frame()
311     self.render_legend()
312     self.render_scalebar()
313 frank 909 self.dc.EndDrawing()
314    
315 bh 1866 def render_frame(self):
316 frank 909 """Render the frames for map and legend/scalebar."""
317    
318     dc = self.dc
319     dc.SetPen(wxBLACK_PEN)
320     dc.SetBrush(wxTRANSPARENT_BRUSH)
321    
322     # Dimension stuff
323     width, height = dc.GetSizeTuple()
324 bh 1866 mminx, mminy, mmaxx, mmaxy = self.destination_region
325 frank 909
326     # Page Frame
327     dc.DrawRectangle(15,15,width-30, (mmaxy-mminy)+10)
328 bh 1552
329 frank 909 # Map Frame
330 bh 1866 llx, lly, urx, ury = self.region
331 frank 909 dc.DrawRectangle(mminx + self.shiftx, mminy + self.shifty, urx, ury)
332 bh 1552
333 frank 909 # Legend Frame
334     dc.DrawRectangle(mmaxx+10,mminy,(width-20) - (mmaxx+10), mmaxy-mminy)
335    
336     dc.DestroyClippingRegion()
337     dc.SetClippingRegion(mmaxx+10,mminy,
338     (width-20) - (mmaxx+10), mmaxy-mminy)
339    
340 bh 1866 def render_legend(self):
341 frank 909 """Render the legend on the Map."""
342    
343     previewer = ClassDataPreviewer()
344     dc = self.dc
345     dc.SetPen(wxBLACK_PEN)
346     dc.SetBrush(wxTRANSPARENT_BRUSH)
347    
348     # Dimension stuff
349     width, height = dc.GetSizeTuple()
350 bh 1866 mminx, mminy, mmaxx, mmaxy = self.destination_region
351 frank 909 textwidth, textheight = dc.GetTextExtent("0")
352     iconwidth = textheight
353     iconheight = textheight
354     stepy = textheight+3
355     dx = 10
356 bh 1552 posx = mmaxx + 10 + 5 # 10 pix distance mapframe/legend frame,
357 frank 909 # 5 pix inside legend frame
358     posy = mminy + 5 # 5 pix inside legend frame
359 bh 1552
360 frank 909 # Render the legend
361     dc.SetTextForeground(wxBLACK)
362 bh 1866 if self.map.HasLayers():
363     layers = self.map.Layers()[:]
364 frank 1324 layers.reverse()
365     for l in layers:
366 frank 909 if l.Visible():
367     # Render title
368     dc.DrawText(l.Title(), posx, posy)
369     posy+=stepy
370 jonathan 1298 if l.HasClassification():
371     # Render classification
372     clazz = l.GetClassification()
373     shapeType = l.ShapeType()
374     for g in clazz:
375     if g.IsVisible():
376 bh 1552 previewer.Draw(dc,
377     wxRect(posx+dx, posy,
378     iconwidth, iconheight),
379 jonathan 1298 g.GetProperties(), shapeType)
380 bh 1552 dc.DrawText(g.GetDisplayText(),
381 jonathan 1298 posx+2*dx+iconwidth, posy)
382     posy+=stepy
383 bh 1552
384 bh 1866 def render_scalebar(self):
385 frank 909 """Render the scalebar."""
386    
387 bh 1866 scalebar = ScaleBar(self.map)
388 frank 909
389     # Dimension stuff
390     width, height = self.dc.GetSizeTuple()
391 bh 1866 mminx, mminy, mmaxx, mmaxy = self.destination_region
392 bh 1552
393 frank 909 # Render the scalebar
394 bh 1552 scalebar.DrawScaleBar(self.scale, self.dc,
395 frank 909 (mmaxx+10+5, mmaxy-25),
396     ((width-15-5) - (mmaxx+10+5),20)
397     )
398     # 10 pix between map and legend frame, 5 pix inside legend frame
399     # 25 pix from the legend frame bottom line
400     # Width: 15 pix from DC border, 5 pix inside frame, 10, 5 as above
401     # Height: 20
402    
403     class PrinterRenderer(ExportRenderer):
404    
405     # Printing as well as Export / Screen display only the visible layer.
406     honor_visibility = 1
407    

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26