/[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 2514 - (hide annotations)
Mon Jan 3 16:21:17 2005 UTC (20 years, 2 months ago) by frank
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 13704 byte(s)
Thuban/UI/renderer.py (ScreenRendererdraw_selection_incrementally):
    BugFix 2883: Former implementation only worked on classified point layers:
    KeyError was raised, now use the default size if field is None.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26