/[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 442 - (show annotations)
Thu Feb 27 15:55:25 2003 UTC (22 years ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 10043 byte(s)
Use new Classification and Group functions.  Use common.py functions.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26