/[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 394 by jonathan, Mon Feb 10 15:27:13 2003 UTC revision 938 by jonathan, Tue May 20 15:25:10 2003 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001, 2002 by Intevation GmbH  # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4    # 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, wxColour, 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 _
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
38    
39  class MapRenderer:  class MapRenderer:
40    
# Line 45  class MapRenderer: Line 58  class MapRenderer:
58                  the renderer's default.                  the renderer's default.
59          """          """
60          # resolution in pixel/inch          # resolution in pixel/inch
61    
62          self.dc = dc          self.dc = dc
63          self.scale = scale          self.scale = scale
64          self.offset = offset          self.offset = offset
# Line 56  class MapRenderer: Line 70  class MapRenderer:
70    
71      def render_map(self, map):      def render_map(self, map):
72          self.map = map          self.map = map
73            seenRaster = True
74    
75            #
76            # This is only a good optimization if there is only one
77            # raster layer and the image covers the entire window (as
78            # it currently does).
79            #
80            for layer in map.Layers():
81                if isinstance(layer, RasterLayer):
82                    seenRaster = False
83                    break
84    
85          for layer in map.Layers():          for layer in map.Layers():
86              # if honor_visibility is true, only draw visible layers,              # if honor_visibility is true, only draw visible layers,
87              # otherwise draw all layers              # otherwise draw all layers
88              if not self.honor_visibility or layer.Visible():              if not self.honor_visibility or layer.Visible():
89                  self.draw_shape_layer(layer)                  if isinstance(layer, Layer) and seenRaster:
90                        self.draw_shape_layer(layer)
91                    elif isinstance(layer, RasterLayer):
92                        self.draw_raster_layer(layer)
93                        seenRaster = True
94    
95          self.draw_label_layer(map.LabelLayer())          self.draw_label_layer(map.LabelLayer())
96    
97      def draw_shape_layer(self, layer):      def draw_shape_layer(self, layer):
# Line 76  class MapRenderer: Line 107  class MapRenderer:
107          pen   = wxTRANSPARENT_PEN          pen   = wxTRANSPARENT_PEN
108    
109          old_prop = None          old_prop = None
110            old_group = None
111            lc = layer.GetClassification()
112            field = lc.GetField()
113            defaultGroup = lc.GetDefaultGroup()
114    
115    
116            if shapetype != SHAPETYPE_POINT:
117                polygon_render_param = self.polygon_render_param(layer)
118    
119            if shapetype == SHAPETYPE_POINT:
120                draw_func = lambda i: \
121                       self.draw_point_shape(layer, i)
122            else:
123                draw_func = lambda i: \
124                       self.draw_polygon_shape(polygon_render_param, i, pen, brush)
125                
126          for i in self.layer_ids(layer):          for i in self.layer_ids(layer):
127              value = None  
128              shape = layer.Shape(i)              if field is None:
129              lc = layer.classification                  group = defaultGroup
             field = lc.field  
   
             if field is not None:  
                 record = layer.table.read_record(i)  
                 if record is not None:  
                     value = record[field]  
   
             #  
             # if the above statements fail 'value' should  
             # be null, at which point this call will  
             # at least retreive the NullData  
             #  
             prop = lc.GetProperties(value)  
   
             if prop != old_prop:  
                 old_prop = prop  
   
                 if shapetype == SHAPETYPE_ARC:  
                     fill = None  
                 else:  
                     fill = prop.GetFill()  
       
                 if fill is None:  
                     brush = wxTRANSPARENT_BRUSH  
                 else:  
                     color = wxColour(fill.red * 255,  
                                      fill.green * 255,  
                                      fill.blue * 255)  
                     brush = wxBrush(color, wxSOLID)  
       
                 stroke = prop.GetStroke()  
                 stroke_width = prop.GetStrokeWidth()  
                 if stroke is None:  
                     pen = wxTRANSPARENT_PEN  
                 else:  
                     color = wxColour(stroke.red * 255,  
                                      stroke.green * 255,  
                                      stroke.blue * 255)  
                     pen = wxPen(color, stroke_width, wxSOLID)  
       
             if shapetype == SHAPETYPE_POINT:  
                 self.dc.SetBrush(brush)  
                 self.dc.SetPen(pen)  
                 self.draw_point_shape(layer, i)  
130              else:              else:
131                  self.draw_polygon_shape(layer, i, pen, brush)                  record = layer.table.ReadRowAsDict(i)
132                    assert record is not None
133                    group = lc.FindGroup(record[field])
134    
135    
136                if not group.IsVisible():
137                    continue
138    
139    
140                # don't recreate new objects if they are the same as before
141                if group is not old_group:
142                    old_group = group
143    
144                    prop = group.GetProperties()
145    
146                    if prop != old_prop:
147                        old_prop = prop
148    
149                        if shapetype == SHAPETYPE_ARC:
150                            fill = Color.Transparent
151                        else:
152                            fill = prop.GetFill()
153    
154    
155                        if fill is Color.Transparent:
156                            brush = wxTRANSPARENT_BRUSH
157                        else:
158                            color = Color2wxColour(fill)
159                            brush = wxBrush(color, wxSOLID)
160    
161                        stroke = prop.GetLineColor()
162                        stroke_width = prop.GetLineWidth()
163                        if stroke is Color.Transparent:
164                            pen = wxTRANSPARENT_PEN
165                        else:
166                            color = Color2wxColour(stroke)
167                            pen = wxPen(color, stroke_width, wxSOLID)
168    
169                        if shapetype == SHAPETYPE_POINT:
170                            self.dc.SetBrush(brush)
171                            self.dc.SetPen(pen)
172    
173                draw_func(i)
174    
175        def draw_raster_layer(self, layer):
176            data = None
177            offx, offy = self.offset
178            width, height = self.dc.GetSizeTuple()
179    
180            inProj = ""
181            proj = layer.GetProjection()
182            if proj is not None:
183                for p in proj.GetAllParameters():
184                    inProj += "+" + p + " "
185    
186            outProj = ""
187            proj = self.map.GetProjection()
188            if proj is not None:
189                for p in proj.GetAllParameters():
190                    outProj += "+" + p + " "
191    
192            print "self.scale: ", self.scale, offx, offy, width, height
193            xmin = (0 - offx) / self.scale
194            ymin = (offy - height) / self.scale
195            xmax = (width - offx) / self.scale
196            ymax = (offy - 0) / self.scale
197    
198            try:
199                data = ProjectRasterFile(
200                    layer.GetImageFilename(),
201                    inProj,
202                    outProj,
203                    str(xmin), str(ymin), str(xmax), str(ymax),
204                    "", str(width), str(height));
205            except (AttributeError, IOError, ValueError):
206                pass
207            else:
208                if data is not None:
209                    stream = cStringIO.StringIO(data)
210                    image = wxImageFromStream(stream, wxBITMAP_TYPE_BMP)
211                    bitmap = wxBitmapFromImage(image)
212                    self.dc.BeginDrawing()
213                    self.dc.DrawBitmap(bitmap, 0, 0)
214                    self.dc.EndDrawing()
215    
216      def layer_ids(self, layer):      def layer_ids(self, layer):
217          """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.
218            
219          The default implementation simply returns all ids in the layer.          The default implementation simply returns all ids in the layer.
220          Override in derived classes to be more precise.          Override in derived classes to be more precise.
221          """          """
222          return range(layer.NumShapes())          return range(layer.NumShapes())
223    
224      def draw_polygon_shape(self, layer, index, pen, brush):      def polygon_render_param(self, layer):
225          offx, offy = self.offset                  """Return the low-lever render parameter for the layer"""
226          draw_polygon_shape(layer.shapefile.cobject(), index,          offx, offy = self.offset
227                             self.dc, pen, brush,          return draw_polygon_init(layer.shapefile, self.dc,
228                             self.map.projection, layer.projection,                                   self.map.projection,
229                             self.scale, -self.scale, offx, offy)                                   layer.projection,
230                                     self.scale, -self.scale,
231                                     offx, offy)
232    
233        def draw_polygon_shape(self, draw_polygon_info, index, pen, brush):
234            draw_polygon_shape(draw_polygon_info, index, pen, brush)
235    
236      def projected_points(self, layer, index):      def projected_points(self, layer, index):
237          proj = self.map.projection          proj = self.map.GetProjection()
238          if proj is not None:          if proj is not None:
239              forward = proj.Forward              forward = proj.Forward
240          else:          else:
241              forward = None              forward = None
242          proj = layer.projection          proj = layer.GetProjection()
243          if proj is not None:          if proj is not None:
244              inverse = proj.Inverse              inverse = proj.Inverse
245          else:          else:
# Line 171  class MapRenderer: Line 262  class MapRenderer:
262          self.dc.DrawLines(points)          self.dc.DrawLines(points)
263    
264      def draw_point_shape(self, layer, index):      def draw_point_shape(self, layer, index):
265          p = self.projected_points(layer, index)[0]          pp = self.projected_points(layer, index)
266    
267            if len(pp) == 0: return # ignore Null Shapes which have no points
268    
269            p = pp[0]
270          radius = self.resolution * 5          radius = self.resolution * 5
271          self.dc.DrawEllipse(p.x - radius, p.y - radius, 2*radius, 2*radius)          self.dc.DrawEllipse(p.x - radius, p.y - radius, 2*radius, 2*radius)
272    
# Line 219  class ScreenRenderer(MapRenderer): Line 314  class ScreenRenderer(MapRenderer):
314      # On the screen we want to see only visible layers by default      # On the screen we want to see only visible layers by default
315      honor_visibility = 1      honor_visibility = 1
316            
317      def RenderMap(self, map, region, selected_layer, selected_shape):      def RenderMap(self, map, region, selected_layer, selected_shapes):
318          """Render the map.          """Render the map.
319    
320          Only the given region (a tuple in window coordinates as returned          Only the given region (a tuple in window coordinates as returned
321          by a wxrect's asTuple method) needs to be redrawn. Highlight the          by a wxrect's asTuple method) needs to be redrawn. Highlight the
322          shape with id selected_shape in the selected_layer.          shapes given by the ids in selected_shapes in the
323            selected_layer.
324          """          """
325          self.update_region = region          self.update_region = region
326          self.selected_layer = selected_layer          self.selected_layer = selected_layer
327          self.selected_shape = selected_shape          self.selected_shapes = selected_shapes
328          self.render_map(map)          self.render_map(map)
329    
330      def draw_shape_layer(self, layer):      def draw_shape_layer(self, layer):
331          MapRenderer.draw_shape_layer(self, layer)          MapRenderer.draw_shape_layer(self, layer)
332          if layer is self.selected_layer and self.selected_shape is not None:          if layer is self.selected_layer and self.selected_shapes:
333              pen = wxPen(wxBLACK, 3, wxSOLID)              pen = wxPen(wxBLACK, 3, wxSOLID)
334              brush = wxBrush(wxBLACK, wxCROSS_HATCH)              brush = wxBrush(wxBLACK, wxCROSS_HATCH)
335                
336              shapetype = layer.ShapeType()              shapetype = layer.ShapeType()
             index = self.selected_shape  
337              if shapetype == SHAPETYPE_POLYGON:              if shapetype == SHAPETYPE_POLYGON:
338                  self.draw_polygon_shape(layer, index, pen, brush)                  offx, offy = self.offset
339                    renderparam = self.polygon_render_param(layer)
340                    func = self.draw_polygon_shape
341                    args = (pen, brush)
342              elif shapetype == SHAPETYPE_ARC:              elif shapetype == SHAPETYPE_ARC:
343                  self.draw_polygon_shape(layer, index, pen, None)                  renderparam = self.polygon_render_param(layer)
344              else:                  func = self.draw_polygon_shape
345                    args = (pen, None)
346                elif shapetype == SHAPETYPE_POINT:
347                    renderparam = layer
348                  self.dc.SetBrush(brush)                  self.dc.SetBrush(brush)
349                  self.dc.SetPen(pen)                  self.dc.SetPen(pen)
350                  if shapetype == SHAPETYPE_POINT:                  func = self.draw_point_shape
351                      self.draw_point_shape(layer, index)                  args = ()
352                  else:              else:
353                      raise TypeError(_("Unhandled shape type %s") % shapetype)                  raise TypeError(_("Unhandled shape type %s") % shapetype)
354    
355                for index in self.selected_shapes:
356                    func(renderparam, index, *args)
357    
358    
359      def layer_ids(self, layer):      def layer_ids(self, layer):
360          """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 289  class ScreenRenderer(MapRenderer): Line 394  class ScreenRenderer(MapRenderer):
394          return layer.ShapesInRegion((left, bottom, right, top))          return layer.ShapesInRegion((left, bottom, right, top))
395    
396    
397  class PrinterRender(MapRenderer):  class ExportRenderer(ScreenRenderer):
398    
399      # When printing we want to see all layers      honor_visibility = 1
     honor_visibility = 0  
   
     RenderMap = MapRenderer.render_map  
400            
401        def RenderMap(self, map, region, mapregion,
402                      selected_layer, selected_shapes ):
403            """Render the map.
404    
405            The rendering device has been specified during initialisation.
406            The device border distance was set in Thuban.UI.view.OutputTranform().
407            
408            RenderMap renders a frame set (one page frame, one around
409            legend/scalebar and one around the map), the map, the legend and the
410            scalebar on the given DC. The map is rendered with the region displayed
411            in the canvas view, centered on the area available for map display.
412            """
413            
414            self.update_region = region
415            self.selected_layer = selected_layer
416            self.selected_shapes = selected_shapes
417    
418            # Get some dimensions
419            llx, lly, urx, ury = region
420            self.mapregion = mapregion
421            mminx, mminy, mmaxx, mmaxy = self.mapregion
422    
423            # Manipulate the offset to position the map
424            offx, offy = self.offset
425            # 1. Shift to corner of map drawing area
426            offx = offx + mminx
427            offy = offy + mminy
428    
429            # 2. Center the map on the map drawing area:
430            # region identifies the region on the canvas view:
431            # center of map drawing area - half the size of region: rendering origin
432            self.shiftx = (mmaxx - mminx)*0.5 - (urx - llx)*0.5
433            self.shifty = (mmaxy - mminy)*0.5 - (ury - lly)*0.5
434    
435            self.offset = (offx+self.shiftx, offy+self.shifty)
436    
437            # Draw the map
438            self.dc.BeginDrawing()
439            self.dc.DestroyClippingRegion()
440            self.dc.SetClippingRegion(mminx+self.shiftx, mminy+self.shifty,
441                                      urx, ury)
442            self.render_map(map)
443            self.dc.EndDrawing()
444    
445            # Draw the rest (frames, legend, scalebar)
446            self.dc.BeginDrawing()
447            self.dc.DestroyClippingRegion()
448    
449            # Force the font for Legend drawing
450            font = wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)
451            self.dc.SetFont(font)
452    
453            self.render_frame(region)
454            self.render_legend(map)
455            self.render_scalebar(map)
456            self.dc.EndDrawing()
457    
458        def render_frame(self, region):
459            """Render the frames for map and legend/scalebar."""
460    
461            dc = self.dc
462            dc.SetPen(wxBLACK_PEN)
463            dc.SetBrush(wxTRANSPARENT_BRUSH)
464    
465            # Dimension stuff
466            width, height = dc.GetSizeTuple()
467            mminx, mminy, mmaxx, mmaxy = self.mapregion
468    
469            # Page Frame
470            dc.DrawRectangle(15,15,width-30, (mmaxy-mminy)+10)
471            
472            # Map Frame
473            llx, lly, urx, ury = region
474            dc.DrawRectangle(mminx + self.shiftx, mminy + self.shifty, urx, ury)
475            
476            # Legend Frame
477            dc.DrawRectangle(mmaxx+10,mminy,(width-20) - (mmaxx+10), mmaxy-mminy)
478    
479            dc.DestroyClippingRegion()
480            dc.SetClippingRegion(mmaxx+10,mminy,
481                                 (width-20) - (mmaxx+10), mmaxy-mminy)
482    
483        def render_legend(self, map):
484            """Render the legend on the Map."""
485    
486            previewer = ClassDataPreviewer()
487            dc = self.dc
488            dc.SetPen(wxBLACK_PEN)
489            dc.SetBrush(wxTRANSPARENT_BRUSH)
490    
491            # Dimension stuff
492            width, height = dc.GetSizeTuple()
493            mminx, mminy, mmaxx, mmaxy = self.mapregion
494            textwidth, textheight = dc.GetTextExtent("0")
495            iconwidth  = textheight
496            iconheight = textheight
497            stepy = textheight+3
498            dx = 10
499            posx = mmaxx + 10 + 5   # 10 pix distance mapframe/legend frame,
500                                    # 5 pix inside legend frame
501            posy = mminy + 5        # 5 pix inside legend frame
502            
503            # Render the legend
504            dc.SetTextForeground(wxBLACK)
505            if map.HasLayers():
506                for l in map.Layers():
507                    if l.Visible():
508                        # Render title
509                        dc.DrawText(l.Title(), posx, posy)
510                        posy+=stepy
511                        # Render classification
512                        clazz = l.GetClassification()
513                        shapeType = l.ShapeType()
514                        for g in clazz:
515                            if g.IsVisible():
516                                previewer.Draw(dc,
517                                    wxRect(posx+dx, posy, iconwidth, iconheight),
518                                    g.GetProperties(), shapeType)
519                                dc.DrawText(g.GetDisplayText(),
520                                            posx+2*dx+iconwidth, posy)
521                                posy+=stepy
522            
523        def render_scalebar(self, map):
524            """Render the scalebar."""
525    
526            scalebar = ScaleBar(map)
527    
528            # Dimension stuff
529            width, height = self.dc.GetSizeTuple()
530            mminx, mminy, mmaxx, mmaxy = self.mapregion
531          
532            # Render the scalebar
533            scalebar.DrawScaleBar(self.scale, self.dc,
534                                 (mmaxx+10+5, mmaxy-25),
535                                 ((width-15-5) - (mmaxx+10+5),20)
536                                )
537            # 10 pix between map and legend frame, 5 pix inside legend frame
538            # 25 pix from the legend frame bottom line
539            # Width: 15 pix from DC border, 5 pix inside frame, 10, 5 as above
540            # Height: 20
541    
542    class PrinterRenderer(ExportRenderer):
543    
544        # Printing as well as Export / Screen display only the visible layer.
545        honor_visibility = 1
546    

Legend:
Removed from v.394  
changed lines
  Added in v.938

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26