/[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 605 by jonathan, Fri Apr 4 12:16:13 2003 UTC revision 1165 by jonathan, Thu Jun 12 12:42:10 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 *  
15    
16  from Thuban.Model.layer import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \  from wxPython.wx import wxMemoryDC, wxEmptyBitmap, \
17       SHAPETYPE_POINT      wxPoint, wxRect, wxPen, wxBrush, wxFont, \
18        wxTRANSPARENT_PEN, wxTRANSPARENT_BRUSH, \
19        wxBLACK_PEN, wxRED_PEN, wxBLACK, \
20        wxSOLID, wxCROSS_HATCH, wxSWISS, wxNORMAL, \
21        wxBitmap, wxImageFromBitmap, wxBitmapFromImage, \
22        wxImageFromStream, wxBITMAP_TYPE_BMP
23    
24    from wxproj import draw_polygon_shape, draw_polygon_init
25    from gdalwarp import ProjectRasterFile
26    
27    from Thuban.UI.common import Color2wxColour
28    from Thuban.UI.classifier import ClassDataPreviewer
29    from Thuban.UI.scalebar import ScaleBar
30    
31    from Thuban.Model.layer import Layer, RasterLayer, \
32         SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT
33  from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \  from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \
34       ALIGN_LEFT, ALIGN_RIGHT, ALIGN_BASELINE       ALIGN_LEFT, ALIGN_RIGHT, ALIGN_BASELINE
35    
36  from Thuban.Model.classification import Classification  from Thuban.Model.classification import Classification
37  from Thuban.Model.color import Color  from Thuban.Model.color import Color
38    import Thuban.Model.resource
39    
40  class MapRenderer:  class MapRenderer:
41    
# Line 49  class MapRenderer: Line 60  class MapRenderer:
60          """          """
61          # resolution in pixel/inch          # resolution in pixel/inch
62    
         assert scale > 0  
   
63          self.dc = dc          self.dc = dc
64          self.scale = scale          self.scale = scale
65          self.offset = offset          self.offset = offset
# Line 62  class MapRenderer: Line 71  class MapRenderer:
71    
72      def render_map(self, map):      def render_map(self, map):
73          self.map = map          self.map = map
74            seenRaster = True
75    
76            if self.scale == 0:
77                return
78    
79            #
80            # This is only a good optimization if there is only one
81            # raster layer and the image covers the entire window (as
82            # it currently does). We note if there is a raster layer
83            # and only begin drawing layers once we have drawn it.
84            # That way we avoid drawing layers that won't be seen.
85            #
86            for layer in map.Layers():
87                if isinstance(layer, RasterLayer) and layer.Visible():
88                    seenRaster = False
89                    break
90    
91          for layer in map.Layers():          for layer in map.Layers():
92              # if honor_visibility is true, only draw visible layers,              # if honor_visibility is true, only draw visible layers,
93              # otherwise draw all layers              # otherwise draw all layers
94              if not self.honor_visibility or layer.Visible():              if not self.honor_visibility or layer.Visible():
95                  self.draw_shape_layer(layer)                  if isinstance(layer, Layer) and seenRaster:
96                        self.draw_shape_layer(layer)
97                    elif isinstance(layer, RasterLayer) \
98                        and Thuban.Model.resource.has_gdal_support():
99                        self.draw_raster_layer(layer)
100                        seenRaster = True
101    
102          self.draw_label_layer(map.LabelLayer())          self.draw_label_layer(map.LabelLayer())
103    
104      def draw_shape_layer(self, layer):      def draw_shape_layer(self, layer):
# Line 82  class MapRenderer: Line 114  class MapRenderer:
114          pen   = wxTRANSPARENT_PEN          pen   = wxTRANSPARENT_PEN
115    
116          old_prop = None          old_prop = None
117            old_group = None
118          lc = layer.GetClassification()          lc = layer.GetClassification()
119          field = lc.GetField()          field = lc.GetField()
120            defaultGroup = lc.GetDefaultGroup()
121    
         defaultProps = lc.GetDefaultGroup().GetProperties()  
122    
123            if shapetype != SHAPETYPE_POINT:
124                polygon_render_param = self.polygon_render_param(layer)
125    
126            if shapetype == SHAPETYPE_POINT:
127                draw_func = lambda i: \
128                       self.draw_point_shape(layer, i)
129            else:
130                draw_func = lambda i: \
131                       self.draw_polygon_shape(polygon_render_param, i, pen, brush)
132                
133          for i in self.layer_ids(layer):          for i in self.layer_ids(layer):
             value = None  
134    
135              if field is not None:              if field is None:
136                  try:                  group = defaultGroup
                     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)  
