/[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 2431 - (hide annotations)
Sun Dec 5 15:05:02 2004 UTC (20 years, 3 months ago) by joey
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 13611 byte(s)
Added PNG, TIFF and GIF as supported bitmap image formats (helpful
for the WMS extension)

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     if shapetype == SHAPETYPE_POINT:
170     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    
272     # Draw the map
273     self.dc.BeginDrawing()
274     self.dc.DestroyClippingRegion()
275 bh 1552 self.dc.SetClippingRegion(mminx+self.shiftx, mminy+self.shifty,
276 frank 909 urx, ury)
277 bh 1866 self.render_map()
278 frank 909 self.dc.EndDrawing()
279    
280     # Draw the rest (frames, legend, scalebar)
281     self.dc.BeginDrawing()
282     self.dc.DestroyClippingRegion()
283    
284     # Force the font for Legend drawing
285     font = wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)
286     self.dc.SetFont(font)
287    
288 bh 1866 self.render_frame()
289     self.render_legend()
290     self.render_scalebar()
291 frank 909 self.dc.EndDrawing()
292    
293 bh 1866 def render_frame(self):
294 frank 909 """Render the frames for map and legend/scalebar."""
295    
296     dc = self.dc
297     dc.SetPen(wxBLACK_PEN)
298     dc.SetBrush(wxTRANSPARENT_BRUSH)
299    
300     # Dimension stuff
301     width, height = dc.GetSizeTuple()
302 bh 1866 mminx, mminy, mmaxx, mmaxy = self.destination_region
303 frank 909
304     # Page Frame
305     dc.DrawRectangle(15,15,width-30, (mmaxy-mminy)+10)
306 bh 1552
307 frank 909 # Map Frame
308 bh 1866 llx, lly, urx, ury = self.region
309 frank 909 dc.DrawRectangle(mminx + self.shiftx, mminy + self.shifty, urx, ury)
310 bh 1552
311 frank 909 # Legend Frame
312     dc.DrawRectangle(mmaxx+10,mminy,(width-20) - (mmaxx+10), mmaxy-mminy)
313    
314     dc.DestroyClippingRegion()
315     dc.SetClippingRegion(mmaxx+10,mminy,
316     (width-20) - (mmaxx+10), mmaxy-mminy)
317    
318 bh 1866 def render_legend(self):
319 frank 909 """Render the legend on the Map."""
320    
321     previewer = ClassDataPreviewer()
322     dc = self.dc
323     dc.SetPen(wxBLACK_PEN)
324     dc.SetBrush(wxTRANSPARENT_BRUSH)
325    
326     # Dimension stuff
327     width, height = dc.GetSizeTuple()
328 bh 1866 mminx, mminy, mmaxx, mmaxy = self.destination_region
329 frank 909 textwidth, textheight = dc.GetTextExtent("0")
330     iconwidth = textheight
331     iconheight = textheight
332     stepy = textheight+3
333     dx = 10
334 bh 1552 posx = mmaxx + 10 + 5 # 10 pix distance mapframe/legend frame,
335 frank 909 # 5 pix inside legend frame
336     posy = mminy + 5 # 5 pix inside legend frame
337 bh 1552
338 frank 909 # Render the legend
339     dc.SetTextForeground(wxBLACK)
340 bh 1866 if self.map.HasLayers():
341     layers = self.map.Layers()[:]
342 frank 1324 layers.reverse()
343     for l in layers:
344 frank 909 if l.Visible():
345     # Render title
346     dc.DrawText(l.Title(), posx, posy)
347     posy+=stepy
348 jonathan 1298 if l.HasClassification():
349     # Render classification
350     clazz = l.GetClassification()
351     shapeType = l.ShapeType()
352     for g in clazz:
353     if g.IsVisible():
354 bh 1552 previewer.Draw(dc,
355     wxRect(posx+dx, posy,
356     iconwidth, iconheight),
357 jonathan 1298 g.GetProperties(), shapeType)
358 bh 1552 dc.DrawText(g.GetDisplayText(),
359 jonathan 1298 posx+2*dx+iconwidth, posy)
360     posy+=stepy
361 bh 1552
362 bh 1866 def render_scalebar(self):
363 frank 909 """Render the scalebar."""
364    
365 bh 1866 scalebar = ScaleBar(self.map)
366 frank 909
367     # Dimension stuff
368     width, height = self.dc.GetSizeTuple()
369 bh 1866 mminx, mminy, mmaxx, mmaxy = self.destination_region
370 bh 1552
371 frank 909 # Render the scalebar
372 bh 1552 scalebar.DrawScaleBar(self.scale, self.dc,
373 frank 909 (mmaxx+10+5, mmaxy-25),
374     ((width-15-5) - (mmaxx+10+5),20)
375     )
376     # 10 pix between map and legend frame, 5 pix inside legend frame
377     # 25 pix from the legend frame bottom line
378     # Width: 15 pix from DC border, 5 pix inside frame, 10, 5 as above
379     # Height: 20
380    
381     class PrinterRenderer(ExportRenderer):
382    
383     # Printing as well as Export / Screen display only the visible layer.
384     honor_visibility = 1
385    

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26