/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/renderer.py
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/Thuban/UI/renderer.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 686 - (show annotations)
Wed Apr 16 13:22:25 2003 UTC (21 years, 10 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 11121 byte(s)
Safer implementation of the performance enhancements of the
low-level renderer:

* extensions/thuban/wxproj.cpp (extract_projection)
(extract_pointer): Rename extract_projection to extract_pointer
and redefine its purpose to return the pointer stored in a CObject
returned by the object's cobject method. Update all callers.
(s_draw_info, free_draw_info, draw_polygon_init): Implement the
handling of these low-level parameters so that each s_draw_info
instance is handled as a CObject at python level that also
contains real references to the actual python objects which
contain the values in the struct. Add free_draw_info as the
destructor.
(draw_polygon_shape): Add the py_draw_info parameter which must a
cobject containing an s_draw_info pointer.

* Thuban/UI/renderer.py (MapRenderer.polygon_render_param): New
method to instantiat the low-level render parameter
(MapRenderer.draw_shape_layer): Use the new method. Remove some
commented out code.
(MapRenderer.draw_polygon_shape): Make the first parameter not the
layer but the low-level render parameter
(ScreenRenderer.draw_shape_layer): Use the low-level render
parameter.

1 # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2 # Authors:
3 # Bernhard Herzog <[email protected]>
4 # Jonathan Coles <[email protected]>
5 #
6 # This program is free software under the GPL (>=v2)
7 # Read the file COPYING coming with Thuban for details.
8
9 __version__ = "$Revision$"
10
11 from wxPython.wx import wxPoint, wxPen, wxBrush, wxFont, \
12 wxTRANSPARENT_PEN, wxTRANSPARENT_BRUSH, \
13 wxBLACK, wxSOLID, wxCROSS_HATCH, wxSWISS, wxNORMAL
14
15 from wxproj import draw_polygon_shape, draw_polygon_init
16
17 from Thuban import _
18 from Thuban.UI.common import *
19
20 from Thuban.Model.layer import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \
21 SHAPETYPE_POINT
22 from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \
23 ALIGN_LEFT, ALIGN_RIGHT, ALIGN_BASELINE
24
25 from Thuban.Model.classification import Classification
26 from Thuban.Model.color import Color
27
28
29 class MapRenderer:
30
31 """Class to render a map onto a wxDC"""
32
33 honor_visibility = 1
34
35 def __init__(self, dc, scale, offset, resolution = 72.0,
36 honor_visibility = None):
37 """Inititalize the renderer.
38
39 dc -- the wxPython DC to render on
40 scale, offset -- the scale factor and translation to convert
41 between projected coordinates and the DC coordinates
42
43 resolution -- the assumed resolution of the DC. Used to convert
44 absolute lengths like font sizes to DC coordinates
45
46 honor_visibility -- boolean. If true, honor the visibility flag
47 of the layers, otherwise draw all layers. If None, use
48 the renderer's default.
49 """
50 # resolution in pixel/inch
51
52 assert scale > 0
53
54 self.dc = dc
55 self.scale = scale
56 self.offset = offset
57 if honor_visibility is not None:
58 self.honor_visibility = honor_visibility
59 # store the resolution in pixel/point because it's more useful
60 # later.
61 self.resolution = resolution / 72.0
62
63 def render_map(self, map):
64 self.map = map
65 for layer in map.Layers():
66 # if honor_visibility is true, only draw visible layers,
67 # otherwise draw all layers
68 if not self.honor_visibility or layer.Visible():
69 self.draw_shape_layer(layer)
70 self.draw_label_layer(map.LabelLayer())
71
72 def draw_shape_layer(self, layer):
73 scale = self.scale
74 offx, offy = self.offset
75
76 map_proj = self.map.projection
77 layer_proj = layer.projection
78
79 shapetype = layer.ShapeType()
80
81 brush = wxTRANSPARENT_BRUSH
82 pen = wxTRANSPARENT_PEN
83
84 old_prop = None
85 lc = layer.GetClassification()
86 field = lc.GetField()
87
88
89 if shapetype != SHAPETYPE_POINT:
90 polygon_render_param = self.polygon_render_param(layer)
91
92 for i in self.layer_ids(layer):
93 value = None
94
95 if field is not None:
96 try:
97 record = layer.table.read_record(i)
98 if record is not None:
99 value = record[field]
100 except:
101 pass
102
103 #
104 # if the above statements fail 'value' should
105 # be null, at which point this call will
106 # at least retreive the NullData
107 #
108
109 group = lc.FindGroup(value)
110
111 #prop = lc.GetProperties(value)
112 else:
113 group = lc.GetDefaultGroup()
114
115
116 if not group.IsVisible():
117 continue
118
119 prop = group.GetProperties()
120
121 # don't recreate new objects if they are the same as before
122 if prop != old_prop:
123 old_prop = prop
124
125 if shapetype == SHAPETYPE_ARC:
126 fill = Color.Transparent
127 else:
128 fill = prop.GetFill()
129
130
131 if fill is Color.Transparent:
132 brush = wxTRANSPARENT_BRUSH
133 else:
134 color = Color2wxColour(fill)
135 brush = wxBrush(color, wxSOLID)
136
137 stroke = prop.GetLineColor()
138 stroke_width = prop.GetLineWidth()
139 if stroke is Color.Transparent:
140 pen = wxTRANSPARENT_PEN
141 else:
142 color = Color2wxColour(stroke)
143 pen = wxPen(color, stroke_width, wxSOLID)
144
145
146 if shapetype == SHAPETYPE_POINT:
147 self.dc.SetBrush(brush)
148 self.dc.SetPen(pen)
149 self.draw_point_shape(layer, i)
150 else:
151 self.draw_polygon_shape(polygon_render_param, i, pen, brush)
152
153 def layer_ids(self, layer):
154 """Return the shape ids of the given layer that have to be drawn.
155
156 The default implementation simply returns all ids in the layer.
157 Override in derived classes to be more precise.
158 """
159 return range(layer.NumShapes())
160
161 def polygon_render_param(self, layer):
162 """Return the low-lever render parameter for the layer"""
163 offx, offy = self.offset
164 return draw_polygon_init(layer.shapefile, self.dc,
165 self.map.projection,
166 layer.projection,
167 self.scale, -self.scale,
168 offx, offy)
169
170 def draw_polygon_shape(self, draw_polygon_info, index, pen, brush):
171 draw_polygon_shape(draw_polygon_info, index, pen, brush)
172
173 def projected_points(self, layer, index):
174 proj = self.map.projection
175 if proj is not None:
176 forward = proj.Forward
177 else:
178 forward = None
179 proj = layer.projection
180 if proj is not None:
181 inverse = proj.Inverse
182 else:
183 inverse = None
184 shape = layer.Shape(index)
185 points = []
186 scale = self.scale
187 offx, offy = self.offset
188 for x, y in shape.Points():
189 if inverse:
190 x, y = inverse(x, y)
191 if forward:
192 x, y = forward(x, y)
193 points.append(wxPoint(x * scale + offx,
194 -y * scale + offy))
195 return points
196
197 def draw_arc_shape(self, layer, index):
198 points = self.projected_points(layer, index)
199 self.dc.DrawLines(points)
200
201 def draw_point_shape(self, layer, index):
202 pp = self.projected_points(layer, index)
203
204 if len(pp) == 0: return # ignore Null Shapes which have no points
205
206 p = pp[0]
207 radius = self.resolution * 5
208 self.dc.DrawEllipse(p.x - radius, p.y - radius, 2*radius, 2*radius)
209
210 def draw_label_layer(self, layer):
211 scale = self.scale
212 offx, offy = self.offset
213
214 font = wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)
215 self.dc.SetFont(font)
216
217 map_proj = self.map.projection
218 if map_proj is not None:
219 forward = map_proj.Forward
220 else:
221 forward = None
222
223 for label in layer.Labels():
224 x = label.x
225 y = label.y
226 text = label.text
227 if forward:
228 x, y = forward(x, y)
229 x = x * scale + offx
230 y = -y * scale + offy
231 width, height = self.dc.GetTextExtent(text)
232 if label.halign == ALIGN_LEFT:
233 # nothing to be done
234 pass
235 elif label.halign == ALIGN_RIGHT:
236 x = x - width
237 elif label.halign == ALIGN_CENTER:
238 x = x - width/2
239 if label.valign == ALIGN_TOP:
240 # nothing to be done
241 pass
242 elif label.valign == ALIGN_BOTTOM:
243 y = y - height
244 elif label.valign == ALIGN_CENTER:
245 y = y - height/2
246 self.dc.DrawText(text, x, y)
247
248
249 class ScreenRenderer(MapRenderer):
250
251 # On the screen we want to see only visible layers by default
252 honor_visibility = 1
253
254 def RenderMap(self, map, region, selected_layer, selected_shapes):
255 """Render the map.
256
257 Only the given region (a tuple in window coordinates as returned
258 by a wxrect's asTuple method) needs to be redrawn. Highlight the
259 shapes given by the ids in selected_shapes in the
260 selected_layer.
261 """
262 self.update_region = region
263 self.selected_layer = selected_layer
264 self.selected_shapes = selected_shapes
265 self.render_map(map)
266
267 def draw_shape_layer(self, layer):
268 MapRenderer.draw_shape_layer(self, layer)
269 if layer is self.selected_layer and self.selected_shapes:
270 pen = wxPen(wxBLACK, 3, wxSOLID)
271 brush = wxBrush(wxBLACK, wxCROSS_HATCH)
272
273 shapetype = layer.ShapeType()
274 if shapetype == SHAPETYPE_POLYGON:
275 offx, offy = self.offset
276 renderparam = self.polygon_render_param(layer)
277 func = self.draw_polygon_shape
278 args = (pen, brush)
279 elif shapetype == SHAPETYPE_ARC:
280 renderparam = self.polygon_render_param(layer)
281 func = self.draw_polygon_shape
282 args = (pen, None)
283 elif shapetype == SHAPETYPE_POINT:
284 renderparam = layer
285 self.dc.SetBrush(brush)
286 self.dc.SetPen(pen)
287 func = self.draw_point_shape
288 args = ()
289 else:
290 raise TypeError(_("Unhandled shape type %s") % shapetype)
291
292 for index in self.selected_shapes:
293 func(renderparam, index, *args)
294
295
296 def layer_ids(self, layer):
297 """Return the shapeids covered by the region that has to be redrawn
298
299 Call the layer's ShapesInRegion method to determine the ids so
300 that it can use the quadtree.
301 """
302 # FIXME: the quad-tree should be built from the projected
303 # coordinates not the lat-long ones because it's not trivial to
304 # determine an appropriate rectangle in lat-long for a given
305 # rectangle in projected coordinates which we have to start from
306 # here.
307 proj = self.map.projection
308 if proj is not None:
309 inverse = proj.Inverse
310 else:
311 inverse = None
312
313 scale = self.scale
314 offx, offy = self.offset
315 xs = []
316 ys = []
317 x, y, width, height = self.update_region
318 for winx, winy in ((x, y), (x + width, y),
319 (x + width, y + height), (x, y + height)):
320 px = (winx - offx) / scale
321 py = -(winy - offy) / scale
322 if inverse:
323 px, py = inverse(px, py)
324 xs.append(px)
325 ys.append(py)
326 left = min(xs)
327 right = max(xs)
328 top = max(ys)
329 bottom = min(ys)
330
331 return layer.ShapesInRegion((left, bottom, right, top))
332
333
334 class PrinterRender(MapRenderer):
335
336 # When printing we want to see all layers
337 honor_visibility = 0
338
339 RenderMap = MapRenderer.render_map
340

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26