137              else:              else:
138                  prop = defaultProps                  record = layer.table.ReadRowAsDict(i)
139                    assert record is not None
140                    group = lc.FindGroup(record[field])
141    
142    
143                if not group.IsVisible():
144                    continue
145    
146    
147              # don't recreate new objects if they are the same as before              # don't recreate new objects if they are the same as before
148              if prop != old_prop:              if group is not old_group:
149                  old_prop = prop                  old_group = group
150    
151                  if shapetype == SHAPETYPE_ARC:                  prop = group.GetProperties()
152                      fill = Color.None  
153                  else:                  if prop != old_prop:
154                      fill = prop.GetFill()                      old_prop = prop
155        
156                  if fill is Color.None:                      if shapetype == SHAPETYPE_ARC:
157                      brush = wxTRANSPARENT_BRUSH                          fill = Color.Transparent
158                  else:                      else:
159                      color = Color2wxColour(fill)                          fill = prop.GetFill()
160                      brush = wxBrush(color, wxSOLID)  
161        
162                  stroke = prop.GetLineColor()                      if fill is Color.Transparent:
163                  stroke_width = prop.GetLineWidth()                          brush = wxTRANSPARENT_BRUSH
164                  if stroke is Color.None:                      else:
165                      pen = wxTRANSPARENT_PEN                          color = Color2wxColour(fill)
166                  else:                          brush = wxBrush(color, wxSOLID)
167                      color = Color2wxColour(stroke)  
168                      pen = wxPen(color, stroke_width, wxSOLID)                      stroke = prop.GetLineColor()
169                            stroke_width = prop.GetLineWidth()
170              if shapetype == SHAPETYPE_POINT:                      if stroke is Color.Transparent:
171                  self.dc.SetBrush(brush)                          pen = wxTRANSPARENT_PEN
172                  self.dc.SetPen(pen)                      else:
173                  self.draw_point_shape(layer, i)                          color = Color2wxColour(stroke)
174              else:                          pen = wxPen(color, stroke_width, wxSOLID)
175                  self.draw_polygon_shape(layer, i, pen, brush)  
176                        if shapetype == SHAPETYPE_POINT:
177                            self.dc.SetBrush(brush)
178                            self.dc.SetPen(pen)
179    
180                draw_func(i)
181    
182        def draw_raster_layer(self, layer):
183            data = None
184            offx, offy = self.offset
185            width, height = self.dc.GetSizeTuple()
186    
187            inProj = ""
188            proj = layer.GetProjection()
189            if proj is not None:
190                for p in proj.GetAllParameters():
191                    inProj += "+" + p + " "
192    
193            outProj = ""
194            proj = self.map.GetProjection()
195            if proj is not None:
196                for p in proj.GetAllParameters():
197                    outProj += "+" + p + " "
198    
199            xmin = (0 - offx) / self.scale
200            ymin = (offy - height) / self.scale
201            xmax = (width - offx) / self.scale
202            ymax = (offy - 0) / self.scale
203    
204            try:
205                data = ProjectRasterFile(
206                    layer.GetImageFilename(),
207                    inProj,
208                    outProj,
209                    (xmin, ymin, xmax, ymax),
210                    "", (width, height))
211            except IOError, (strerr):
212                print strerr
213            except (AttributeError, ValueError):
214                pass
215            else:
216                if data is not None:
217                    stream = cStringIO.StringIO(data)
218                    image = wxImageFromStream(stream, wxBITMAP_TYPE_BMP)
219                    bitmap = wxBitmapFromImage(image)
220                    self.dc.BeginDrawing()
221                    self.dc.DrawBitmap(bitmap, 0, 0)
222                    self.dc.EndDrawing()
223    
224      def layer_ids(self, layer):      def layer_ids(self, layer):
225          """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.
226            
227          The default implementation simply returns all ids in the layer.          The default implementation simply returns all ids in the layer.
228          Override in derived classes to be more precise.          Override in derived classes to be more precise.
229          """          """
230          return range(layer.NumShapes())          return range(layer.NumShapes())
231    
232      def draw_polygon_shape(self, layer, index, pen, brush):      def polygon_render_param(self, layer):
233          offx, offy = self.offset                  """Return the low-lever render parameter for the layer"""
234          draw_polygon_shape(layer.shapefile.cobject(), index,          offx, offy = self.offset
235                             self.dc, pen, brush,          return draw_polygon_init(layer.shapefile, self.dc,
236                             self.map.projection, layer.projection,                                   self.map.projection,
237                             self.scale, -self.scale, offx, offy)                                   layer.projection,
238                                     self.scale, -self.scale,
239                                     offx, offy)
240    
241        def draw_polygon_shape(self, draw_polygon_info, index, pen, brush):
242            draw_polygon_shape(draw_polygon_info, index, pen, brush)
243    
244      def projected_points(self, layer, index):      def projected_points(self, layer, index):
245          proj = self.map.projection          proj = self.map.GetProjection()
246          if proj is not None:          if proj is not None:
247              forward = proj.Forward              forward = proj.Forward
248          else:          else:
249              forward = None              forward = None
250          proj = layer.projection          proj = layer.GetProjection()
251          if proj is not None:          if proj is not None:
252              inverse = proj.Inverse              inverse = proj.Inverse
253          else:          else:
# Line 254  class ScreenRenderer(MapRenderer): Line 343  class ScreenRenderer(MapRenderer):
343    
344              shapetype = layer.ShapeType()              shapetype = layer.ShapeType()
345              if shapetype == SHAPETYPE_POLYGON:              if shapetype == SHAPETYPE_POLYGON:
346                    offx, offy = self.offset
347                    renderparam = self.polygon_render_param(layer)
348                  func = self.draw_polygon_shape                  func = self.draw_polygon_shape
349                  args = (pen, brush)                  args = (pen, brush)
350              elif shapetype == SHAPETYPE_ARC:              elif shapetype == SHAPETYPE_ARC:
351                    renderparam = self.polygon_render_param(layer)
352                  func = self.draw_polygon_shape                  func = self.draw_polygon_shape
353                  args = (pen, None)                  args = (pen, None)
354              elif shapetype == SHAPETYPE_POINT:              elif shapetype == SHAPETYPE_POINT:
355                    renderparam = layer
356                  self.dc.SetBrush(brush)                  self.dc.SetBrush(brush)
357                  self.dc.SetPen(pen)                  self.dc.SetPen(pen)
358                  func = self.draw_point_shape                  func = self.draw_point_shape
# Line 268  class ScreenRenderer(MapRenderer): Line 361  class ScreenRenderer(MapRenderer):
361                  raise TypeError(_("Unhandled shape type %s") % shapetype)                  raise TypeError(_("Unhandled shape type %s") % shapetype)
362    
363              for index in self.selected_shapes:              for index in self.selected_shapes:
364                  func(layer, index, *args)                  func(renderparam, index, *args)
365    
366    
367      def layer_ids(self, layer):      def layer_ids(self, layer):
368          """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 308  class ScreenRenderer(MapRenderer): Line 402  class ScreenRenderer(MapRenderer):
402          return layer.ShapesInRegion((left, bottom, right, top))          return layer.ShapesInRegion((left, bottom, right, top))
403    
404    
405  class PrinterRender(MapRenderer):  class ExportRenderer(ScreenRenderer):
406    
407      # When printing we want to see all layers      honor_visibility = 1
     honor_visibility = 0  
   
     RenderMap = MapRenderer.render_map  
