/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/renderer.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/UI/renderer.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 574 by jonathan, Fri Mar 28 17:07:26 2003 UTC revision 1552 by bh, Wed Aug 6 17:21:32 2003 UTC
# Line 2  Line 2 
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  # Jonathan Coles <[email protected]>  # Jonathan Coles <[email protected]>
5    # Frank Koormann <[email protected]>
6  #  #
7  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
8  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
9    
10  __version__ = "$Revision$"  __version__ = "$Revision$"
11    
12  from wxPython.wx import wxPoint, wxPen, wxBrush, wxFont, \  import cStringIO
      wxTRANSPARENT_PEN, wxTRANSPARENT_BRUSH, \  
      wxBLACK, wxSOLID, wxCROSS_HATCH, wxSWISS, wxNORMAL  
   
 from wxproj import draw_polygon_shape  
13    
14  from Thuban import _  from Thuban import _
 from Thuban.UI.common import *  
   
 from Thuban.Model.layer import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \  
      SHAPETYPE_POINT  
 from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \  
      ALIGN_LEFT, ALIGN_RIGHT, ALIGN_BASELINE  
15    
16  from Thuban.Model.classification import Classification  from wxPython.wx import wxPoint, wxRect, wxPen, wxBrush, wxFont, \
17  from Thuban.Model.color import Color      wxTRANSPARENT_PEN, wxTRANSPARENT_BRUSH, \
18        wxBLACK_PEN, wxBLACK, wxSOLID, wxCROSS_HATCH, wxSWISS, wxNORMAL, \
19        wxBitmapFromImage, wxImageFromStream, wxBITMAP_TYPE_BMP
20    
21    from wxproj import draw_polygon_shape, draw_polygon_init
22    
23  class MapRenderer:  from Thuban.UI.common import Color2wxColour
24    from Thuban.UI.classifier import ClassDataPreviewer
25      """Class to render a map onto a wxDC"""  from Thuban.UI.scalebar import ScaleBar
26    
27      honor_visibility = 1  from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT
28    
29      def __init__(self, dc, scale, offset, resolution = 72.0,  from Thuban.Model.color import Transparent
30                   honor_visibility = None):  import Thuban.Model.resource
         """Inititalize the renderer.  
   
         dc -- the wxPython DC to render on  
         scale, offset -- the scale factor and translation to convert  
                 between projected coordinates and the DC coordinates  
   
         resolution -- the assumed resolution of the DC. Used to convert  
                 absolute lengths like font sizes to DC coordinates  
   
         honor_visibility -- boolean. If true, honor the visibility flag  
                 of the layers, otherwise draw all layers. If None, use  
                 the renderer's default.  
         """  
         # resolution in pixel/inch  
31    
32          assert(scale > 0)  from baserenderer import BaseRenderer
33    
34          self.dc = dc  class MapRenderer(BaseRenderer):
         self.scale = scale  
         self.offset = offset  
         if honor_visibility is not None:  
             self.honor_visibility = honor_visibility  
         # store the resolution in pixel/point because it's more useful  
         # later.  
         self.resolution = resolution / 72.0  
   
     def render_map(self, map):  
         self.map = map  
         for layer in map.Layers():  
             # if honor_visibility is true, only draw visible layers,  
             # otherwise draw all layers  
             if not self.honor_visibility or layer.Visible():  
                 self.draw_shape_layer(layer)  
         self.draw_label_layer(map.LabelLayer())  
35    
36      def draw_shape_layer(self, layer):      """Class to render a map onto a wxDC"""
         scale = self.scale  
         offx, offy = self.offset  
   
         map_proj = self.map.projection  
         layer_proj = layer.projection  
   
         shapetype = layer.ShapeType()  
