/[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 374 - (show annotations)
Mon Jan 27 14:20:02 2003 UTC (22 years, 1 month ago) by jan
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 10043 byte(s)
Replace user string by _() for i18n.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26