/[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 416 - (show annotations)
Wed Feb 19 16:53:08 2003 UTC (22 years ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 10208 byte(s)
Use new Color and Classification methods.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26