37    
38          brush = wxTRANSPARENT_BRUSH      TRANSPARENT_PEN = wxTRANSPARENT_PEN
39          pen   = wxTRANSPARENT_PEN      TRANSPARENT_BRUSH = wxTRANSPARENT_BRUSH
40    
41          old_prop = None      make_point = wxPoint
         lc = layer.GetClassification()  
         field = lc.GetField()  
   
         defaultProps = lc.GetDefaultGroup().GetProperties()  
   
         for i in self.layer_ids(layer):  
             value = None  
   
             if field is not None:  
                 try:  
                     record = layer.table.read_record(i)  
                     if record is not None:  
                         value = record[field]  
                 except:  
                     pass  
   
                 #  
                 # if the above statements fail 'value' should  
                 # be null, at which point this call will  
                 # at least retreive the NullData  
                 #  
                 prop = lc.GetProperties(value)  
             else:  
                 prop = defaultProps  
   
             # don't recreate new objects if they are the same as before  
             if prop != old_prop:  
                 old_prop = prop  
   
                 if shapetype == SHAPETYPE_ARC:  
                     fill = Color.None  
                 else:  
                     fill = prop.GetFill()  
       
                 if fill is Color.None:  
                     brush = wxTRANSPARENT_BRUSH  
                 else:  
                     color = Color2wxColour(fill)  
                     brush = wxBrush(color, wxSOLID)  
       
                 stroke = prop.GetLineColor()  
                 stroke_width = prop.GetLineWidth()  
                 if stroke is Color.None:  
                     pen = wxTRANSPARENT_PEN  
                 else:  
                     color = Color2wxColour(stroke)  
                     pen = wxPen(color, stroke_width, wxSOLID)  
       
             if shapetype == SHAPETYPE_POINT:  
                 self.dc.SetBrush(brush)  
                 self.dc.SetPen(pen)  
                 self.draw_point_shape(layer, i)  
             else:  
                 self.draw_polygon_shape(layer, i, pen, brush)  
42    
43      def layer_ids(self, layer):      def tools_for_property(self, prop):
44          """Return the shape ids of the given layer that have to be drawn.          fill = prop.GetFill()
45                    if fill is Transparent:
46          The default implementation simply returns all ids in the layer.              brush = self.TRANSPARENT_BRUSH
         Override in derived classes to be more precise.  
         """  
         return range(layer.NumShapes())  
   
     def draw_polygon_shape(self, layer, index, pen, brush):  
         offx, offy = self.offset          
         draw_polygon_shape(layer.shapefile.cobject(), index,  
                            self.dc, pen, brush,  
                            self.map.projection, layer.projection,  
                            self.scale, -self.scale, offx, offy)  
   
     def projected_points(self, layer, index):  
         proj = self.map.projection  
         if proj is not None:  
             forward = proj.Forward  
         else:  
             forward = None  
         proj = layer.projection  
         if proj is not None:  
             inverse = proj.Inverse  
47          else:          else:
48              inverse = None              brush = wxBrush(Color2wxColour(fill), wxSOLID)
         shape = layer.Shape(index)  
         points = []  
         scale = self.scale  
         offx, offy = self.offset  
         for x, y in shape.Points():  
             if inverse:  
                 x, y = inverse(x, y)  
             if forward:  
                 x, y = forward(x, y)  
             points.append(wxPoint(x * scale + offx,  
                                   -y * scale + offy))  
         return points  
   
     def draw_arc_shape(self, layer, index):  
         points = self.projected_points(layer, index)  
         self.dc.DrawLines(points)  
   
     def draw_point_shape(self, layer, index):  
         p = self.projected_points(layer, index)[0]  
         radius = self.resolution * 5  
         self.dc.DrawEllipse(p.x - radius, p.y - radius, 2*radius, 2*radius)  
49    
50      def draw_label_layer(self, layer):          stroke = prop.GetLineColor()
51          scale = self.scale          if stroke is Transparent:
52          offx, offy = self.offset              pen = self.TRANSPARENT_PEN
53            else:
54                pen = wxPen(Color2wxColour(stroke), prop.GetLineWidth(), wxSOLID)
55            return pen, brush
56    
57          font = wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)      def low_level_renderer(self, layer):
58          self.dc.SetFont(font)          """Override inherited method to provide more efficient renderers
59    
60          map_proj = self.map.projection          For point shapes, return self.draw_point_shape and layer just as
61          if map_proj is not None:          the base class method. For arc and polygon use the more
62              forward = map_proj.Forward          efficient wxproj.draw_polygon_shape and its corresponding
63            parameter created with wxproj.draw_polygon_init.
64            """
65            shapetype = layer.ShapeType()
66            if shapetype == SHAPETYPE_POINT:
67                func = self.draw_point_shape
68                param = layer
69          else:          else:
70              forward = None              offx, offy = self.offset
71                param = draw_polygon_init(layer.ShapeStore().Shapefile(), self.dc,
72          for label in layer.Labels():                                        self.map.projection,
73              x = label.x                                        layer.projection,
74              y = label.y                                        self.scale, -self.scale,
75              text = label.text                                        offx, offy)
76              if forward:              func = draw_polygon_shape
77                  x, y = forward(x, y)          return func, param
78              x = x * scale + offx  
79              y = -y * scale + offy      def label_font(self):
80              width, height = self.dc.GetTextExtent(text)          return wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)
81              if label.halign == ALIGN_LEFT:  
82                  # nothing to be done      def draw_raster_data(self, data):
83                  pass          stream = cStringIO.StringIO(data)
84              elif label.halign == ALIGN_RIGHT:          image = wxImageFromStream(stream, wxBITMAP_TYPE_BMP)
85                  x = x - width          bitmap = wxBitmapFromImage(image)
86              elif label.halign == ALIGN_CENTER:          self.dc.DrawBitmap(bitmap, 0, 0)
                 x = x - width/2  
             if label.valign == ALIGN_TOP:  
                 # nothing to be done  
                 pass  
             elif label.valign == ALIGN_BOTTOM:  
                 y = y - height  
             elif label.valign == ALIGN_CENTER:  
                 y = y - height/2  
             self.dc.DrawText(text, x, y)  
