/[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 1866 by bh, Mon Oct 27 13:01:58 2003 UTC revision 2413 by bernhard, Mon Nov 22 11:16:35 2004 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 20  __version__ = "$Revision$" Line 20  __version__ = "$Revision$"
20  # $Source$  # $Source$
21  # $Id$  # $Id$
22    
23    import sys
24  import traceback  import traceback
25    
26  from Thuban.Model.layer import Layer, RasterLayer  from Thuban.Model.layer import Layer, RasterLayer
# Line 33  if Thuban.Model.resource.has_gdal_suppor Line 34  if Thuban.Model.resource.has_gdal_suppor
34      from gdalwarp import ProjectRasterFile      from gdalwarp import ProjectRasterFile
35    
36    
37    #
38    #       Renderer Extensions
39    #
40    # The renderer extensions provide a way to render layer types defined in
41    # Thuban extensions. The renderer extensions are stored as a list with
42    # (layer_class, draw_function) pairs. If the renderer has to draw a
43    # non-builtin layer type, i.e. a layer that is not a subclass of Layer
44    # or RasterLayer, it iterates through that list, tests whether the layer
45    # to be drawn is an instance of layer_class and if so calls
46    # draw_function with the renderer and the layer as arguments. Since
47    # drawing is done incrementally, the draw_function should return an
48    # iterable. The easiest way is to simply implement the draw_function as
49    # a generator and to yield in suitable places, or to return the empty
50    # tuple.
51    #
52    # New renderer extensions should be added with add_renderer_extension().
53    # If necessary the extensions list can be reset with
54    # init_renderer_extensions().
55    
56    _renderer_extensions = []
57    
58    def add_renderer_extension(layer_class, function):
59        """Add a renderer extension for the layer class layer_class
60    
61        When an instance of layer_class is to be drawn by the renderer the
62        renderer will call function with the renderer and the layer_class
63        instance as arguments. Since drawing is done incrementally, the
64        function should return an iterable. The easiest way is to simply
65        implement the draw_function as a generator and to yield True in
66        suitable places, or to return the empty tuple if it's not possible
67        to do the rendering incrementally.
68        """
69        _renderer_extensions.append((layer_class, function))
70    
71    def init_renderer_extensions():
72        """(Re)initialize the list of renderer extensions
73    
74        Calling this function outside of the test suite is probably not
75        useful.
76        """
77        del _renderer_extensions[:]
78    
79    
80    #
81    #       Base Renderer
82    #
83    
84  class BaseRenderer:  class BaseRenderer:
85    
86      """Basic Renderer Infrastructure for Thuban Maps      """Basic Renderer Infrastructure for Thuban Maps
# Line 150  class BaseRenderer: Line 198  class BaseRenderer:
198              # if honor_visibility is true, only draw visible layers,              # if honor_visibility is true, only draw visible layers,
199              # otherwise draw all layers              # otherwise draw all layers
200              if not self.honor_visibility or layer.Visible():              if not self.honor_visibility or layer.Visible():
201                  if isinstance(layer, Layer) and seenRaster:                  if isinstance(layer, Layer):
202                      for i in self.draw_shape_layer_incrementally(layer):                      if seenRaster:
203                          yield True                          for i in self.draw_shape_layer_incrementally(layer):
204                                yield True
205                  elif isinstance(layer, RasterLayer) \                  elif isinstance(layer, RasterLayer) \
206                      and Thuban.Model.resource.has_gdal_support():                      and Thuban.Model.resource.has_gdal_support():
207                      self.draw_raster_layer(layer)                      self.draw_raster_layer(layer)
208                      seenRaster = True                      seenRaster = True
209                      yield True                      yield True
210                    else:
211                        # look it up in the renderer extensions
212                        for cls, func in _renderer_extensions:
213                            if isinstance(layer, cls):
214                                for i in func(self, layer):
215                                    yield True
216                                break
217                        else:
218                            # No renderer found. Print a message about it
219                            print >>sys.stderr, ("Drawing layer %r not supported"
220                                                 % layer)
221                yield True
222    
223          self.draw_label_layer(self.map.LabelLayer())          self.draw_label_layer(self.map.LabelLayer())
224          yield False          yield False
# Line 184  class BaseRenderer: Line 245  class BaseRenderer:
245          defaultGroup = lc.GetDefaultGroup()          defaultGroup = lc.GetDefaultGroup()
246          table = layer.ShapeStore().Table()          table = layer.ShapeStore().Table()
247    
248            if lc.GetNumGroups() == 0:
249                # There's only the default group, so we can pretend that
250                # there is no field to classifiy on which makes things
251                # faster since we don't need the attribute information at
252                # all.
253                field = None
254    
255          # Determine which render function to use.          # Determine which render function to use.
256          useraw, draw_func, draw_func_param = self.low_level_renderer(layer)          useraw, draw_func, draw_func_param = self.low_level_renderer(layer)
257    
258            #
259          # Iterate through all shapes that have to be drawn.          # Iterate through all shapes that have to be drawn.
260            #
261    
262            # Count the shapes drawn so that we can yield every few hundred
263            # shapes
264          count = 0          count = 0
265    
266            # Cache the tools (pens and brushes) for the classification
267            # groups. This is a mapping from the group's ids to the a tuple
268            # (pen, brush)
269            tool_cache = {}
270    
271          for shape in self.layer_shapes(layer):          for shape in self.layer_shapes(layer):
272              count += 1              count += 1
273              if field is None:              if field is None:
274                  group = defaultGroup                  group = defaultGroup
275              else:              else:
276                  record = table.ReadRowAsDict(shape.ShapeID())                  value = table.ReadValue(shape.ShapeID(), field)
277                  assert record is not None                  group = lc.FindGroup(value)
                 group = lc.FindGroup(record[field])  
278    
279              if not group.IsVisible():              if not group.IsVisible():
280                  continue                  continue
281    
282              # don't recreate new objects if they are the same as before              try:
283              if group is not old_group:                  pen, brush = tool_cache[id(group)]
284                  old_group = group              except KeyError:
285                    pen, brush = tool_cache[id(group)] \
286                  prop = group.GetProperties()                               = self.tools_for_property(group.GetProperties())
   
                 if prop != old_prop:  
                     pen, brush = self.tools_for_property(prop)  
287    
288              if useraw:              if useraw:
289                  data = shape.RawData()                  data = shape.RawData()
290              else:              else:
291                  data = shape.Points()                  data = shape.Points()
292              draw_func(draw_func_param, data, pen, brush)              if draw_func == self.draw_point_shape:
293                     draw_func(draw_func_param, data, pen, brush,
294                               size = group.GetProperties().GetSize())
295                else:
296                     draw_func(draw_func_param, data, pen, brush)
297              if count % 500 == 0:              if count % 500 == 0:
298                  yield True                  yield True
299    
# Line 309  class BaseRenderer: Line 388  class BaseRenderer:
388          value of the shape's Points() method. The coordinates in the          value of the shape's Points() method. The coordinates in the
389          DC's coordinate system are determined with          DC's coordinate system are determined with
390          self.projected_points.          self.projected_points.
391    
392            For a description of the algorithm look in wxproj.cpp.
393          """          """
394          points = self.projected_points(layer, points)          points = self.projected_points(layer, points)
395    
# Line 317  class BaseRenderer: Line 398  class BaseRenderer:
398              for part in points:              for part in points:
399                  polygon.extend(part)                  polygon.extend(part)
400    
401                # missing back vertices for correct filling.
402              insert_index = len(polygon)              insert_index = len(polygon)
403              for part in points[:-1]:              for part in points[:-1]:
404                  polygon.insert(insert_index, part[0])                  polygon.insert(insert_index, part[0])
# Line 346  class BaseRenderer: Line 428  class BaseRenderer:
428          for part in points:          for part in points:
429              self.dc.DrawLines(part)              self.dc.DrawLines(part)
430    
431      def draw_point_shape(self, layer, points, pen, brush):      def draw_point_shape(self, layer, points, pen, brush, size = 5):
432          """Draw a point shape from layer with the given brush and pen          """Draw a point shape from layer with the given brush and pen
433    
434          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 360  class BaseRenderer: Line 442  class BaseRenderer:
442          if not points:          if not points:
443              return              return
444    
445          radius = self.resolution * 5          radius = int(round(self.resolution * size))
446          self.dc.SetBrush(brush)          self.dc.SetBrush(brush)
447          self.dc.SetPen(pen)          self.dc.SetPen(pen)
448          for part in points:          for part in points:
# Line 408  class BaseRenderer: Line 490  class BaseRenderer:
490              # better.              # better.
491              traceback.print_exc()              traceback.print_exc()
492          else:          else:
493              self.draw_raster_data(data)              self.draw_raster_data(data, "BMP")
494    
495      def draw_raster_data(self, data):      def draw_raster_data(self, data, format="BMP"):
496          """Draw the raster image in data onto the DC          """Draw the raster image in data onto the DC
497    
498          The raster image data is a string holding the data in BMP          The raster image data is a string holding the data in the format
499          format. The data is exactly the size of the dc and covers it          indicated by the format parameter. The image is assumed to be
500          completely.          exactly the size of the dc and to cover it completely.
501    
502            The format parameter is a string with the name of the format.
503            The following format names should be used:
504    
505              'BMP' -- Windows Bitmap
506              'JPEG' -- Jpeg
507    
508            The default format is 'bmp'.
509    
510          This method has to be implemented by derived classes.          This method has to be implemented by derived classes. The
511            implementation in the derived class should try to support at
512            least the formats specified above and may support more.
513          """          """
514          raise NotImplementedError          raise NotImplementedError
515    
# Line 447  class BaseRenderer: Line 539  class BaseRenderer:
539              text = label.text              text = label.text
540              if forward:              if forward:
541                  x, y = forward(x, y)                  x, y = forward(x, y)
542              x = x * scale + offx              x = int(round(x * scale + offx))
543              y = -y * scale + offy              y = int(round(-y * scale + offy))
544              width, height = self.dc.GetTextExtent(text)              width, height = self.dc.GetTextExtent(text)
545              if label.halign == ALIGN_LEFT:              if label.halign == ALIGN_LEFT:
546                  # nothing to be done                  # nothing to be done

Legend:
Removed from v.1866  
changed lines
  Added in v.2413

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26