/[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 2394 - (hide annotations)
Wed Nov 17 22:02:29 2004 UTC (20 years, 3 months ago) by jan
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 13457 byte(s)
(ScreenRenderer.draw_selection_incrementally):
Added consideration of the specific size of point symbols.
The property for each point symbol is retrieved and the size applied
for the rendering method.
Added doc-string.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26