/[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 362 - (hide annotations)
Mon Jan 27 11:39:03 2003 UTC (22 years, 1 month ago) by jonathan
Original Path: trunk/thuban/Thuban/UI/renderer.py
File MIME type: text/x-python
File size: 10018 byte(s)
added support for drawing classifications

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26