/[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 1554 by bh, Wed Aug 6 17:24:30 2003 UTC revision 1879 by bh, Wed Oct 29 17:43:40 2003 UTC
# Line 14  be tested reasonably easily and it could Line 14  be tested reasonably easily and it could
14  renderers.  renderers.
15  """  """
16    
17    from __future__ import generators
18    
19  __version__ = "$Revision$"  __version__ = "$Revision$"
20  # $Source$  # $Source$
21  # $Id$  # $Id$
# Line 49  class BaseRenderer: Line 51  class BaseRenderer:
51      TRANSPARENT_PEN = None      TRANSPARENT_PEN = None
52      TRANSPARENT_BRUSH = None      TRANSPARENT_BRUSH = None
53    
54      def __init__(self, dc, scale, offset, resolution = 72.0,      def __init__(self, dc, map, scale, offset, region = None,
55                   honor_visibility = None):                   resolution = 72.0, honor_visibility = None):
56          """Inititalize the renderer.          """Inititalize the renderer.
57    
58          dc -- the device context to render on.          dc -- the device context to render on.
# Line 58  class BaseRenderer: Line 60  class BaseRenderer:
60          scale, offset -- the scale factor and translation to convert          scale, offset -- the scale factor and translation to convert
61                  between projected coordinates and the DC coordinates                  between projected coordinates and the DC coordinates
62    
63            region -- The region to draw as a (x, y, width, height) tuple in
64                      the map's coordinate system. Default is None meaning
65                      to draw everything.
66    
67          resolution -- the assumed resolution of the DC. Used to convert          resolution -- the assumed resolution of the DC. Used to convert
68                  absolute lengths like font sizes to DC coordinates. The                  absolute lengths like font sizes to DC coordinates. The
69                  defauult is 72.0                  default is 72.0. If given, this parameter must be
70                    provided as a keyword argument.
71    
72          honor_visibility -- boolean. If true, honor the visibility flag          honor_visibility -- boolean. If true, honor the visibility flag
73                  of the layers, otherwise draw all layers. If None (the                  of the layers, otherwise draw all layers. If None (the
74                  default), use the renderer's default.                  default), use the renderer's default. If given, this
75                    parameter must be provided as a keyword argument.
76          """          """
77          # resolution in pixel/inch          # resolution in pixel/inch
   
78          self.dc = dc          self.dc = dc
79            self.map = map
80          self.scale = scale          self.scale = scale
81          self.offset = offset          self.offset = offset
82            self.region = region
83          if honor_visibility is not None:          if honor_visibility is not None:
84              self.honor_visibility = honor_visibility              self.honor_visibility = honor_visibility
85          # store the resolution in pixel/point because it's more useful          # store the resolution in pixel/point because it's more useful
# Line 85  class BaseRenderer: Line 94  class BaseRenderer:
94          """          """
95          raise NotImplementedError          raise NotImplementedError
96    
97      def render_map(self, map):      def render_map(self):
98          """Render the map onto the DC the renderer was instantiated with          """Render the map onto the DC.
99    
100            Both map and DC are the ones the renderer was instantiated with.
101    
102            This method is just a front-end for render_map_incrementally
103            which does all rendering in one go. It also calls the dc's
104            BeginDrawing and EndDrawing methods before and after calling
105            render_map_incrementally.
106            """
107    
108            self.dc.BeginDrawing()
109            try:
110                for cont in self.render_map_incrementally():
111                    pass
112            finally:
113                self.dc.EndDrawing()
114    
115        def render_map_incrementally(self):
116            """Render the map incrementally.
117    
118            Return an iterator whose next method should be called until it
119            returns False. After returning False it will raise StopIteration
120            so that you could also use it in a for loop (implementation
121            detail: this method is implemented as a generator).
122    
123          Iterate through all layers and draw them. Layers containing          Iterate through all layers and draw them. Layers containing
124          vector data are drawn with the draw_shape_layer method, raster          vector data are drawn with the draw_shape_layer method, raster
# Line 97  class BaseRenderer: Line 129  class BaseRenderer:
129          that methods especially in derived classes have access to the          that methods especially in derived classes have access to the
130          map if necessary.          map if necessary.
131          """          """
         # Some method have to have access to the map so we store it in  
         # self.map.  
         self.map = map  
   
132          # Whether the raster layer has already been drawn. See below for          # Whether the raster layer has already been drawn. See below for
133          # the optimization this is used for          # the optimization this is used for
134          seenRaster = True          seenRaster = True
135    
136          self.dc.BeginDrawing()          #
137            # This is only a good optimization if there is only one
138            # raster layer and the image covers the entire window (as
139            # it currently does). We note if there is a raster layer
140            # and only begin drawing layers once we have drawn it.
141            # That way we avoid drawing layers that won't be seen.
142            #
143            if Thuban.Model.resource.has_gdal_support():
144                for layer in self.map.Layers():
145                    if isinstance(layer, RasterLayer) and layer.Visible():
146                        seenRaster = False
147                        break
148    
149            for layer in self.map.Layers():
150                # if honor_visibility is true, only draw visible layers,
151                # otherwise draw all layers
152                if not self.honor_visibility or layer.Visible():
153                    if isinstance(layer, Layer) and seenRaster:
154                        for i in self.draw_shape_layer_incrementally(layer):
155                            yield True
156                    elif isinstance(layer, RasterLayer) \
157                        and Thuban.Model.resource.has_gdal_support():
158                        self.draw_raster_layer(layer)
159                        seenRaster = True
160                        yield True
161    
162          try:          self.draw_label_layer(self.map.LabelLayer())
163              #          yield False
             # 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 map.Layers():  
                     if isinstance(layer, RasterLayer) and layer.Visible():  
                         seenRaster = False  
                         break  
   
             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():  
                     if isinstance(layer, Layer) and seenRaster:  
                         self.draw_shape_layer(layer)  
                     elif isinstance(layer, RasterLayer) \  
                         and Thuban.Model.resource.has_gdal_support():  
                         self.draw_raster_layer(layer)  
                         seenRaster = True  
   
             self.draw_label_layer(map.LabelLayer())  
         finally:  
             self.dc.EndDrawing()  
164    
165      def draw_shape_layer(self, layer):      def draw_shape_layer_incrementally(self, layer):
166          """Draw the shape layer layer onto the map.          """Draw the shape layer layer onto the map incrementally.
167    
168          Automatically called by render_map. Iterate through all shapes          This method is a generator which yields True after every 500
169          as indicated by self.layer_ids() and draw them, using low-level          shapes.
         renderers returned by self.low_level_renderer().  
170          """          """
171          scale = self.scale          scale = self.scale
172          offx, offy = self.offset          offx, offy = self.offset
# Line 159  class BaseRenderer: Line 184  class BaseRenderer:
184          defaultGroup = lc.GetDefaultGroup()          defaultGroup = lc.GetDefaultGroup()
185          table = layer.ShapeStore().Table()          table = layer.ShapeStore().Table()
186    
187            if lc.GetNumGroups() == 0:
188                # There's only the default group, so we can pretend that
189                # there is no field to classifiy on which makes things
190                # faster since we don't need the attribute information at
191                # all.
192                field = None
193    
194          # Determine which render function to use.          # Determine which render function to use.
195          draw_func, draw_func_param = self.low_level_renderer(layer)          useraw, draw_func, draw_func_param = self.low_level_renderer(layer)
196    
197          # Iterate through all shapes that have to be drawn.          # Iterate through all shapes that have to be drawn.
198          for i in self.layer_ids(layer):          count = 0
199            for shape in self.layer_shapes(layer):
200                count += 1
201              if field is None:              if field is None:
202                  group = defaultGroup                  group = defaultGroup
203              else:              else:
204                  record = table.ReadRowAsDict(i)                  record = table.ReadRowAsDict(shape.ShapeID())
205                  assert record is not None                  assert record is not None
206                  group = lc.FindGroup(record[field])                  group = lc.FindGroup(record[field])
207    
# Line 184  class BaseRenderer: Line 217  class BaseRenderer:
217                  if prop != old_prop:                  if prop != old_prop:
218                      pen, brush = self.tools_for_property(prop)                      pen, brush = self.tools_for_property(prop)
219    
220              draw_func(draw_func_param, i, pen, brush)              if useraw:
221                    data = shape.RawData()
222                else:
223                    data = shape.Points()
224                draw_func(draw_func_param, data, pen, brush)
225                if count % 500 == 0:
226                    yield True
227    
228      def layer_ids(self, layer):      def layer_shapes(self, layer):
229          """Return the shape ids of the given layer that have to be drawn.          """Return an iterable over the shapes to be drawn from the given layer.
230    
231          The default implementation simply returns all ids in the layer.          The default implementation simply returns all ids in the layer.
232          Override in derived classes to be more precise.          Override in derived classes to be more precise.
233          """          """
234          return range(layer.NumShapes())          return layer.ShapeStore().AllShapes()
235    
236      def low_level_renderer(self, layer):      def low_level_renderer(self, layer):
237          """Return the low-level renderer for the layer for draw_shape_layer          """Return the low-level renderer for the layer for draw_shape_layer
238    
239          The low level renderer to be returned by this method is a tuple          The low level renderer to be returned by this method is a tuple
240          (func, param) where func is a callable object and param is          (useraw, func, param) where useraw is a boolean indicating
241          passed as the first parameter to func. The draw_shape_layer          whether the function uses the raw shape data, func is a callable
242          method will call func like this:          object and param is passed as the first parameter to func. The
243            draw_shape_layer method will call func like this:
244              func(param, rawshape, pen, brush)  
245                func(param, shapedata, pen, brush)
246          where rawshape is currently the shapeid. pen and brush are the  
247          pen and brush to use to draw the shape on the dc.          where shapedata is the return value of the RawData method of the
248            shape object if useraw is true or the return value of the Points
249            method if it's false. pen and brush are the pen and brush to use
250            to draw the shape on the dc.
251    
252          The default implementation returns one of          The default implementation returns one of
253          self.draw_polygon_shape, self.draw_arc_shape or          self.draw_polygon_shape, self.draw_arc_shape or
254          self.draw_point_shape as func and layer as param. Derived          self.draw_point_shape as func and layer as param. None of the
255          classes can override this method to return more efficient low          method use the raw shape data. Derived classes can override this
256          level renderers.          method to return more efficient low level renderers.
257          """          """
258          shapetype = layer.ShapeType()          shapetype = layer.ShapeType()
259          if shapetype == SHAPETYPE_POINT:          if shapetype == SHAPETYPE_POINT:
# Line 220  class BaseRenderer: Line 262  class BaseRenderer:
262              func = self.draw_arc_shape              func = self.draw_arc_shape
263          else:          else:
264              func = self.draw_polygon_shape              func = self.draw_polygon_shape
265          return func, layer          return False, func, layer
266    
267      def make_point(self, x, y):      def make_point(self, x, y):
268          """Convert (x, y) to a point object.          """Convert (x, y) to a point object.
# Line 229  class BaseRenderer: Line 271  class BaseRenderer:
271          """          """
272          raise NotImplementedError          raise NotImplementedError
273    
274      def projected_points(self, layer, shapeid):      def projected_points(self, layer, points):
275          """Return the projected coordinates of shape shapeid in layer.          """Return the projected coordinates of the points taken from layer.
276    
277          Read the shape from the layer through its Shape method and          Transform all the points in the list of lists of coordinate
278          transform all the points in the list of lists of coordinate          pairs in points.
         pairs returned by the shape's Points method.  
279    
280          The transformation applies the inverse of the layer's projection          The transformation applies the inverse of the layer's projection
281          if any, then the map's projection if any and finally applies          if any, then the map's projection if any and finally applies
# Line 253  class BaseRenderer: Line 294  class BaseRenderer:
294              inverse = proj.Inverse              inverse = proj.Inverse
295          else:          else:
296              inverse = None              inverse = None
297          shape = layer.Shape(shapeid)          result = []
         points = []  
298          scale = self.scale          scale = self.scale
299          offx, offy = self.offset          offx, offy = self.offset
300          make_point = self.make_point          make_point = self.make_point
301          for part in shape.Points():          for part in points:
302              points.append([])              result.append([])
303              for x, y in part:              for x, y in part:
304                  if inverse:                  if inverse:
305                      x, y = inverse(x, y)                      x, y = inverse(x, y)
306                  if forward:                  if forward:
307                      x, y = forward(x, y)                      x, y = forward(x, y)
308                  points[-1].append(make_point(x * scale + offx,                  result[-1].append(make_point(x * scale + offx,
309                                               -y * scale + offy))                                               -y * scale + offy))
310          return points          return result
311    
312      def draw_polygon_shape(self, layer, index, pen, brush):      def draw_polygon_shape(self, layer, points, pen, brush):
313          """Draw a polygon shape with the given brush and pen          """Draw a polygon shape from layer with the given brush and pen
314    
315          The shape is indicated by its id (index) and the layer. The          The shape is given by points argument which is a the return
316          coordinates in the DC's coordinate system are determined with          value of the shape's Points() method. The coordinates in the
317            DC's coordinate system are determined with
318          self.projected_points.          self.projected_points.
319          """          """
320          points = self.projected_points(layer, index)          points = self.projected_points(layer, points)
321    
322          if brush is not self.TRANSPARENT_BRUSH:          if brush is not self.TRANSPARENT_BRUSH:
323              polygon = []              polygon = []
# Line 298  class BaseRenderer: Line 339  class BaseRenderer:
339              for part in points:              for part in points:
340                  self.dc.DrawLines(part)                  self.dc.DrawLines(part)
341    
342      def draw_arc_shape(self, layer, index, pen, brush):      def draw_arc_shape(self, layer, points, pen, brush):
343          """Draw an arc shape with the given brush and pen          """Draw an arc shape from layer with the given brush and pen
344    
345          The shape is indicated by its id (index) and the layer. The          The shape is given by points argument which is a the return
346          coordinates in the DC's coordinate system are determined with          value of the shape's Points() method. The coordinates in the
347            DC's coordinate system are determined with
348          self.projected_points.          self.projected_points.
349          """          """
350          points = self.projected_points(layer, index)          points = self.projected_points(layer, points)
351          self.dc.SetBrush(brush)          self.dc.SetBrush(brush)
352          self.dc.SetPen(pen)          self.dc.SetPen(pen)
353          for part in points:          for part in points:
354              self.dc.DrawLines(part)              self.dc.DrawLines(part)
355    
356      def draw_point_shape(self, layer, index, pen, brush):      def draw_point_shape(self, layer, points, pen, brush):
357          """Draw a point shape with the given brush and pen          """Draw a point shape from layer with the given brush and pen
358    
359          The shape is indicated by its id (index) and the layer. The          The shape is given by points argument which is a the return
360          coordinates in the DC's coordinate system are determined with          value of the shape's Points() method. The coordinates in the
361            DC's coordinate system are determined with
362          self.projected_points.          self.projected_points.
363    
364          The point is drawn as a circle centered on the point.          The point is drawn as a circle centered on the point.
365          """          """
366          points = self.projected_points(layer, index)          points = self.projected_points(layer, points)
367          if not points:          if not points:
368              return              return
369    

Legend:
Removed from v.1554  
changed lines
  Added in v.1879

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26