/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/renderer.py
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/Thuban/UI/renderer.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 798 - (hide annotations)
Wed Apr 30 17:02:04 2003 UTC (21 years, 10 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 11096 byte(s)
(MapRenderer.draw_shape_layer): Optimize
        the rendering loop by reducing the number of if's, removing the
        unnecessary try/except block, and checking if the old group
        is the same as the new one (which happens a lot if there is
        no classification, or lots of shapes are in the same group).

1 bh 424 # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2 bh 6 # Authors:
3     # Bernhard Herzog <[email protected]>
4 jonathan 416 # Jonathan Coles <[email protected]>
5 bh 6 #
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 jonathan 442 from wxPython.wx import wxPoint, wxPen, wxBrush, wxFont, \
12 bh 6 wxTRANSPARENT_PEN, wxTRANSPARENT_BRUSH, \
13     wxBLACK, wxSOLID, wxCROSS_HATCH, wxSWISS, wxNORMAL
14    
15 jonathan 676 from wxproj import draw_polygon_shape, draw_polygon_init
16 bh 6
17 jan 374 from Thuban import _
18 jonathan 442 from Thuban.UI.common import *
19 jan 374
20 bh 6 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 jonathan 394 from Thuban.Model.classification import Classification
26 jonathan 416 from Thuban.Model.color import Color
27 bh 6
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 jonathan 574
51 bh 6 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 jonathan 362 brush = wxTRANSPARENT_BRUSH
79     pen = wxTRANSPARENT_PEN
80    
81     old_prop = None
82 jonathan 798 old_group = None
83 jonathan 468 lc = layer.GetClassification()
84     field = lc.GetField()
85 jonathan 798 defaultGroup = lc.GetDefaultGroup()
86 jonathan 468
87 jonathan 676
88     if shapetype != SHAPETYPE_POINT:
89 bh 686 polygon_render_param = self.polygon_render_param(layer)
90 jonathan 676
91 jonathan 798 if shapetype == SHAPETYPE_POINT:
92     draw_func = lambda i: \
93     self.draw_point_shape(layer, i)
94     else:
95     draw_func = lambda i: \
96     self.draw_polygon_shape(polygon_render_param, i, pen, brush)
97    
98 jonathan 362 for i in self.layer_ids(layer):
99    
100 jonathan 798 if field is None:
101     group = defaultGroup
102 jonathan 468 else:
103 jonathan 798 record = layer.table.read_record(i)
104     assert record is not None
105     group = lc.FindGroup(record[field])
106 jonathan 362
107 jonathan 642
108     if not group.IsVisible():
109     continue
110    
111 jonathan 676
112 jonathan 442 # don't recreate new objects if they are the same as before
113 jonathan 798 if group is not old_group:
114     old_group = group
115 jonathan 362
116 jonathan 798 prop = group.GetProperties()
117 jonathan 676
118 jonathan 798 if prop != old_prop:
119     old_prop = prop
120 bh 686
121 jonathan 798 if shapetype == SHAPETYPE_ARC:
122     fill = Color.Transparent
123     else:
124     fill = prop.GetFill()
125 bh 686
126 jonathan 676
127 jonathan 798 if fill is Color.Transparent:
128     brush = wxTRANSPARENT_BRUSH
129     else:
130     color = Color2wxColour(fill)
131     brush = wxBrush(color, wxSOLID)
132 bh 686
133 jonathan 798 stroke = prop.GetLineColor()
134     stroke_width = prop.GetLineWidth()
135     if stroke is Color.Transparent:
136     pen = wxTRANSPARENT_PEN
137     else:
138     color = Color2wxColour(stroke)
139     pen = wxPen(color, stroke_width, wxSOLID)
140 bh 6
141 jonathan 798 if shapetype == SHAPETYPE_POINT:
142     self.dc.SetBrush(brush)
143     self.dc.SetPen(pen)
144    
145     draw_func(i)
146    
147 bh 144 def layer_ids(self, layer):
148     """Return the shape ids of the given layer that have to be drawn.
149 bh 686
150 bh 144 The default implementation simply returns all ids in the layer.
151     Override in derived classes to be more precise.
152     """
153     return range(layer.NumShapes())
154    
155 bh 686 def polygon_render_param(self, layer):
156     """Return the low-lever render parameter for the layer"""
157     offx, offy = self.offset
158     return draw_polygon_init(layer.shapefile, self.dc,
159     self.map.projection,
160     layer.projection,
161     self.scale, -self.scale,
162     offx, offy)
163 bh 6
164 bh 686 def draw_polygon_shape(self, draw_polygon_info, index, pen, brush):
165     draw_polygon_shape(draw_polygon_info, index, pen, brush)
166    
167 bh 6 def projected_points(self, layer, index):
168 jonathan 798 proj = self.map.GetProjection()
169 bh 6 if proj is not None:
170     forward = proj.Forward
171     else:
172     forward = None
173 jonathan 798 proj = layer.GetProjection()
174 bh 6 if proj is not None:
175     inverse = proj.Inverse
176     else:
177     inverse = None
178     shape = layer.Shape(index)
179     points = []
180     scale = self.scale
181     offx, offy = self.offset
182     for x, y in shape.Points():
183     if inverse:
184     x, y = inverse(x, y)
185     if forward:
186     x, y = forward(x, y)
187     points.append(wxPoint(x * scale + offx,
188     -y * scale + offy))
189     return points
190    
191     def draw_arc_shape(self, layer, index):
192     points = self.projected_points(layer, index)
193     self.dc.DrawLines(points)
194    
195     def draw_point_shape(self, layer, index):
196 jonathan 588 pp = self.projected_points(layer, index)
197    
198     if len(pp) == 0: return # ignore Null Shapes which have no points
199    
200     p = pp[0]
201 bh 6 radius = self.resolution * 5
202     self.dc.DrawEllipse(p.x - radius, p.y - radius, 2*radius, 2*radius)
203    
204     def draw_label_layer(self, layer):
205     scale = self.scale
206     offx, offy = self.offset
207    
208     font = wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)
209     self.dc.SetFont(font)
210    
211     map_proj = self.map.projection
212     if map_proj is not None:
213     forward = map_proj.Forward
214     else:
215     forward = None
216    
217     for label in layer.Labels():
218     x = label.x
219     y = label.y
220     text = label.text
221     if forward:
222     x, y = forward(x, y)
223     x = x * scale + offx
224     y = -y * scale + offy
225     width, height = self.dc.GetTextExtent(text)
226     if label.halign == ALIGN_LEFT:
227     # nothing to be done
228     pass
229     elif label.halign == ALIGN_RIGHT:
230     x = x - width
231     elif label.halign == ALIGN_CENTER:
232     x = x - width/2
233     if label.valign == ALIGN_TOP:
234     # nothing to be done
235     pass
236     elif label.valign == ALIGN_BOTTOM:
237     y = y - height
238     elif label.valign == ALIGN_CENTER:
239     y = y - height/2
240     self.dc.DrawText(text, x, y)
241    
242    
243     class ScreenRenderer(MapRenderer):
244    
245     # On the screen we want to see only visible layers by default
246     honor_visibility = 1
247    
248 bh 535 def RenderMap(self, map, region, selected_layer, selected_shapes):
249 bh 144 """Render the map.
250    
251 bh 148 Only the given region (a tuple in window coordinates as returned
252     by a wxrect's asTuple method) needs to be redrawn. Highlight the
253 bh 535 shapes given by the ids in selected_shapes in the
254     selected_layer.
255 bh 144 """
256     self.update_region = region
257 bh 6 self.selected_layer = selected_layer
258 bh 535 self.selected_shapes = selected_shapes
259 bh 6 self.render_map(map)
260    
261     def draw_shape_layer(self, layer):
262     MapRenderer.draw_shape_layer(self, layer)
263 bh 535 if layer is self.selected_layer and self.selected_shapes:
264 bh 6 pen = wxPen(wxBLACK, 3, wxSOLID)
265     brush = wxBrush(wxBLACK, wxCROSS_HATCH)
266 bh 535
267 bh 6 shapetype = layer.ShapeType()
268     if shapetype == SHAPETYPE_POLYGON:
269 bh 686 offx, offy = self.offset
270     renderparam = self.polygon_render_param(layer)
271 bh 535 func = self.draw_polygon_shape
272     args = (pen, brush)
273 bh 290 elif shapetype == SHAPETYPE_ARC:
274 bh 686 renderparam = self.polygon_render_param(layer)
275 bh 535 func = self.draw_polygon_shape
276     args = (pen, None)
277     elif shapetype == SHAPETYPE_POINT:
278 bh 686 renderparam = layer
279 bh 6 self.dc.SetBrush(brush)
280     self.dc.SetPen(pen)
281 bh 535 func = self.draw_point_shape
282     args = ()
283     else:
284     raise TypeError(_("Unhandled shape type %s") % shapetype)
285 bh 6
286 bh 535 for index in self.selected_shapes:
287 bh 686 func(renderparam, index, *args)
288 bh 535
289 bh 686
290 bh 144 def layer_ids(self, layer):
291     """Return the shapeids covered by the region that has to be redrawn
292 bh 6
293 bh 144 Call the layer's ShapesInRegion method to determine the ids so
294     that it can use the quadtree.
295     """
296     # FIXME: the quad-tree should be built from the projected
297     # coordinates not the lat-long ones because it's not trivial to
298     # determine an appropriate rectangle in lat-long for a given
299     # rectangle in projected coordinates which we have to start from
300     # here.
301     proj = self.map.projection
302     if proj is not None:
303     inverse = proj.Inverse
304     else:
305     inverse = None
306    
307     scale = self.scale
308     offx, offy = self.offset
309     xs = []
310     ys = []
311 bh 148 x, y, width, height = self.update_region
312 bh 144 for winx, winy in ((x, y), (x + width, y),
313     (x + width, y + height), (x, y + height)):
314     px = (winx - offx) / scale
315     py = -(winy - offy) / scale
316     if inverse:
317     px, py = inverse(px, py)
318     xs.append(px)
319     ys.append(py)
320     left = min(xs)
321     right = max(xs)
322     top = max(ys)
323     bottom = min(ys)
324    
325     return layer.ShapesInRegion((left, bottom, right, top))
326    
327    
328 bh 6 class PrinterRender(MapRenderer):
329    
330     # When printing we want to see all layers
331     honor_visibility = 0
332    
333     RenderMap = MapRenderer.render_map
334    

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26