/[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 686 - (hide annotations)
Wed Apr 16 13:22:25 2003 UTC (21 years, 10 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 11121 byte(s)
Safer implementation of the performance enhancements of the
low-level renderer:

* extensions/thuban/wxproj.cpp (extract_projection)
(extract_pointer): Rename extract_projection to extract_pointer
and redefine its purpose to return the pointer stored in a CObject
returned by the object's cobject method. Update all callers.
(s_draw_info, free_draw_info, draw_polygon_init): Implement the
handling of these low-level parameters so that each s_draw_info
instance is handled as a CObject at python level that also
contains real references to the actual python objects which
contain the values in the struct. Add free_draw_info as the
destructor.
(draw_polygon_shape): Add the py_draw_info parameter which must a
cobject containing an s_draw_info pointer.

* Thuban/UI/renderer.py (MapRenderer.polygon_render_param): New
method to instantiat the low-level render parameter
(MapRenderer.draw_shape_layer): Use the new method. Remove some
commented out code.
(MapRenderer.draw_polygon_shape): Make the first parameter not the
layer but the low-level render parameter
(ScreenRenderer.draw_shape_layer): Use the low-level render
parameter.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26