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

Legend:
Removed from v.290  
changed lines
  Added in v.1165

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26