87    
88    
89  class ScreenRenderer(MapRenderer):  class ScreenRenderer(MapRenderer):
90    
91      # On the screen we want to see only visible layers by default      # On the screen we want to see only visible layers by default
92      honor_visibility = 1      honor_visibility = 1
93        
94      def RenderMap(self, map, region, selected_layer, selected_shapes):      def RenderMap(self, map, region, selected_layer, selected_shapes):
95          """Render the map.          """Render the map.
96    
# Line 249  class ScreenRenderer(MapRenderer): Line 111  class ScreenRenderer(MapRenderer):
111              brush = wxBrush(wxBLACK, wxCROSS_HATCH)              brush = wxBrush(wxBLACK, wxCROSS_HATCH)
112    
113              shapetype = layer.ShapeType()              shapetype = layer.ShapeType()
114              if shapetype == SHAPETYPE_POLYGON:              func, param = self.low_level_renderer(layer)
115                  func = self.draw_polygon_shape              args = (pen, brush)
                 args = (pen, brush)  
             elif shapetype == SHAPETYPE_ARC:  
                 func = self.draw_polygon_shape  
                 args = (pen, None)  
             elif shapetype == SHAPETYPE_POINT:  
                 self.dc.SetBrush(brush)  
                 self.dc.SetPen(pen)  
                 func = self.draw_point_shape  
                 args = ()  
             else:  
                 raise TypeError(_("Unhandled shape type %s") % shapetype)  
   
