/[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 686 by bh, Wed Apr 16 13:22:25 2003 UTC revision 1539 by bh, Fri Aug 1 14:27:57 2003 UTC
# Line 2  Line 2 
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  # Jonathan Coles <[email protected]>  # 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, wxPen, wxBrush, wxFont, \  import cStringIO
13       wxTRANSPARENT_PEN, wxTRANSPARENT_BRUSH, \  
14       wxBLACK, wxSOLID, wxCROSS_HATCH, wxSWISS, wxNORMAL  from Thuban import _
15    
16    from wxPython.wx import wxMemoryDC, wxEmptyBitmap, \
17        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  from wxproj import draw_polygon_shape, draw_polygon_init
25    
26  from Thuban import _  from Thuban.UI.common import Color2wxColour
27  from Thuban.UI.common import *  from Thuban.UI.classifier import ClassDataPreviewer
28    from Thuban.UI.scalebar import ScaleBar
29    
30  from Thuban.Model.layer import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \  from Thuban.Model.layer import Layer, RasterLayer
31       SHAPETYPE_POINT  from Thuban.Model.data import SHAPETYPE_POLYGON, SHAPETYPE_ARC, SHAPETYPE_POINT
32  from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \  from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \
33       ALIGN_LEFT, ALIGN_RIGHT, ALIGN_BASELINE       ALIGN_LEFT, ALIGN_RIGHT, ALIGN_BASELINE
34    
35  from Thuban.Model.classification import Classification  from Thuban.Model.classification import Classification
36  from Thuban.Model.color import Color  from Thuban.Model.color import Transparent
37    import Thuban.Model.resource
38    
39    if Thuban.Model.resource.has_gdal_support():
40        from gdalwarp import ProjectRasterFile
41    
42  class MapRenderer:  class MapRenderer:
43    
# Line 49  class MapRenderer: Line 62  class MapRenderer:
62          """          """
63          # resolution in pixel/inch          # resolution in pixel/inch
64    
         assert scale > 0  
   
65          self.dc = dc          self.dc = dc
66          self.scale = scale          self.scale = scale
67          self.offset = offset          self.offset = offset
# Line 62  class MapRenderer: Line 73  class MapRenderer:
73    
74      def render_map(self, map):      def render_map(self, map):
75          self.map = map          self.map = map
76            seenRaster = True
77    
78            self.dc.BeginDrawing()
79    
80            #
81            # This is only a good optimization if there is only one
82            # raster layer and the image covers the entire window (as
83            # it currently does). We note if there is a raster layer
84            # and only begin drawing layers once we have drawn it.
85            # That way we avoid drawing layers that won't be seen.
86            #
87            if Thuban.Model.resource.has_gdal_support():
88                for layer in map.Layers():
89                    if isinstance(layer, RasterLayer) and layer.Visible():
90                        seenRaster = False
91                        break
92    
93          for layer in map.Layers():          for layer in map.Layers():
94              # if honor_visibility is true, only draw visible layers,              # if honor_visibility is true, only draw visible layers,
95              # otherwise draw all layers              # otherwise draw all layers
96              if not self.honor_visibility or layer.Visible():              if not self.honor_visibility or layer.Visible():
97                  self.draw_shape_layer(layer)                  if isinstance(layer, Layer) and seenRaster:
98                        self.draw_shape_layer(layer)
99                    elif isinstance(layer, RasterLayer) \
100                        and Thuban.Model.resource.has_gdal_support():
101                        self.draw_raster_layer(layer)
102                        seenRaster = True
103    
104          self.draw_label_layer(map.LabelLayer())          self.draw_label_layer(map.LabelLayer())
105    
106            self.dc.EndDrawing()
107    
108      def draw_shape_layer(self, layer):      def draw_shape_layer(self, layer):
109          scale = self.scale          scale = self.scale
110          offx, offy = self.offset          offx, offy = self.offset
# Line 82  class MapRenderer: Line 118  class MapRenderer:
118          pen   = wxTRANSPARENT_PEN          pen   = wxTRANSPARENT_PEN
119    
120          old_prop = None          old_prop = None
121            old_group = None
122          lc = layer.GetClassification()          lc = layer.GetClassification()
123          field = lc.GetField()          field = layer.GetClassificationColumn()
124            defaultGroup = lc.GetDefaultGroup()
125    
126    
         if shapetype != SHAPETYPE_POINT:  
             polygon_render_param = self.polygon_render_param(layer)  
127    
128          for i in self.layer_ids(layer):          if shapetype == SHAPETYPE_POINT:
129              value = None              draw_func = self.draw_point_shape
130                draw_func_param = layer
131              if field is not None:          else:
132                  try:              draw_func = draw_polygon_shape
133                      record = layer.table.read_record(i)              draw_func_param = self.polygon_render_param(layer)
                     if record is not None:  
                         value = record[field]  
                 except:  
                     pass  
   
                 #  
                 # if the above statements fail 'value' should  
                 # be null, at which point this call will  
                 # at least retreive the NullData  
                 #  
134    
135                  group = lc.FindGroup(value)          table = layer.ShapeStore().Table()
136            for i in self.layer_ids(layer):
137    
138                  #prop = lc.GetProperties(value)              if field is None:
139                    group = defaultGroup
140              else:              else:
141                  group = lc.GetDefaultGroup()                  record = table.ReadRowAsDict(i)
142                    assert record is not None
143                    group = lc.FindGroup(record[field])
144    
145    
146              if not group.IsVisible():              if not group.IsVisible():
147                  continue                  continue
148    
             prop = group.GetProperties()  
149    
150              # don't recreate new objects if they are the same as before              # don't recreate new objects if they are the same as before
151              if prop != old_prop:              if group is not old_group:
152                  old_prop = prop                  old_group = group
153    
154                  if shapetype == SHAPETYPE_ARC:                  prop = group.GetProperties()
155                      fill = Color.Transparent  
156                  else:                  if prop != old_prop:
157                      fill = prop.GetFill()                      old_prop = prop
158    
159                        if shapetype == SHAPETYPE_ARC:
160                  if fill is Color.Transparent:                          fill = Transparent
161                      brush = wxTRANSPARENT_BRUSH                      else:
162                  else:                          fill = prop.GetFill()
163                      color = Color2wxColour(fill)  
164                      brush = wxBrush(color, wxSOLID)  
165                        if fill is Transparent:
166                  stroke = prop.GetLineColor()                          brush = wxTRANSPARENT_BRUSH
167                  stroke_width = prop.GetLineWidth()                      else:
168                  if stroke is Color.Transparent:                          color = Color2wxColour(fill)
169                      pen = wxTRANSPARENT_PEN                          brush = wxBrush(color, wxSOLID)
170                  else:  
171                      color = Color2wxColour(stroke)                      stroke = prop.GetLineColor()
172                      pen = wxPen(color, stroke_width, wxSOLID)                      stroke_width = prop.GetLineWidth()
173                        if stroke is Transparent:
174                            pen = wxTRANSPARENT_PEN
175              if shapetype == SHAPETYPE_POINT:                      else:
176                  self.dc.SetBrush(brush)                          color = Color2wxColour(stroke)
177                  self.dc.SetPen(pen)                          pen = wxPen(color, stroke_width, wxSOLID)
178                  self.draw_point_shape(layer, i)  
179              else:              draw_func(draw_func_param, i, pen, brush)
180                  self.draw_polygon_shape(polygon_render_param, i, pen, brush)  
181        def draw_raster_layer(self, layer):
182            data = None
183            offx, offy = self.offset
184            width, height = self.dc.GetSizeTuple()
185    
186            inProj = ""
187            proj = layer.GetProjection()
188            if proj is not None:
189                for p in proj.GetAllParameters():
190                    inProj += "+" + p + " "
191    
192            outProj = ""
193            proj = self.map.GetProjection()
194            if proj is not None:
195                for p in proj.GetAllParameters():
196                    outProj += "+" + p + " "
197    
198            xmin = (0 - offx) / self.scale
199            ymin = (offy - height) / self.scale
200            xmax = (width - offx) / self.scale
201            ymax = (offy - 0) / self.scale
202    
203            try:
204                data = ProjectRasterFile(
205                    layer.GetImageFilename(),
206                    inProj,
207                    outProj,
208                    (xmin, ymin, xmax, ymax),
209                    "", (width, height))
210            except IOError, (strerr):
211                print strerr
212            except (AttributeError, ValueError):
213                pass
214            else:
215                if data is not None:
216                    stream = cStringIO.StringIO(data)
217                    image = wxImageFromStream(stream, wxBITMAP_TYPE_BMP)
218                    bitmap = wxBitmapFromImage(image)
219                    self.dc.DrawBitmap(bitmap, 0, 0)
220    
221      def layer_ids(self, layer):      def layer_ids(self, layer):
222          """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.
# Line 161  class MapRenderer: Line 229  class MapRenderer:
229      def polygon_render_param(self, layer):      def polygon_render_param(self, layer):
230          """Return the low-lever render parameter for the layer"""          """Return the low-lever render parameter for the layer"""
231          offx, offy = self.offset          offx, offy = self.offset
232          return draw_polygon_init(layer.shapefile, self.dc,          return draw_polygon_init(layer.ShapeStore().Shapefile(), self.dc,
233                                   self.map.projection,                                   self.map.projection,
234                                   layer.projection,                                   layer.projection,
235                                   self.scale, -self.scale,                                   self.scale, -self.scale,
# Line 171  class MapRenderer: Line 239  class MapRenderer:
239          draw_polygon_shape(draw_polygon_info, index, pen, brush)          draw_polygon_shape(draw_polygon_info, index, pen, brush)
240    
241      def projected_points(self, layer, index):      def projected_points(self, layer, index):
242          proj = self.map.projection          proj = self.map.GetProjection()
243          if proj is not None:          if proj is not None:
244              forward = proj.Forward              forward = proj.Forward
245          else:          else:
246              forward = None              forward = None
247          proj = layer.projection          proj = layer.GetProjection()
248          if proj is not None:          if proj is not None:
249              inverse = proj.Inverse              inverse = proj.Inverse
250          else:          else:
# Line 198  class MapRenderer: Line 266  class MapRenderer:
266          points = self.projected_points(layer, index)          points = self.projected_points(layer, index)
267          self.dc.DrawLines(points)          self.dc.DrawLines(points)
268    
269      def draw_point_shape(self, layer, index):      def draw_point_shape(self, layer, index, pen, brush):
270          pp = self.projected_points(layer, index)          pp = self.projected_points(layer, index)
271    
272          if len(pp) == 0: return # ignore Null Shapes which have no points          if len(pp) == 0: return # ignore Null Shapes which have no points
273    
274          p = pp[0]          p = pp[0]
275          radius = self.resolution * 5          radius = self.resolution * 5
276            self.dc.SetBrush(brush)
277            self.dc.SetPen(pen)
278          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)
279    
280      def draw_label_layer(self, layer):      def draw_label_layer(self, layer):
# Line 282  class ScreenRenderer(MapRenderer): Line 352  class ScreenRenderer(MapRenderer):
352                  args = (pen, None)                  args = (pen, None)
353              elif shapetype == SHAPETYPE_POINT:              elif shapetype == SHAPETYPE_POINT:
354                  renderparam = layer                  renderparam = layer
                 self.dc.SetBrush(brush)  
                 self.dc.SetPen(pen)  
355                  func = self.draw_point_shape                  func = self.draw_point_shape
356                  args = ()                  args = (pen, brush)
357              else:              else:
358                  raise TypeError(_("Unhandled shape type %s") % shapetype)                  raise TypeError(_("Unhandled shape type %s") % shapetype)
359    
360              for index in self.selected_shapes:              for index in self.selected_shapes:
361                  func(renderparam, index, *args)                  func(renderparam, index, *args)
362    
   
363      def layer_ids(self, layer):      def layer_ids(self, layer):
364          """Return the shapeids covered by the region that has to be redrawn          """Return the shapeids covered by the region that has to be redrawn
365    
# Line 331  class ScreenRenderer(MapRenderer): Line 398  class ScreenRenderer(MapRenderer):
398          return layer.ShapesInRegion((left, bottom, right, top))          return layer.ShapesInRegion((left, bottom, right, top))
399    
400    
401  class PrinterRender(MapRenderer):  class ExportRenderer(ScreenRenderer):
402    
403      # When printing we want to see all layers      honor_visibility = 1
     honor_visibility = 0  
   
     RenderMap = MapRenderer.render_map  
404            
405        def RenderMap(self, map, region, mapregion,
406                      selected_layer, selected_shapes ):
407            """Render the map.
408    
409            The rendering device has been specified during initialisation.
410            The device border distance was set in Thuban.UI.view.OutputTranform().
411            
412            RenderMap renders a frame set (one page frame, one around
413            legend/scalebar and one around the map), the map, the legend and the
414            scalebar on the given DC. The map is rendered with the region displayed
415            in the canvas view, centered on the area available for map display.
416            """
417            
418            self.update_region = region
419            self.selected_layer = selected_layer
420            self.selected_shapes = selected_shapes
421    
422            # Get some dimensions
423            llx, lly, urx, ury = region
424            self.mapregion = mapregion
425            mminx, mminy, mmaxx, mmaxy = self.mapregion
426    
427            # Manipulate the offset to position the map
428            offx, offy = self.offset
429            # 1. Shift to corner of map drawing area
430            offx = offx + mminx
431            offy = offy + mminy
432    
433            # 2. Center the map on the map drawing area:
434            # region identifies the region on the canvas view:
435            # center of map drawing area - half the size of region: rendering origin
436            self.shiftx = (mmaxx - mminx)*0.5 - (urx - llx)*0.5
437            self.shifty = (mmaxy - mminy)*0.5 - (ury - lly)*0.5
438    
439            self.offset = (offx+self.shiftx, offy+self.shifty)
440    
441            # Draw the map
442            self.dc.BeginDrawing()
443            self.dc.DestroyClippingRegion()
444            self.dc.SetClippingRegion(mminx+self.shiftx, mminy+self.shifty,
445                                      urx, ury)
446            self.render_map(map)
447            self.dc.EndDrawing()
448    
449            # Draw the rest (frames, legend, scalebar)
450            self.dc.BeginDrawing()
451            self.dc.DestroyClippingRegion()
452    
453            # Force the font for Legend drawing
454            font = wxFont(self.resolution * 10, wxSWISS, wxNORMAL, wxNORMAL)
455            self.dc.SetFont(font)
456    
457            self.render_frame(region)
458            self.render_legend(map)
459            self.render_scalebar(map)
460            self.dc.EndDrawing()
461    
462        def render_frame(self, region):
463            """Render the frames for map and legend/scalebar."""
464    
465            dc = self.dc
466            dc.SetPen(wxBLACK_PEN)
467            dc.SetBrush(wxTRANSPARENT_BRUSH)
468    
469            # Dimension stuff
470            width, height = dc.GetSizeTuple()
471            mminx, mminy, mmaxx, mmaxy = self.mapregion
472    
473            # Page Frame
474            dc.DrawRectangle(15,15,width-30, (mmaxy-mminy)+10)
475            
476            # Map Frame
477            llx, lly, urx, ury = region
478            dc.DrawRectangle(mminx + self.shiftx, mminy + self.shifty, urx, ury)
479            
480            # Legend Frame
481            dc.DrawRectangle(mmaxx+10,mminy,(width-20) - (mmaxx+10), mmaxy-mminy)
482    
483            dc.DestroyClippingRegion()
484            dc.SetClippingRegion(mmaxx+10,mminy,
485                                 (width-20) - (mmaxx+10), mmaxy-mminy)
486    
487        def render_legend(self, map):
488            """Render the legend on the Map."""
489    
490            previewer = ClassDataPreviewer()
491            dc = self.dc
492            dc.SetPen(wxBLACK_PEN)
493            dc.SetBrush(wxTRANSPARENT_BRUSH)
494    
495            # Dimension stuff
496            width, height = dc.GetSizeTuple()
497            mminx, mminy, mmaxx, mmaxy = self.mapregion
498            textwidth, textheight = dc.GetTextExtent("0")
499            iconwidth  = textheight
500            iconheight = textheight
501            stepy = textheight+3
502            dx = 10
503            posx = mmaxx + 10 + 5   # 10 pix distance mapframe/legend frame,
504                                    # 5 pix inside legend frame
505            posy = mminy + 5        # 5 pix inside legend frame
506            
507            # Render the legend
508            dc.SetTextForeground(wxBLACK)
509            if map.HasLayers():
510                layers = map.Layers()
511                layers.reverse()
512                for l in layers:
513                    if l.Visible():
514                        # Render title
515                        dc.DrawText(l.Title(), posx, posy)
516                        posy+=stepy
517                        if l.HasClassification():
518                            # Render classification
519                            clazz = l.GetClassification()
520                            shapeType = l.ShapeType()
521                            for g in clazz:
522                                if g.IsVisible():
523                                    previewer.Draw(dc,
524                                        wxRect(posx+dx, posy,
525                                               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.686  
changed lines
  Added in v.1539

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26