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

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

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

revision 1935 by bh, Tue Nov 11 18:16:20 2003 UTC revision 2617 by jonathan, Fri May 6 14:18:00 2005 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003, 2004 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  # Jonathan Coles <[email protected]>  # Jonathan Coles <[email protected]>
# Line 30  from Thuban.Model.label import ALIGN_CEN Line 30  from Thuban.Model.label import ALIGN_CEN
30    
31  import Thuban.Model.resource  import Thuban.Model.resource
32    
 if Thuban.Model.resource.has_gdal_support():  
     from gdalwarp import ProjectRasterFile  
33    
34    
35  #  #
# Line 42  if Thuban.Model.resource.has_gdal_suppor Line 40  if Thuban.Model.resource.has_gdal_suppor
40  # (layer_class, draw_function) pairs. If the renderer has to draw a  # (layer_class, draw_function) pairs. If the renderer has to draw a
41  # non-builtin layer type, i.e. a layer that is not a subclass of Layer  # non-builtin layer type, i.e. a layer that is not a subclass of Layer
42  # or RasterLayer, it iterates through that list, tests whether the layer  # or RasterLayer, it iterates through that list, tests whether the layer
43  # to be drawin is an instance of layer_class and if so calls  # to be drawn is an instance of layer_class and if so calls
44  # draw_function with the renderer and the layer as arguments. Since  # draw_function with the renderer and the layer as arguments. Since
45  # drawing is done incrementally, the draw_function should return an  # drawing is done incrementally, the draw_function should return an
46  # iterable. The easiest way is to simply implement the draw_function as  # iterable. The easiest way is to simply implement the draw_function as
# Line 64  def add_renderer_extension(layer_class, Line 62  def add_renderer_extension(layer_class,
62      function should return an iterable. The easiest way is to simply      function should return an iterable. The easiest way is to simply
63      implement the draw_function as a generator and to yield True in      implement the draw_function as a generator and to yield True in
64      suitable places, or to return the empty tuple if it's not possible      suitable places, or to return the empty tuple if it's not possible
65      to do the rendering in incrementally.      to do the rendering incrementally.
66      """      """
67      _renderer_extensions.append((layer_class, function))      _renderer_extensions.append((layer_class, function))
68    
# Line 76  def init_renderer_extensions(): Line 74  def init_renderer_extensions():
74      """      """
75      del _renderer_extensions[:]      del _renderer_extensions[:]
76    
77    def proj_params_to_str(proj):
78        "Build a string suitable for GDAL describing the given projection"
79        str = ""
80        if proj is not None:
81            for p in proj.GetAllParameters():
82                str += "+" + p + " "
83        return str
84    
85  #  #
86  #       Base Renderer  #       Base Renderer
# Line 177  class BaseRenderer: Line 182  class BaseRenderer:
182          that methods especially in derived classes have access to the          that methods especially in derived classes have access to the
183          map if necessary.          map if necessary.
184          """          """
         # Whether the raster layer has already been drawn. See below for  
         # the optimization this is used for  
         seenRaster = True  
   
         #  
         # This is only a good optimization if there is only one  
         # raster layer and the image covers the entire window (as  
         # it currently does). We note if there is a raster layer  
         # and only begin drawing layers once we have drawn it.  
         # That way we avoid drawing layers that won't be seen.  
         #  
         if Thuban.Model.resource.has_gdal_support():  
             for layer in self.map.Layers():  
                 if isinstance(layer, RasterLayer) and layer.Visible():  
                     seenRaster = False  
                     break  
185    
186          for layer in self.map.Layers():          for layer in self.map.Layers():
187              # if honor_visibility is true, only draw visible layers,              # if honor_visibility is true, only draw visible layers,
188              # otherwise draw all layers              # otherwise draw all layers
189              if not self.honor_visibility or layer.Visible():              if not self.honor_visibility or layer.Visible():
190                  if isinstance(layer, Layer) and seenRaster:                  if isinstance(layer, Layer):
191                      for i in self.draw_shape_layer_incrementally(layer):                      for i in self.draw_shape_layer_incrementally(layer):
192                          yield True                          yield True
193                  elif isinstance(layer, RasterLayer) \                  elif isinstance(layer, RasterLayer):
                     and Thuban.Model.resource.has_gdal_support():  
194                      self.draw_raster_layer(layer)                      self.draw_raster_layer(layer)
                     seenRaster = True  
