/[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 432 by jonathan, Mon Feb 24 18:47:36 2003 UTC revision 909 by frank, Fri May 16 16:23:12 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    
 from wxPython.wx import wxPoint, wxColour, wxPen, wxBrush, wxFont, \  
      wxTRANSPARENT_PEN, wxTRANSPARENT_BRUSH, \  
      wxBLACK, wxSOLID, wxCROSS_HATCH, wxSWISS, wxNORMAL  
   
 from wxproj import draw_polygon_shape  
   
12  from Thuban import _  from Thuban import _
13    
14    from wxPython.wx import wxMemoryDC, wxEmptyBitmap, \
15        wxPoint, wxRect, wxPen, wxBrush, wxFont, \
16        wxTRANSPARENT_PEN, wxTRANSPARENT_BRUSH, \
17        wxBLACK_PEN, wxRED_PEN, wxBLACK, wxSOLID, wxCROSS_HATCH, wxSWISS, wxNORMAL
18    
19    from wxproj import draw_polygon_shape, draw_polygon_init
20    
21    from Thuban.UI.common import Color2wxColour
22    from Thuban.UI.classifier import ClassDataPreviewer
23    from Thuban.UI.scalebar import ScaleBar
24    
25  from Thuban.Model.layer import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \  from Thuban.Model.layer import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \
26       SHAPETYPE_POINT       SHAPETYPE_POINT
27  from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \  from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \
# Line 24  from Thuban.Model.label import ALIGN_CEN Line 30  from Thuban.Model.label import ALIGN_CEN
30  from Thuban.Model.classification import Classification  from Thuban.Model.classification import Classification
31  from Thuban.Model.color import Color  from Thuban.Model.color import Color
32    
   
33  class MapRenderer:  class MapRenderer:
34    
35      """Class to render a map onto a wxDC"""      """Class to render a map onto a wxDC"""
# Line 47  class MapRenderer: Line 52  class MapRenderer:
52                  the renderer's default.                  the renderer's default.
53          """          """
54          # resolution in pixel/inch          # resolution in pixel/inch
55    
56          self.dc = dc          self.dc = dc
57          self.scale = scale          self.scale = scale
58          self.offset = offset          self.offset = offset
# Line 78  class MapRenderer: Line 84  class MapRenderer:
84          pen   = wxTRANSPARENT_PEN          pen   = wxTRANSPARENT_PEN
85    
86          old_prop = None          old_prop = None
87            old_group = None
88            lc = layer.GetClassification()
89            field = lc.GetField()
90            defaultGroup = lc.GetDefaultGroup()
91    
92    
93            if shapetype != SHAPETYPE_POINT:
94                polygon_render_param = self.polygon_render_param(layer)
95    
96            if shapetype == SHAPETYPE_POINT:
97                draw_func = lambda i: \
98                       self.draw_point_shape(layer, i)
99            else:
100                draw_func = lambda i: \
101                       self.draw_polygon_shape(polygon_render_param, i, pen, brush)
102                
103          for i in self.layer_ids(layer):          for i in self.layer_ids(layer):
104              value = None  
105              lc = layer.GetClassification()              if field is None:
106              field = lc.field                  group = defaultGroup
   
             if field is not None:  
                 record = layer.table.read_record(i)  
                 if record is not None:  
                     value = record[field]  
   
             #  
             # if the above statements fail 'value' should  
             # be null, at which point this call will  
             # at least retreive the NullData  
             #  
             prop = lc.GetClassData(value)  
   
             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 = wxColour(fill.red * 255,  
                                      fill.green * 255,  
                                      fill.blue * 255)  
                     brush = wxBrush(color, wxSOLID)  
       
                 stroke = prop.GetStroke()  
                 stroke_width = prop.GetStrokeWidth()  
                 if stroke is Color.None:  
                     pen = wxTRANSPARENT_PEN  
                 else:  
                     color = wxColour(stroke.red * 255,  
                                      stroke.green * 255,  
                                      stroke.blue * 255)  
                     pen = wxPen(color, stroke_width, wxSOLID)  
       
             if shapetype == SHAPETYPE_POINT:  
                 self.dc.SetBrush(brush)  
                 self.dc.SetPen(pen)  
                 self.draw_point_shape(layer, i)  
107              else:              else:
108                  self.draw_polygon_shape(layer, i, pen, brush)                  record = layer.table.ReadRowAsDict(i)
109                    assert record is not None
110                    group = lc.FindGroup(record[field])
111    
112    
113                if not group.IsVisible():
114                    continue
115    
116    
117                # don't recreate new objects if they are the same as before
118                if group is not old_group:
119                    old_group = group
120    
121                    prop = group.GetProperties()
122    
123                    if prop != old_prop:
124                        old_prop = prop
125    
126                        if shapetype == SHAPETYPE_ARC:
127                            fill = Color.Transparent
128                        else:
129                            fill = prop.GetFill()
130    
131    
132                        if fill is Color.Transparent:
133                            brush = wxTRANSPARENT_BRUSH
134                        else:
135                            color = Color2wxColour(fill)
136                            brush = wxBrush(color, wxSOLID)
137    
138                        stroke = prop.GetLineColor()
139                        stroke_width = prop.GetLineWidth()
140                        if stroke is Color.Transparent:
141                            pen = wxTRANSPARENT_PEN
142                        else:
143                            color = Color2wxColour(stroke)
144                            pen = wxPen(color, stroke_width, wxSOLID)
145    
146                        if shapetype == SHAPETYPE_POINT:
147                            self.dc.SetBrush(brush)
148                            self.dc.SetPen(pen)
149    
150                draw_func(i)
151    
152      def layer_ids(self, layer):      def layer_ids(self, layer):
153          """Return the shape ids of the given layer that have to be drawn.          """Return the shape ids of the given layer that have to be drawn.
154            
155          The default implementation simply returns all ids in the layer.          The default implementation simply returns all ids in the layer.
156          Override in derived classes to be more precise.          Override in derived classes to be more precise.
157          """          """
158          return range(layer.NumShapes())          return range(layer.NumShapes())
159    
160      def draw_polygon_shape(self, layer, index, pen, brush):      def polygon_render_param(self, layer):
161          offx, offy = self.offset                  """Return the low-lever render parameter for the layer"""
162          draw_polygon_shape(layer.shapefile.cobject(), index,          offx, offy = self.offset
163                             self.dc, pen, brush,          return draw_polygon_init(layer.shapefile, self.dc,
164                             self.map.projection, layer.projection,                                   self.map.projection,
165                             self.scale, -self.scale, offx, offy)                                   layer.projection,
166                                     self.scale, -self.scale,
167                                     offx, offy)
168    
169        def draw_polygon_shape(self, draw_polygon_info, index, pen, brush):
170            draw_polygon_shape(draw_polygon_info, index, pen, brush)
171    
172      def projected_points(self, layer, index):      def projected_points(self, layer, index):
173          proj = self.map.projection          proj = self.map.GetProjection()
174          if proj is not None:          if proj is not None:
175              forward = proj.Forward              forward = proj.Forward
176          else:          else:
177              forward = None              forward = None
178          proj = layer.projection          proj = layer.GetProjection()
179          if proj is not None:          if proj is not None:
180              inverse = proj.Inverse              inverse = proj.Inverse
181          else:          else:
# Line 172  class MapRenderer: Line 198  class MapRenderer:
198          self.dc.DrawLines(points)          self.dc.DrawLines(points)
199    
200      def draw_point_shape(self, layer, index):      def draw_point_shape(self, layer, index):
201          p = self.projected_points(layer, index)[0]          pp = self.projected_points(layer, index)
202    
203            if len(pp) == 0: return # ignore Null Shapes which have no points
204    
205            p = pp[0]
206          radius = self.resolution * 5          radius = self.resolution * 5
207          self.dc.DrawEllipse(p.x - radius, p.y - radius, 2*radius, 2*radius)          self.dc.DrawEllipse(p.x - radius, p.y - radius, 2*radius, 2*radius)
208    
# Line 220  class ScreenRenderer(MapRenderer): Line 250  class ScreenRenderer(MapRenderer):
250      # On the screen we want to see only visible layers by default      # On the screen we want to see only visible layers by default
251      honor_visibility = 1      honor_visibility = 1
252            
253      def RenderMap(self, map, region, selected_layer, selected_shape):      def RenderMap(self, map, region, selected_layer, selected_shapes):
254          """Render the map.          """Render the map.
255    
256          Only the given region (a tuple in window coordinates as returned          Only the given region (a tuple in window coordinates as returned
257          by a wxrect's asTuple method) needs to be redrawn. Highlight the          by a wxrect's asTuple method) needs to be redrawn. Highlight the
258          shape with id selected_shape in the selected_layer.          shapes given by the ids in selected_shapes in the
259            selected_layer.
260          """          """
261          self.update_region = region          self.update_region = region
262          self.selected_layer = selected_layer          self.selected_layer = selected_layer
263          self.selected_shape = selected_shape          self.selected_shapes = selected_shapes
264          self.render_map(map)          self.render_map(map)
265    
266      def draw_shape_layer(self, layer):      def draw_shape_layer(self, layer):
267          MapRenderer.draw_shape_layer(self, layer)          MapRenderer.draw_shape_layer(self, layer)
268          if layer is self.selected_layer and self.selected_shape is not None:          if layer is self.selected_layer and self.selected_shapes:
269              pen = wxPen(wxBLACK, 3, wxSOLID)              pen = wxPen(wxBLACK, 3, wxSOLID)
270              brush = wxBrush(wxBLACK, wxCROSS_HATCH)              brush = wxBrush(wxBLACK, wxCROSS_HATCH)
271                
272              shapetype = layer.ShapeType()              shapetype = layer.ShapeType()
             index = self.selected_shape  
273              if shapetype == SHAPETYPE_POLYGON:              if shapetype == SHAPETYPE_POLYGON:
274                  self.draw_polygon_shape(layer, index, pen, brush)                  offx, offy = self.offset
275                    renderparam = self.polygon_render_param(layer)
276                    func = self.draw_polygon_shape
277                    args = (pen, brush)
278              elif shapetype == SHAPETYPE_ARC:              elif shapetype == SHAPETYPE_ARC:
279                  self.draw_polygon_shape(layer, index, pen, None)                  renderparam = self.polygon_render_param(layer)
280              else:                  func = self.draw_polygon_shape
281                    args = (pen, None)
282                elif shapetype == SHAPETYPE_POINT:
283                    renderparam = layer
284                  self.dc.SetBrush(brush)                  self.dc.SetBrush(brush)
285                  self.dc.SetPen(pen)                  self.dc.SetPen(pen)
286                  if shapetype == SHAPETYPE_POINT:                  func = self.draw_point_shape
287                      self.draw_point_shape(layer, index)                  args = ()
288                  else:              else:
289                      raise TypeError(_("Unhandled shape type %s") % shapetype)                  raise TypeError(_("Unhandled shape type %s") % shapetype)
290    
291                for index in self.selected_shapes:
292                    func(renderparam, index, *args)
293    
294    
295      def layer_ids(self, layer):      def layer_ids(self, layer):
296          """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 290  class ScreenRenderer(MapRenderer): Line 330  class ScreenRenderer(MapRenderer):
330          return layer.ShapesInRegion((left, bottom, right, top))          return layer.ShapesInRegion((left, bottom, right, top))
331    
332    
333  class PrinterRender(MapRenderer):  class ExportRenderer(ScreenRenderer):
334    
335      # When printing we want to see all layers      honor_visibility = 1
     honor_visibility = 0  
   
     RenderMap = MapRenderer.render_map  
336            
337        def RenderMap(self, map, region, mapregion,
338                      selected_layer, selected_shapes ):
339            """Render the map.
340    
341            The rendering device has been specified during initialisation.
342            The device border distance was set in Thuban.UI.view.OutputTranform().
343            
344            RenderMap renders a frame set (one page frame, one around
345            legend/scalebar and one around the map), the map, the legend and the
346            scalebar on the given DC. The map is rendered with the region displayed
347            in the canvas view, centered on the area available for map display.
348            """
349            
350            self.update_region = region
351            self.selected_layer = selected_layer
352            self.selected_shapes = selected_shapes
353    
354            # Get some dimensions
355            llx, lly, urx, ury = region
356            self.mapregion = mapregion
357            mminx, mminy, mmaxx, mmaxy = self.mapregion
358    
359            # Manipulate the offset to position the map
360            offx, offy = self.offset
361            # 1. Shift to corner of map drawing area
362            offx = offx + mminx
363            offy = offy + mminy
364    
365            # 2. Center the map on the map drawing area:
366            # region identifies the region on the canvas view:
367            # center of map drawing area - half the size of region: rendering origin
368            self.shiftx = (mmaxx - mminx)*0.5 - (urx - llx)*0.5
369            self.shifty = (mmaxy - mminy)*0.5 - (ury - lly)*0.5
370    
371            self.offset = (offx+self.shiftx, offy+self.shifty)
372    
373            # Draw the map
374            self.dc.BeginDrawing()
375            self.dc.DestroyClippingRegion()
376            self.dc.SetClippingRegion(mminx+self.shiftx, mminy+self.shifty,
377                                      urx, ury)
378            self.render_map(map)
379            self.dc.EndDrawing()
380    
381            # Draw the rest (frames, legend, scalebar)
382            self.dc.BeginDrawing()
383            self.dc.DestroyClippingRegion()
384    
385            # Force the font for Legend drawing
386            font = wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)
387            self.dc.SetFont(font)
388    
389            self.render_frame(region)
390            self.render_legend(map)
391            self.render_scalebar(map)
392            self.dc.EndDrawing()
393    
394        def render_frame(self, region):
395            """Render the frames for map and legend/scalebar."""
396    
397            dc = self.dc
398            dc.SetPen(wxBLACK_PEN)
399            dc.SetBrush(wxTRANSPARENT_BRUSH)
400    
401            # Dimension stuff
402            width, height = dc.GetSizeTuple()
403            mminx, mminy, mmaxx, mmaxy = self.mapregion
404    
405            # Page Frame
406            dc.DrawRectangle(15,15,width-30, (mmaxy-mminy)+10)
407            
408            # Map Frame
409            llx, lly, urx, ury = region
410            dc.DrawRectangle(mminx + self.shiftx, mminy + self.shifty, urx, ury)
411            
412            # Legend Frame
413            dc.DrawRectangle(mmaxx+10,mminy,(width-20) - (mmaxx+10), mmaxy-mminy)
414    
415            dc.DestroyClippingRegion()
416            dc.SetClippingRegion(mmaxx+10,mminy,
417                                 (width-20) - (mmaxx+10), mmaxy-mminy)
418    
419        def render_legend(self, map):
420            """Render the legend on the Map."""
421    
422            previewer = ClassDataPreviewer()
423            dc = self.dc
424            dc.SetPen(wxBLACK_PEN)
425            dc.SetBrush(wxTRANSPARENT_BRUSH)
426    
427            # Dimension stuff
428            width, height = dc.GetSizeTuple()
429            mminx, mminy, mmaxx, mmaxy = self.mapregion
430            textwidth, textheight = dc.GetTextExtent("0")
431            iconwidth  = textheight
432            iconheight = textheight
433            stepy = textheight+3
434            dx = 10
435            posx = mmaxx + 10 + 5   # 10 pix distance mapframe/legend frame,
436                                    # 5 pix inside legend frame
437            posy = mminy + 5        # 5 pix inside legend frame
438            
439            # Render the legend
440            dc.SetTextForeground(wxBLACK)
441            if map.HasLayers():
442                for l in map.Layers():
443                    if l.Visible():
444                        # Render title
445                        dc.DrawText(l.Title(), posx, posy)
446                        posy+=stepy
447                        # Render classification
448                        clazz = l.GetClassification()
449                        shapeType = l.ShapeType()
450                        for g in clazz:
451                            if g.IsVisible():
452                                previewer.Draw(dc,
453                                    wxRect(posx+dx, posy, iconwidth, iconheight),
454                                    g.GetProperties(), shapeType)
455                                dc.DrawText(g.GetDisplayText(),
456                                            posx+2*dx+iconwidth, posy)
457                                posy+=stepy
458            
459        def render_scalebar(self, map):
460            """Render the scalebar."""
461    
462            scalebar = ScaleBar(map)
463    
464            # Dimension stuff
465            width, height = self.dc.GetSizeTuple()
466            mminx, mminy, mmaxx, mmaxy = self.mapregion
467          
468            # Render the scalebar
469            scalebar.DrawScaleBar(self.scale, self.dc,
470                                 (mmaxx+10+5, mmaxy-25),
471                                 ((width-15-5) - (mmaxx+10+5),20)
472                                )
473            # 10 pix between map and legend frame, 5 pix inside legend frame
474            # 25 pix from the legend frame bottom line
475            # Width: 15 pix from DC border, 5 pix inside frame, 10, 5 as above
476            # Height: 20
477    
478    class PrinterRenderer(ExportRenderer):
479    
480        # Printing as well as Export / Screen display only the visible layer.
481        honor_visibility = 1
482    

Legend:
Removed from v.432  
changed lines
  Added in v.909

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26