/[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 882 - (show annotations)
Fri May 9 16:34:28 2003 UTC (21 years, 10 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 11112 byte(s)
Explicit imports.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26