/[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 424 - (hide annotations)
Mon Feb 24 14:17:07 2003 UTC (22 years ago) by bh
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 10179 byte(s)
(MapRenderer.draw_shape_layer): Remove
unneeded Shape() call. Rendering is substantially faster without
it and it avoids some problems with broken shape files.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26