195                      yield True                      yield True
196                  else:                  else:
197                      # look it up in the renderer extensions                      # look it up in the renderer extensions
# Line 288  class BaseRenderer: Line 275  class BaseRenderer:
275                  data = shape.RawData()                  data = shape.RawData()
276              else:              else:
277                  data = shape.Points()                  data = shape.Points()
278              draw_func(draw_func_param, data, pen, brush)              if draw_func == self.draw_point_shape:
279                     draw_func(draw_func_param, data, pen, brush,
280                               size = group.GetProperties().GetSize())
281                else:
282                     draw_func(draw_func_param, data, pen, brush)
283              if count % 500 == 0:              if count % 500 == 0:
284                  yield True                  yield True
285    
# Line 365  class BaseRenderer: Line 356  class BaseRenderer:
356          scale = self.scale          scale = self.scale
357          offx, offy = self.offset          offx, offy = self.offset
358          make_point = self.make_point          make_point = self.make_point
359    
360          for part in points:          for part in points:
361              result.append([])              result.append([])
362              for x, y in part:              for x, y in part:
# Line 383  class BaseRenderer: Line 375  class BaseRenderer:
375          value of the shape's Points() method. The coordinates in the          value of the shape's Points() method. The coordinates in the
376          DC's coordinate system are determined with          DC's coordinate system are determined with
377          self.projected_points.          self.projected_points.
378    
379            For a description of the algorithm look in wxproj.cpp.
380          """          """
381          points = self.projected_points(layer, points)          points = self.projected_points(layer, points)
382    
# Line 391  class BaseRenderer: Line 385  class BaseRenderer:
385              for part in points:              for part in points:
386                  polygon.extend(part)                  polygon.extend(part)
387    
388                # missing back vertices for correct filling.
389              insert_index = len(polygon)              insert_index = len(polygon)
390              for part in points[:-1]:              for part in points[:-1]:
391                  polygon.insert(insert_index, part[0])                  polygon.insert(insert_index, part[0])
# Line 420  class BaseRenderer: Line 415  class BaseRenderer:
415          for part in points:          for part in points:
416              self.dc.DrawLines(part)              self.dc.DrawLines(part)
417    
418      def draw_point_shape(self, layer, points, pen, brush):      def draw_point_shape(self, layer, points, pen, brush, size = 5):
419          """Draw a point shape from layer with the given brush and pen          """Draw a point shape from layer with the given brush and pen
420    
421          The shape is given by points argument which is a the return          The shape is given by points argument which is a the return
# Line 434  class BaseRenderer: Line 429  class BaseRenderer:
429          if not points:          if not points:
430              return              return
431    
432          radius = int(round(self.resolution * 5))          radius = int(round(self.resolution * size))
433          self.dc.SetBrush(brush)          self.dc.SetBrush(brush)
434          self.dc.SetPen(pen)          self.dc.SetPen(pen)
435          for part in points:          for part in points:
# Line 445  class BaseRenderer: Line 440  class BaseRenderer:
440      def draw_raster_layer(self, layer):      def draw_raster_layer(self, layer):
441          """Draw the raster layer          """Draw the raster layer
442    
443          This implementation does the projection and scaling of the data          This implementation uses self.projected_raster_layer() to project
444          as required by the layer's and map's projections and the scale          and scale the data as required by the layer's and map's projections
445          and offset of the renderer and then hands the transformed data          and the scale and offset of the renderer and then hands the transformed
446          to self.draw_raster_data() which has to be implemented in          data to self.draw_raster_data() which has to be implemented in
447          derived classes.          derived classes.
448          """          """
449          offx, offy = self.offset          offx, offy = self.offset
450          width, height = self.dc.GetSizeTuple()          width, height = self.dc.GetSizeTuple()
451    
452          in_proj = ""          in_proj  = proj_params_to_str(layer.GetProjection())
453          proj = layer.GetProjection()          out_proj = proj_params_to_str(self.map.GetProjection())
         if proj is not None:  
             for p in proj.GetAllParameters():  
                 in_proj += "+" + p + " "  
454    
455          out_proj = ""          # True  -- warp the image to the size of the whole screen
456          proj = self.map.GetProjection()          # False -- only use the bound box of the layer (currently inaccurate)
457          if proj is not None:          if True:
458              for p in proj.GetAllParameters():          #if False:
459                  out_proj += "+" + p + " "              pmin = [0,height]
460                pmax = [width, 0]
461            else:
462                bb = layer.LatLongBoundingBox()
463                bb = [[[bb[0], bb[1]], [bb[2], bb[3]],],]
464                pmin, pmax = self.projected_points(layer, bb)[0]
465    
466          xmin = (0 - offx) / self.scale          #print bb
467          ymin = (offy - height) / self.scale          #print pmin, pmax
         xmax = (width - offx) / self.scale  
         ymax = (offy - 0) / self.scale  