408            
409        def RenderMap(self, map, region, mapregion,
410                      selected_layer, selected_shapes ):
411            """Render the map.
412    
413            The rendering device has been specified during initialisation.
414            The device border distance was set in Thuban.UI.view.OutputTranform().
415            
416            RenderMap renders a frame set (one page frame, one around
417            legend/scalebar and one around the map), the map, the legend and the
418            scalebar on the given DC. The map is rendered with the region displayed
419            in the canvas view, centered on the area available for map display.
420            """
421            
422            self.update_region = region
423            self.selected_layer = selected_layer
424            self.selected_shapes = selected_shapes
425    
426            # Get some dimensions
427            llx, lly, urx, ury = region
428            self.mapregion = mapregion
429            mminx, mminy, mmaxx, mmaxy = self.mapregion
430    
431            # Manipulate the offset to position the map
432            offx, offy = self.offset
433            # 1. Shift to corner of map drawing area
434            offx = offx + mminx
435            offy = offy + mminy
436    
437            # 2. Center the map on the map drawing area:
438            # region identifies the region on the canvas view:
439            # center of map drawing area - half the size of region: rendering origin
440            self.shiftx = (mmaxx - mminx)*0.5 - (urx - llx)*0.5
441            self.shifty = (mmaxy - mminy)*0.5 - (ury - lly)*0.5
442    
443            self.offset = (offx+self.shiftx, offy+self.shifty)
444    
445            # Draw the map
446            self.dc.BeginDrawing()
447            self.dc.DestroyClippingRegion()
448            self.dc.SetClippingRegion(mminx+self.shiftx, mminy+self.shifty,
449                                      urx, ury)
450            self.render_map(map)
451            self.dc.EndDrawing()
452    
453            # Draw the rest (frames, legend, scalebar)
454            self.dc.BeginDrawing()
455            self.dc.DestroyClippingRegion()
456    
457            # Force the font for Legend drawing
458            font = wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)
459            self.dc.SetFont(font)
460    
461            self.render_frame(region)
462            self.render_legend(map)
463            self.render_scalebar(map)
464            self.dc.EndDrawing()
465    
466        def render_frame(self, region):
467            """Render the frames for map and legend/scalebar."""
468    
469            dc = self.dc
470            dc.SetPen(wxBLACK_PEN)
471            dc.SetBrush(wxTRANSPARENT_BRUSH)
472    
473            # Dimension stuff
474            width, height = dc.GetSizeTuple()
475            mminx, mminy, mmaxx, mmaxy = self.mapregion
476    
477            # Page Frame
478            dc.DrawRectangle(15,15,width-30, (mmaxy-mminy)+10)
479            
480            # Map Frame
481            llx, lly, urx, ury = region
482            dc.DrawRectangle(mminx + self.shiftx, mminy + self.shifty, urx, ury)
483            
484            # Legend Frame
485            dc.DrawRectangle(mmaxx+10,mminy,(width-20) - (mmaxx+10), mmaxy-mminy)
486    
487            dc.DestroyClippingRegion()
488            dc.SetClippingRegion(mmaxx+10,mminy,
489                                 (width-20) - (mmaxx+10), mmaxy-mminy)
490    
491        def render_legend(self, map):
492            """Render the legend on the Map."""
493    
494            previewer = ClassDataPreviewer()
495            dc = self.dc
496            dc.SetPen(wxBLACK_PEN)
497            dc.SetBrush(wxTRANSPARENT_BRUSH)
498    
499            # Dimension stuff
500            width, height = dc.GetSizeTuple()
501            mminx, mminy, mmaxx, mmaxy = self.mapregion
502            textwidth, textheight = dc.GetTextExtent("0")
503            iconwidth  = textheight
504            iconheight = textheight
505            stepy = textheight+3
506            dx = 10
507            posx = mmaxx + 10 + 5   # 10 pix distance mapframe/legend frame,
508                                    # 5 pix inside legend frame
509            posy = mminy + 5        # 5 pix inside legend frame
510            
511            # Render the legend
512            dc.SetTextForeground(wxBLACK)
513            if map.HasLayers():
514                for l in map.Layers():
515                    if l.Visible():
516                        # Render title
517                        dc.DrawText(l.Title(), posx, posy)
518                        posy+=stepy
519                        # Render classification
520                        clazz = l.GetClassification()
521                        shapeType = l.ShapeType()
522                        for g in clazz:
523                            if g.IsVisible():
524                                previewer.Draw(dc,
525                                    wxRect(posx+dx, posy, iconwidth, iconheight),
526                                    g.GetProperties(), shapeType)
527                                dc.DrawText(g.GetDisplayText(),
528                                            posx+2*dx+iconwidth, posy)
529                                posy+=stepy
530            
531        def render_scalebar(self, map):
532            """Render the scalebar."""
533    
534            scalebar = ScaleBar(map)
535    
536            # Dimension stuff
537            width, height = self.dc.GetSizeTuple()
538            mminx, mminy, mmaxx, mmaxy = self.mapregion
539          
540            # Render the scalebar
541            scalebar.DrawScaleBar(self.scale, self.dc,
542                                 (mmaxx+10+5, mmaxy-25),
543                                 ((width-15-5) - (mmaxx+10+5),20)
544                                )
545            # 10 pix between map and legend frame, 5 pix inside legend frame
546            # 25 pix from the legend frame bottom line
547            # Width: 15 pix from DC border, 5 pix inside frame, 10, 5 as above
548            # Height: 20
549    
550    class PrinterRenderer(ExportRenderer):
551    
552        # Printing as well as Export / Screen display only the visible layer.
553        honor_visibility = 1
554    

Legend:
Removed from v.605  
changed lines
  Added in v.1165

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26