/[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 362 - (show annotations)
Mon Jan 27 11:39:03 2003 UTC (22 years, 1 month ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 10018 byte(s)
added support for drawing classifications

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26