/[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 676 - (show annotations)
Tue Apr 15 19:20:40 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: 10901 byte(s)
(MapRenderer.draw_shape_layer): Make drawing initialization call to
        draw_polygon_init()
(MapRenderer.draw_polygon_shape): Use new signature of draw_polygon_shape.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26