/[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 432 - (show annotations)
Mon Feb 24 18:47:36 2003 UTC (22 years ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 10178 byte(s)
(MapRenderer.draw_shape_layer): Change
        Classification method name from GetProperties to GetClassData.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26