/[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 641 - (show annotations)
Thu Apr 10 14:36:19 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: 10639 byte(s)
(MapRenderer.draw_shape_layer): Only draw visible groups.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26