/[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 882 - (hide annotations)
Fri May 9 16:34:28 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: 11112 byte(s)
Explicit imports.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26