/[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 468 - (show annotations)
Wed Mar 5 18:19:13 2003 UTC (22 years ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 10263 byte(s)
(MapRenderer.draw_shape_layer): Only get the layer classification once.
Don't try to classify values when the field is None: just use the default
properties.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26