/[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 588 - (hide annotations)
Tue Apr 1 15:58:02 2003 UTC (21 years, 11 months ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 10456 byte(s)
(MapRenderer.draw_point_shape): Check
        that there actually are points in the returned list of points
        before trying to index into the list. The list may be empty if
        the shape is a Null Shape.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26