116              for index in self.selected_shapes:              for index in self.selected_shapes:
117                  func(layer, index, *args)                  func(param, index, *args)
118    
119      def layer_ids(self, layer):      def layer_ids(self, layer):
120          """Return the shapeids covered by the region that has to be redrawn          """Return the shapeids covered by the region that has to be redrawn
# Line 304  class ScreenRenderer(MapRenderer): Line 154  class ScreenRenderer(MapRenderer):
154          return layer.ShapesInRegion((left, bottom, right, top))          return layer.ShapesInRegion((left, bottom, right, top))
155    
156    
157  class PrinterRender(MapRenderer):  class ExportRenderer(ScreenRenderer):
158    
159      # When printing we want to see all layers      honor_visibility = 1
160      honor_visibility = 0  
161        def RenderMap(self, map, region, mapregion,
162                      selected_layer, selected_shapes ):
163            """Render the map.
164    
165            The rendering device has been specified during initialisation.
166            The device border distance was set in Thuban.UI.view.OutputTranform().
167    
168            RenderMap renders a frame set (one page frame, one around
169            legend/scalebar and one around the map), the map, the legend and the
170            scalebar on the given DC. The map is rendered with the region displayed
171            in the canvas view, centered on the area available for map display.
172            """
173    
174            self.update_region = region
175            self.selected_layer = selected_layer
176            self.selected_shapes = selected_shapes
177    
178            # Get some dimensions
179            llx, lly, urx, ury = region
180            self.mapregion = mapregion
181            mminx, mminy, mmaxx, mmaxy = self.mapregion
182    
183            # Manipulate the offset to position the map
184            offx, offy = self.offset
185            # 1. Shift to corner of map drawing area
186            offx = offx + mminx
187            offy = offy + mminy
188    
189            # 2. Center the map on the map drawing area:
190            # region identifies the region on the canvas view:
191            # center of map drawing area - half the size of region: rendering origin
192            self.shiftx = (mmaxx - mminx)*0.5 - (urx - llx)*0.5
193            self.shifty = (mmaxy - mminy)*0.5 - (ury - lly)*0.5
194    
195            self.offset = (offx+self.shiftx, offy+self.shifty)
196    
197            # Draw the map
198            self.dc.BeginDrawing()
199            self.dc.DestroyClippingRegion()
200            self.dc.SetClippingRegion(mminx+self.shiftx, mminy+self.shifty,
201                                      urx, ury)
202            self.render_map(map)
203            self.dc.EndDrawing()
204    
205            # Draw the rest (frames, legend, scalebar)
206            self.dc.BeginDrawing()
207            self.dc.DestroyClippingRegion()
208    
209            # Force the font for Legend drawing
210            font = wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)
211            self.dc.SetFont(font)
212    
213            self.render_frame(region)
214            self.render_legend(map)
215            self.render_scalebar(map)
216            self.dc.EndDrawing()
217    
218        def render_frame(self, region):
219            """Render the frames for map and legend/scalebar."""
220    
221            dc = self.dc
222            dc.SetPen(wxBLACK_PEN)
223            dc.SetBrush(wxTRANSPARENT_BRUSH)
224    
225            # Dimension stuff
226            width, height = dc.GetSizeTuple()
227            mminx, mminy, mmaxx, mmaxy = self.mapregion
228    
229            # Page Frame
230            dc.DrawRectangle(15,15,width-30, (mmaxy-mminy)+10)
231    
232            # Map Frame
233            llx, lly, urx, ury = region
234            dc.DrawRectangle(mminx + self.shiftx, mminy + self.shifty, urx, ury)
235    
236            # Legend Frame
237            dc.DrawRectangle(mmaxx+10,mminy,(width-20) - (mmaxx+10), mmaxy-mminy)
238    
239            dc.DestroyClippingRegion()
240            dc.SetClippingRegion(mmaxx+10,mminy,
241                                 (width-20) - (mmaxx+10), mmaxy-mminy)
242    
243        def render_legend(self, map):
244            """Render the legend on the Map."""
245    
246            previewer = ClassDataPreviewer()
247            dc = self.dc
248            dc.SetPen(wxBLACK_PEN)
249            dc.SetBrush(wxTRANSPARENT_BRUSH)
250    
251            # Dimension stuff
252            width, height = dc.GetSizeTuple()
253            mminx, mminy, mmaxx, mmaxy = self.mapregion
254            textwidth, textheight = dc.GetTextExtent("0")
255            iconwidth  = textheight
256            iconheight = textheight
257            stepy = textheight+3
258            dx = 10
259            posx = mmaxx + 10 + 5   # 10 pix distance mapframe/legend frame,
260                                    # 5 pix inside legend frame
261            posy = mminy + 5        # 5 pix inside legend frame
262    
263            # Render the legend
264            dc.SetTextForeground(wxBLACK)
265            if map.HasLayers():
266                layers = map.Layers()
267                layers.reverse()
268                for l in layers:
269                    if l.Visible():
270                        # Render title
271                        dc.DrawText(l.Title(), posx, posy)
272                        posy+=stepy
273                        if l.HasClassification():
274                            # Render classification
275                            clazz = l.GetClassification()
276                            shapeType = l.ShapeType()
277                            for g in clazz:
278                                if g.IsVisible():
279                                    previewer.Draw(dc,
280                                        wxRect(posx+dx, posy,
281                                               iconwidth, iconheight),
282                                        g.GetProperties(), shapeType)
283                                    dc.DrawText(g.GetDisplayText(),
284                                                posx+2*dx+iconwidth, posy)
285                                    posy+=stepy
286    
287        def render_scalebar(self, map):
288            """Render the scalebar."""
289    
290            scalebar = ScaleBar(map)
291    
292            # Dimension stuff
293            width, height = self.dc.GetSizeTuple()
294            mminx, mminy, mmaxx, mmaxy = self.mapregion
295    
296            # Render the scalebar
297            scalebar.DrawScaleBar(self.scale, self.dc,
298                                 (mmaxx+10+5, mmaxy-25),
299                                 ((width-15-5) - (mmaxx+10+5),20)
300                                )
301            # 10 pix between map and legend frame, 5 pix inside legend frame
302            # 25 pix from the legend frame bottom line
303            # Width: 15 pix from DC border, 5 pix inside frame, 10, 5 as above
304            # Height: 20
305    
306    class PrinterRenderer(ExportRenderer):
307    
308        # Printing as well as Export / Screen display only the visible layer.
309        honor_visibility = 1
310    
     RenderMap = MapRenderer.render_map  
       

Legend:
Removed from v.574  
changed lines
  Added in v.1552

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26