/[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 468 - (hide annotations)
Wed Mar 5 18:19:13 2003 UTC (22 years ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 10263 byte(s)
(MapRenderer.draw_shape_layer): Only get the layer classification once.
Don't try to classify values when the field is None: just use the default
properties.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26