/[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 574 - (hide annotations)
Fri Mar 28 17:07:26 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: 10364 byte(s)
(MapRenderer.__init__): Added assert
        to check if scale > 0. Trying to track down a divide by zero.

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     p = self.projected_points(layer, index)[0]
185     radius = self.resolution * 5
186     self.dc.DrawEllipse(p.x - radius, p.y - radius, 2*radius, 2*radius)
187    
188     def draw_label_layer(self, layer):
189     scale = self.scale
190     offx, offy = self.offset
191    
192     font = wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)
193     self.dc.SetFont(font)
194    
195     map_proj = self.map.projection
196     if map_proj is not None:
197     forward = map_proj.Forward
198     else:
199     forward = None
200    
201     for label in layer.Labels():
202     x = label.x
203     y = label.y
204     text = label.text
205     if forward:
206     x, y = forward(x, y)
207     x = x * scale + offx
208     y = -y * scale + offy
209     width, height = self.dc.GetTextExtent(text)
210     if label.halign == ALIGN_LEFT:
211     # nothing to be done
212     pass
213     elif label.halign == ALIGN_RIGHT:
214     x = x - width
215     elif label.halign == ALIGN_CENTER:
216     x = x - width/2
217     if label.valign == ALIGN_TOP:
218     # nothing to be done
219     pass
220     elif label.valign == ALIGN_BOTTOM:
221     y = y - height
222     elif label.valign == ALIGN_CENTER:
223     y = y - height/2
224     self.dc.DrawText(text, x, y)
225    
226    
227     class ScreenRenderer(MapRenderer):
228    
229     # On the screen we want to see only visible layers by default
230     honor_visibility = 1
231    
232 bh 535 def RenderMap(self, map, region, selected_layer, selected_shapes):
233 bh 144 """Render the map.
234    
235 bh 148 Only the given region (a tuple in window coordinates as returned
236     by a wxrect's asTuple method) needs to be redrawn. Highlight the
237 bh 535 shapes given by the ids in selected_shapes in the
238     selected_layer.
239 bh 144 """
240     self.update_region = region
241 bh 6 self.selected_layer = selected_layer
242 bh 535 self.selected_shapes = selected_shapes
243 bh 6 self.render_map(map)
244    
245     def draw_shape_layer(self, layer):
246     MapRenderer.draw_shape_layer(self, layer)
247 bh 535 if layer is self.selected_layer and self.selected_shapes:
248 bh 6 pen = wxPen(wxBLACK, 3, wxSOLID)
249     brush = wxBrush(wxBLACK, wxCROSS_HATCH)
250 bh 535
251 bh 6 shapetype = layer.ShapeType()
252     if shapetype == SHAPETYPE_POLYGON:
253 bh 535 func = self.draw_polygon_shape
254     args = (pen, brush)
255 bh 290 elif shapetype == SHAPETYPE_ARC:
256 bh 535 func = self.draw_polygon_shape
257     args = (pen, None)
258     elif shapetype == SHAPETYPE_POINT:
259 bh 6 self.dc.SetBrush(brush)
260     self.dc.SetPen(pen)
261 bh 535 func = self.draw_point_shape
262     args = ()
263     else:
264     raise TypeError(_("Unhandled shape type %s") % shapetype)
265 bh 6
266 bh 535 for index in self.selected_shapes:
267     func(layer, index, *args)
268    
269 bh 144 def layer_ids(self, layer):
270     """Return the shapeids covered by the region that has to be redrawn
271 bh 6
272 bh 144 Call the layer's ShapesInRegion method to determine the ids so
273     that it can use the quadtree.
274     """
275     # FIXME: the quad-tree should be built from the projected
276     # coordinates not the lat-long ones because it's not trivial to
277     # determine an appropriate rectangle in lat-long for a given
278     # rectangle in projected coordinates which we have to start from
279     # here.
280     proj = self.map.projection
281     if proj is not None:
282     inverse = proj.Inverse
283     else:
284     inverse = None
285    
286     scale = self.scale
287     offx, offy = self.offset
288     xs = []
289     ys = []
290 bh 148 x, y, width, height = self.update_region
291 bh 144 for winx, winy in ((x, y), (x + width, y),
292     (x + width, y + height), (x, y + height)):
293     px = (winx - offx) / scale
294     py = -(winy - offy) / scale
295     if inverse:
296     px, py = inverse(px, py)
297     xs.append(px)
298     ys.append(py)
299     left = min(xs)
300     right = max(xs)
301     top = max(ys)
302     bottom = min(ys)
303    
304     return layer.ShapesInRegion((left, bottom, right, top))
305    
306    
307 bh 6 class PrinterRender(MapRenderer):
308    
309     # When printing we want to see all layers
310     honor_visibility = 0
311    
312     RenderMap = MapRenderer.render_map
313    

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26