/[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 605 - (show annotations)
Fri Apr 4 12:16:13 2003 UTC (21 years, 11 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 10455 byte(s)
Fix assert calls.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26