468    
469          try:          fmin = [max(0, min(pmin[0], pmax[0])) - offx,
470              data = ProjectRasterFile(layer.GetImageFilename(),                  offy - min(height, max(pmin[1], pmax[1]))]
471                                       in_proj, out_proj,  
472                                       (xmin, ymin, xmax, ymax), "",          fmax = [min(width, max(pmin[0], pmax[0])) - offx,
473                                       (width, height))                  offy - max(0, min(pmin[1], pmax[1]))]
474          except (IOError, AttributeError, ValueError):  
475              # Why does this catch AttributeError and ValueError?          xmin = fmin[0]/self.scale
476              # FIXME: The exception should be communicated to the user          ymin = fmin[1]/self.scale
477              # better.          xmax = fmax[0]/self.scale
478              traceback.print_exc()          ymax = fmax[1]/self.scale
         else:  
             self.draw_raster_data(data, "BMP")  
479    
480      def draw_raster_data(self, data, format="BMP"):          width  = int(min(width,  round(fmax[0] - fmin[0] + 1)))
481          """Draw the raster image in data onto the DC          height = int(min(height, round(fmax[1] - fmin[1] + 1)))
482    
483            options = 0
484            options = options | layer.MaskType()
485    
486            img_data = self.projected_raster_layer(layer, in_proj, out_proj,
487                        (xmin,ymin,xmax,ymax), [0,0], (width, height), options)
488    
489            if img_data is not None:
490                data = (width, height, img_data)
491                self.draw_raster_data(fmin[0]+offx, offy-fmax[1],
492                                      data, format="RAW", opacity=layer.Opacity())
493                data = None
494    
495        def projected_raster_layer(self, layer, srcProj, dstProj, extents,
496                                   resolution, dimensions, options):
497            """Return the projected raster image associated with the layer.
498    
499            The returned value will be a tuple of the form
500    
501                (image_data, mask_data, alpha_data)
502    
503            suitable for the data parameter to draw_raster_data.
504    
505            The return value may be None if raster projections are not supported.
506    
507            srcProj     --  a string describing the source projection
508            dstProj     --  a string describing the destination projection
509            extents     --  a tuple of the region to project in map coordinates
510            resolution  --  (currently not used, defaults to [0,0])
511            dimensions  --  a tuple (width, height) for the output image
512            options     --  bit-wise options to pass to the renderer
513    
514            the currently supported values for options are
515    
516                OPTS_MASK        = 1  -- generate a mask
517                OPTS_ALPHA       = 2  -- generate an alpha channel
518                OPTS_INVERT_MASK = 4  -- invert the values in the mask
519                                         (if generated)
520    
521            This method has to be implemented by derived classes.
522            """
523    
524            raise NotImplementedError
525    
526          The raster image data is a string holding the data in the format      def draw_raster_data(self, x, y, data, format="BMP", opacity=1.0):
527          indicated by the format parameter. The image is assumed to be          """Draw a raster image held in data onto the DC with the top
528          exactly the size of the dc and to cover it completely.          left corner at (x,y)
529    
530            The raster image data is a tuple of the form
531                (width, height, (image_data, mask_data, alpha_data))
532            
533            holding the image width, height, image data, mask data, and alpha data.
534            mask_data may be None if a mask should not be used. alpha_data may
535            also be None. If both are not None mask overrides alpha. If
536            format is 'RAW' the data will be RGB values and the mask
537            will be in XMB format. Otherwise, both kinds
538            of data are assumed to be in the format specified in format.
539    
540          The format parameter is a string with the name of the format.          The format parameter is a string with the name of the format.
541          The following format names should be used:          The following format names should be used:
542    
543            'BMP' -- Windows Bitmap            'RAW'  -- an array of RGB values (len=3*width*height)
544            'JPEG' -- Jpeg            'PNG'  -- Portable Network Graphic (transparency supported)
545              'BMP'  -- Windows Bitmap
546              'TIFF' -- Tagged Image File Format
547              'GIF'  -- GIF Image
548              'JPEG' -- JPEG Image
549    
550          The default format is 'bmp'.          The default format is 'BMP'.
551    
552          This method has to be implemented by derived classes. The          This method has to be implemented by derived classes. The
553          implementation in the derived class should try to support at          implementation in the derived class should try to support at

Legend:
Removed from v.1935  
changed lines
  Added in v.2617

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26