/[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 1591 by bh, Fri Aug 15 14:00:53 2003 UTC revision 2587 by jonathan, Wed Mar 23 15:30:27 2005 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH  # Copyright (c) 2001-2004 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]> (2001-2003)
4  # Jonathan Coles <[email protected]>  # Jonathan Coles <[email protected]> (2003)
5  # Frank Koormann <[email protected]>  # Frank Koormann <[email protected]> (2003)
6    # Jan-Oliver Wagner <[email protected]> (2003, 2004)
7  #  #
8  # This program is free software under the GPL (>=v2)  # This program is free software under the GPL (>=v2)
9  # Read the file COPYING coming with Thuban for details.  # Read the file COPYING coming with Thuban for details.
10    
11    from __future__ import generators
12    
13  __version__ = "$Revision$"  __version__ = "$Revision$"
14    # $Source$
15    # $Id$
16    
17  import cStringIO  import cStringIO
18    
19    import array
20    
21  from Thuban import _  from Thuban import _
22    
23  from wxPython.wx import wxPoint, wxRect, wxPen, wxBrush, wxFont, \  from wxPython.wx import wxPoint, wxRect, wxPen, wxBrush, wxFont, \
24      wxTRANSPARENT_PEN, wxTRANSPARENT_BRUSH, \      wxTRANSPARENT_PEN, wxTRANSPARENT_BRUSH, \
25      wxBLACK_PEN, wxBLACK, wxSOLID, wxCROSS_HATCH, wxSWISS, wxNORMAL, \      wxBLACK_PEN, wxBLACK, wxSOLID, wxCROSS_HATCH, wxSWISS, wxNORMAL, \
26      wxBitmapFromImage, wxImageFromStream, wxBITMAP_TYPE_BMP      wxBitmapFromImage, wxImageFromStream, wxBITMAP_TYPE_BMP, \
27        wxBITMAP_TYPE_JPEG, wxBITMAP_TYPE_PNG, wxBITMAP_TYPE_TIF, \
28        wxBITMAP_TYPE_GIF, wxEmptyImage, wxMask, wxBitmapFromBits
29    
30  from wxproj import draw_polygon_shape, draw_polygon_init  from wxproj import draw_polygon_shape, draw_polygon_init
31    
# Line 32  import Thuban.Model.resource Line 41  import Thuban.Model.resource
41    
42  from baserenderer import BaseRenderer  from baserenderer import BaseRenderer
43    
44    from math import floor
45    
46    from types import StringType
47    
48    from Thuban.version import versions
49    
50    if Thuban.Model.resource.has_gdal_support():
51        from gdalwarp import ProjectRasterFile
52    
53    
54    # Map the strings used for the format parameter of the draw_raster_data
55    # method to the appropriate wxWindows constants
56    raster_format_map = {
57        "BMP": wxBITMAP_TYPE_BMP,
58        "JPEG": wxBITMAP_TYPE_JPEG,
59        "PNG": wxBITMAP_TYPE_PNG,
60        "TIFF": wxBITMAP_TYPE_TIF,
61        "GIF": wxBITMAP_TYPE_GIF,
62        }
63    
64  class MapRenderer(BaseRenderer):  class MapRenderer(BaseRenderer):
65    
66      """Class to render a map onto a wxDC"""      """Class to render a map onto a wxDC"""
# Line 39  class MapRenderer(BaseRenderer): Line 68  class MapRenderer(BaseRenderer):
68      TRANSPARENT_PEN = wxTRANSPARENT_PEN      TRANSPARENT_PEN = wxTRANSPARENT_PEN
69      TRANSPARENT_BRUSH = wxTRANSPARENT_BRUSH      TRANSPARENT_BRUSH = wxTRANSPARENT_BRUSH
70    
71      make_point = wxPoint      def make_point(self, x, y):
72            return wxPoint(int(round(x)), int(round(y)))
73    
74      def tools_for_property(self, prop):      def tools_for_property(self, prop):
75          fill = prop.GetFill()          fill = prop.GetFill()
# Line 69  class MapRenderer(BaseRenderer): Line 99  class MapRenderer(BaseRenderer):
99          if (layer.ShapeStore().RawShapeFormat() == RAW_SHAPEFILE          if (layer.ShapeStore().RawShapeFormat() == RAW_SHAPEFILE
100              and layer.ShapeType() in (SHAPETYPE_ARC, SHAPETYPE_POLYGON)):              and layer.ShapeType() in (SHAPETYPE_ARC, SHAPETYPE_POLYGON)):
101              offx, offy = self.offset              offx, offy = self.offset
102                x = lambda a, b, c, d: None
103                #return (True, x, None)
104              return (True, draw_polygon_shape,              return (True, draw_polygon_shape,
105                      draw_polygon_init(layer.ShapeStore().Shapefile(),                      draw_polygon_init(layer.ShapeStore().Shapefile(),
106                                        self.dc, self.map.projection,                                        self.dc, self.map.projection,
# Line 78  class MapRenderer(BaseRenderer): Line 110  class MapRenderer(BaseRenderer):
110              return BaseRenderer.low_level_renderer(self, layer)              return BaseRenderer.low_level_renderer(self, layer)
111    
112      def label_font(self):      def label_font(self):
113          return wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)          return wxFont(int(round(self.resolution * 10)), wxSWISS, wxNORMAL,
114                          wxNORMAL)
115    
116        def projected_raster_layer(self, layer, srcProj, dstProj, extents,
117                                   resolution, dimensions, options):
118    
119            ret = None
120    
121            if Thuban.Model.resource.has_gdal_support():
122    
123                if versions['wxPython-tuple'] < (2,5,3):
124                    options = options | 4  # INVERT_MASK_BITS
125                    options = options & ~2 # ALPHA_MASK not supported
126    
127                try:
128                    ret = ProjectRasterFile(layer.GetImageFilename(),
129                                            srcProj, dstProj,
130                                            extents, resolution, dimensions,
131                                            options)
132                except (MemoryError, IOError, AttributeError, ValueError):
133                    # Why does this catch AttributeError and ValueError?
134                    # FIXME: The exception should be communicated to the user
135                    # better.
136                    traceback.print_exc()
137    
138            return ret
139    
140        def draw_raster_data(self, layer, x,y, data, format = 'BMP'):
141    
142            mask = None
143            alpha = None
144            width = data[0]
145            height = data[1]
146            image_data, mask_data, alpha_data = data[2]
147    
148            if versions['wxPython-tuple'] < (2,5,3):
149                alpha_data = None
150    
151            if format == 'RAW':
152                image = wxEmptyImage(width, height)
153                image.SetData(image_data)
154                if mask_data is not None:
155                    mask = wxBitmapFromBits(mask_data, width, height, 1)
156                    mask = wxMask(mask)
157                elif alpha_data is not None:
158                    # alpha_data is already in the right format
159                    alpha = alpha_data
160    
161            else:
162                stream = cStringIO.StringIO(image_data)
163                image = wxImageFromStream(stream, raster_format_map[format])
164                if mask_data is not None:
165                    stream = cStringIO.StringIO(mask_data)
166                    mask = wxImageFromStream(stream, raster_format_map[format])
167                    mask = wxMask(wxBitmapFromImage(mask, 1))
168                elif alpha_data is not None:
169                    stream = cStringIO.StringIO(alpha_data)
170                    alpha = wxImageFromStream(stream, raster_format_map[format])
171                    alpha = alpha.GetData()[:] # XXX: do we need to copy this?
172    
173            #
174            # if we are using the alpha_data then scale down the alpha values
175            # by the layer's opacity using a string translation table
176            #
177            if alpha is not None:
178                lo = layer.Opacity()
179                if lo == 0:
180                    return
181                elif lo == 1:
182                    a = alpha
183                else:
184                    tr = [int(i*lo) for i in range(256)]
185                    table = array.array('B', tr).tostring()
186                    a = alpha.translate(table)
187    
188                image.SetAlphaData(a)
189    
     def draw_raster_data(self, data):  
         stream = cStringIO.StringIO(data)  
         image = wxImageFromStream(stream, wxBITMAP_TYPE_BMP)  
190          bitmap = wxBitmapFromImage(image)          bitmap = wxBitmapFromImage(image)
191          self.dc.DrawBitmap(bitmap, 0, 0)  
192            if mask is not None:
193                bitmap.SetMask(mask)
194    
195            self.dc.DrawBitmap(bitmap, int(round(x)), int(round(y)), True)
196    
197    
198  class ScreenRenderer(MapRenderer):  class ScreenRenderer(MapRenderer):
# Line 92  class ScreenRenderer(MapRenderer): Line 200  class ScreenRenderer(MapRenderer):
200      # On the screen we want to see only visible layers by default      # On the screen we want to see only visible layers by default
201      honor_visibility = 1      honor_visibility = 1
202    
203      def RenderMap(self, map, region, selected_layer, selected_shapes):      def RenderMap(self, selected_layer, selected_shapes):
204          """Render the map.          """Render the map.
205    
206          Only the given region (a tuple in window coordinates as returned          Only the given region (a tuple in window coordinates as returned
# Line 100  class ScreenRenderer(MapRenderer): Line 208  class ScreenRenderer(MapRenderer):
208          shapes given by the ids in selected_shapes in the          shapes given by the ids in selected_shapes in the
209          selected_layer.          selected_layer.
210          """          """
         self.update_region = region  
211          self.selected_layer = selected_layer          self.selected_layer = selected_layer
212          self.selected_shapes = selected_shapes          self.selected_shapes = selected_shapes
213          self.render_map(map)          self.render_map()
214    
215        def RenderMapIncrementally(self):
216            """Render the map.
217    
218            Only the given region (a tuple in window coordinates as returned
219            by a wxrect's asTuple method) needs to be redrawn. Highlight the
220            shapes given by the ids in selected_shapes in the
221            selected_layer.
222            """
223            return self.render_map_incrementally()
224    
225        def draw_selection_incrementally(self, layer, selected_shapes):
226            """Draw the selected shapes in a emphasized way (i.e.
227            with a special pen and brush.
228            The drawing is performed incrementally, that means every
229            n shapes, the user can have interactions with the map.
230            n is currently fixed to 500.
231    
232            layer -- the layer where the shapes belong to.
233            selected_shapes -- a list of the shape-ids representing the
234                               selected shapes for the given layer.
235            """
236            pen = wxPen(wxBLACK, 3, wxSOLID)
237            brush = wxBrush(wxBLACK, wxCROSS_HATCH)
238    
239      def draw_shape_layer(self, layer):          shapetype = layer.ShapeType()
240          MapRenderer.draw_shape_layer(self, layer)          useraw, func, param = self.low_level_renderer(layer)
241          if layer is self.selected_layer and self.selected_shapes:          args = (pen, brush)
242              pen = wxPen(wxBLACK, 3, wxSOLID)  
243              brush = wxBrush(wxBLACK, wxCROSS_HATCH)          # for point shapes we need to find out the properties
244            # to determine the size. Based on table and field,
245              shapetype = layer.ShapeType()          # we can find out the properties for object - see below.
246              useraw, func, param = self.low_level_renderer(layer)          if shapetype == SHAPETYPE_POINT:
247              args = (pen, brush)              lc = layer.GetClassification()
248              for index in self.selected_shapes:              field = layer.GetClassificationColumn()
249                  shape = layer.Shape(index)              table = layer.ShapeStore().Table()
250                  if useraw:  
251                      data = shape.RawData()          count = 0
252                  else:          for index in selected_shapes:
253                      data = shape.Points()              count += 1
254                  func(param, data, *args)              shape = layer.Shape(index)
255    
256                # Get the size of the specific property for this
257                # point
258                if shapetype == SHAPETYPE_POINT and field is not None:
259                    value = table.ReadValue(shape.ShapeID(), field)
260                    group = lc.FindGroup(value)
261                    size = group.GetProperties().GetSize()
262                    args = (pen, brush, size)
263    
264                if useraw:
265                    data = shape.RawData()
266                else:
267                    data = shape.Points()
268                func(param, data, *args)
269                if count % 500 == 0:
270                    yield True
271    
272      def layer_ids(self, layer):      def layer_shapes(self, layer):
273          """Return the shapeids covered by the region that has to be redrawn          """Return the shapeids covered by the region that has to be redrawn
274    
275          Call the layer's ShapesInRegion method to determine the ids so          Call the layer's ShapesInRegion method to determine the ids so
# Line 143  class ScreenRenderer(MapRenderer): Line 290  class ScreenRenderer(MapRenderer):
290          offx, offy = self.offset          offx, offy = self.offset
291          xs = []          xs = []
292          ys = []          ys = []
293          x, y, width, height = self.update_region          x, y, width, height = self.region
294          for winx, winy in ((x, y), (x + width, y),          for winx, winy in ((x, y), (x + width, y),
295                             (x + width, y + height), (x, y + height)):                             (x + width, y + height), (x, y + height)):
296              px = (winx - offx) / scale              px = (winx - offx) / scale
# Line 164  class ExportRenderer(ScreenRenderer): Line 311  class ExportRenderer(ScreenRenderer):
311    
312      honor_visibility = 1      honor_visibility = 1
313    
314      def RenderMap(self, map, region, mapregion,      def __init__(self, *args, **kw):
315                    selected_layer, selected_shapes ):          """Initialize the ExportRenderer.
316    
317            In addition to all parameters of the the ScreenRender
318            constructor, this class requires and additional keyword argument
319            destination_region with a tuple (minx, miny, maxx, maxy) giving
320            the region in dc coordinates which is to contain the map.
321            """
322            self.destination_region = kw["destination_region"]
323            del kw["destination_region"]
324            ScreenRenderer.__init__(self, *args, **kw)
325    
326        def RenderMap(self, selected_layer, selected_shapes):
327          """Render the map.          """Render the map.
328    
329          The rendering device has been specified during initialisation.          The rendering device has been specified during initialisation.
330          The device border distance was set in Thuban.UI.view.OutputTranform().          The device border distance was set in
331            Thuban.UI.viewport.output_transform().
332    
333          RenderMap renders a frame set (one page frame, one around          RenderMap renders a frame set (one page frame, one around
334          legend/scalebar and one around the map), the map, the legend and the          legend/scalebar and one around the map), the map, the legend and
335          scalebar on the given DC. The map is rendered with the region displayed          the scalebar on the given DC. The map is rendered with the
336          in the canvas view, centered on the area available for map display.          region displayed in the canvas view, centered on the area
337            available for map display.
338          """          """
339    
         self.update_region = region  
340          self.selected_layer = selected_layer          self.selected_layer = selected_layer
341          self.selected_shapes = selected_shapes          self.selected_shapes = selected_shapes
342    
343          # Get some dimensions          # Get some dimensions
344          llx, lly, urx, ury = region          llx, lly, urx, ury = self.region
345          self.mapregion = mapregion          mminx, mminy, mmaxx, mmaxy = self.destination_region
         mminx, mminy, mmaxx, mmaxy = self.mapregion  
346    
347          # Manipulate the offset to position the map          # Manipulate the offset to position the map
348          offx, offy = self.offset          offx, offy = self.offset
# Line 199  class ExportRenderer(ScreenRenderer): Line 357  class ExportRenderer(ScreenRenderer):
357          self.shifty = (mmaxy - mminy)*0.5 - (ury - lly)*0.5          self.shifty = (mmaxy - mminy)*0.5 - (ury - lly)*0.5
358    
359          self.offset = (offx+self.shiftx, offy+self.shifty)          self.offset = (offx+self.shiftx, offy+self.shifty)
360            self.region = (llx + self.shiftx, lly + self.shifty, urx, ury)
361    
362          # Draw the map          # Draw the map
363          self.dc.BeginDrawing()          self.dc.BeginDrawing()
364          self.dc.DestroyClippingRegion()          self.dc.DestroyClippingRegion()
365          self.dc.SetClippingRegion(mminx+self.shiftx, mminy+self.shifty,          self.dc.SetClippingRegion(mminx+self.shiftx, mminy+self.shifty,
366                                    urx, ury)                                    urx, ury)
367          self.render_map(map)          self.render_map()
368          self.dc.EndDrawing()          self.dc.EndDrawing()
369    
370          # Draw the rest (frames, legend, scalebar)          # Draw the rest (frames, legend, scalebar)
# Line 216  class ExportRenderer(ScreenRenderer): Line 375  class ExportRenderer(ScreenRenderer):
375          font = wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)          font = wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)
376          self.dc.SetFont(font)          self.dc.SetFont(font)
377    
378          self.render_frame(region)          self.render_frame()
379          self.render_legend(map)          self.render_legend()
380          self.render_scalebar(map)          self.render_scalebar()
381          self.dc.EndDrawing()          self.dc.EndDrawing()
382    
383      def render_frame(self, region):      def render_frame(self):
384          """Render the frames for map and legend/scalebar."""          """Render the frames for map and legend/scalebar."""
385    
386          dc = self.dc          dc = self.dc
# Line 230  class ExportRenderer(ScreenRenderer): Line 389  class ExportRenderer(ScreenRenderer):
389    
390          # Dimension stuff          # Dimension stuff
391          width, height = dc.GetSizeTuple()          width, height = dc.GetSizeTuple()
392          mminx, mminy, mmaxx, mmaxy = self.mapregion          mminx, mminy, mmaxx, mmaxy = self.destination_region
393    
394          # Page Frame          # Page Frame
395          dc.DrawRectangle(15,15,width-30, (mmaxy-mminy)+10)          dc.DrawRectangle(15,15,width-30, (mmaxy-mminy)+10)
396    
397          # Map Frame          # Map Frame
398          llx, lly, urx, ury = region          llx, lly, urx, ury = self.region
399          dc.DrawRectangle(mminx + self.shiftx, mminy + self.shifty, urx, ury)          dc.DrawRectangle(mminx + self.shiftx, mminy + self.shifty, urx, ury)
400    
401          # Legend Frame          # Legend Frame
# Line 246  class ExportRenderer(ScreenRenderer): Line 405  class ExportRenderer(ScreenRenderer):
405          dc.SetClippingRegion(mmaxx+10,mminy,          dc.SetClippingRegion(mmaxx+10,mminy,
406                               (width-20) - (mmaxx+10), mmaxy-mminy)                               (width-20) - (mmaxx+10), mmaxy-mminy)
407    
408      def render_legend(self, map):      def render_legend(self):
409          """Render the legend on the Map."""          """Render the legend on the Map."""
410    
411          previewer = ClassDataPreviewer()          previewer = ClassDataPreviewer()
# Line 256  class ExportRenderer(ScreenRenderer): Line 415  class ExportRenderer(ScreenRenderer):
415    
416          # Dimension stuff          # Dimension stuff
417          width, height = dc.GetSizeTuple()          width, height = dc.GetSizeTuple()
418          mminx, mminy, mmaxx, mmaxy = self.mapregion          mminx, mminy, mmaxx, mmaxy = self.destination_region
419          textwidth, textheight = dc.GetTextExtent("0")          textwidth, textheight = dc.GetTextExtent("0")
420          iconwidth  = textheight          iconwidth  = textheight
421          iconheight = textheight          iconheight = textheight
# Line 268  class ExportRenderer(ScreenRenderer): Line 427  class ExportRenderer(ScreenRenderer):
427    
428          # Render the legend          # Render the legend
429          dc.SetTextForeground(wxBLACK)          dc.SetTextForeground(wxBLACK)
430          if map.HasLayers():          if self.map.HasLayers():
431              layers = map.Layers()              layers = self.map.Layers()[:]
432              layers.reverse()              layers.reverse()
433              for l in layers:              for l in layers:
434                  if l.Visible():                  if l.Visible():
# Line 290  class ExportRenderer(ScreenRenderer): Line 449  class ExportRenderer(ScreenRenderer):
449                                              posx+2*dx+iconwidth, posy)                                              posx+2*dx+iconwidth, posy)
450                                  posy+=stepy                                  posy+=stepy
451    
452      def render_scalebar(self, map):      def render_scalebar(self):
453          """Render the scalebar."""          """Render the scalebar."""
454    
455          scalebar = ScaleBar(map)          scalebar = ScaleBar(self.map)
456    
457          # Dimension stuff          # Dimension stuff
458          width, height = self.dc.GetSizeTuple()          width, height = self.dc.GetSizeTuple()
459          mminx, mminy, mmaxx, mmaxy = self.mapregion          mminx, mminy, mmaxx, mmaxy = self.destination_region
460    
461          # Render the scalebar          # Render the scalebar
462          scalebar.DrawScaleBar(self.scale, self.dc,          scalebar.DrawScaleBar(self.scale, self.dc,

Legend:
Removed from v.1591  
changed lines
  Added in v.2587

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26