/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/view.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/UI/view.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1105 by jonathan, Fri May 30 06:30:15 2003 UTC revision 1344 by jonathan, Tue Jul 1 16:11:26 2003 UTC
# Line 19  import os.path Line 19  import os.path
19    
20  from math import hypot  from math import hypot
21    
22  from wxPython.wx import wxWindow,\  from wxPython.wx import wxWindow, \
23       wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\       wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\
24       EVT_PAINT, EVT_LEFT_DOWN, EVT_LEFT_UP, EVT_MOTION, EVT_LEAVE_WINDOW, \       EVT_PAINT, EVT_LEFT_DOWN, EVT_LEFT_UP, EVT_MOTION, EVT_LEAVE_WINDOW, \
25       wxBITMAP_TYPE_XPM, wxBeginBusyCursor, wxEndBusyCursor, wxCursor, \       wxBITMAP_TYPE_XPM, wxCursor, wxImageFromBitmap, wxPlatform, \
26       wxImageFromBitmap, wxPlatform       wxBeginBusyCursor, wxEndBusyCursor
27    
28    
29  # Export related stuff  # Export related stuff
30  if wxPlatform == '__WXMSW__':  if wxPlatform == '__WXMSW__':
# Line 35  from wxPython import wx Line 36  from wxPython import wx
36  from wxproj import point_in_polygon_shape, shape_centroid  from wxproj import point_in_polygon_shape, shape_centroid
37    
38  from Thuban.Model.messages import MAP_PROJECTION_CHANGED, \  from Thuban.Model.messages import MAP_PROJECTION_CHANGED, \
39         LAYER_PROJECTION_CHANGED, \
40       MAP_LAYERS_CHANGED, LAYER_CHANGED, LAYER_VISIBILITY_CHANGED       MAP_LAYERS_CHANGED, LAYER_CHANGED, LAYER_VISIBILITY_CHANGED
41  from Thuban.Model.layer import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \  from Thuban.Model.layer import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \
42       SHAPETYPE_POINT       SHAPETYPE_POINT
43  from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \  from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \
44       ALIGN_LEFT, ALIGN_RIGHT       ALIGN_LEFT, ALIGN_RIGHT
45  from Thuban.Lib.connector import Publisher  from Thuban.Lib.connector import Publisher
46  from Thuban.Model.color import Color  from Thuban.Model.color import Color, Transparent
47    
48  import resource  import resource
49    
# Line 53  import labeldialog Line 55  import labeldialog
55  from messages import LAYER_SELECTED, SHAPES_SELECTED, VIEW_POSITION, \  from messages import LAYER_SELECTED, SHAPES_SELECTED, VIEW_POSITION, \
56                       SCALE_CHANGED                       SCALE_CHANGED
57    
58    #from common import ThubanBeginBusyCursor, ThubanEndBusyCursor
59    
60  #  #
61  #   The tools  #   The tools
# Line 273  class MapPrintout(wx.wxPrintout): Line 276  class MapPrintout(wx.wxPrintout):
276                             self.selected_layer, self.selected_shapes)                             self.selected_layer, self.selected_shapes)
277          return True          return True
278    
   
279  class MapCanvas(wxWindow, Publisher):  class MapCanvas(wxWindow, Publisher):
280    
281      """A widget that displays a map and offers some interaction"""      """A widget that displays a map and offers some interaction"""
# Line 302  class MapCanvas(wxWindow, Publisher): Line 304  class MapCanvas(wxWindow, Publisher):
304          # the map displayed in this canvas. Set with SetMap()          # the map displayed in this canvas. Set with SetMap()
305          self.map = None          self.map = None
306    
307            # current map projection. should only differ from map.projection
308            # when the map's projection is changing and we need access to the
309            # old projection.
310            self.current_map_proj = None
311    
312          # scale and offset describe the transformation from projected          # scale and offset describe the transformation from projected
313          # coordinates to window coordinates.          # coordinates to window coordinates.
314          self.scale = 1.0          self.scale = 1.0
# Line 330  class MapCanvas(wxWindow, Publisher): Line 337  class MapCanvas(wxWindow, Publisher):
337          self.last_selected_layer = None          self.last_selected_layer = None
338          self.last_selected_shape = None          self.last_selected_shape = None
339    
340            self.backgroundColor = wx.wxWHITE_BRUSH
341    
342          # subscribe the WX events we're interested in          # subscribe the WX events we're interested in
343          EVT_PAINT(self, self.OnPaint)          EVT_PAINT(self, self.OnPaint)
344          EVT_LEFT_DOWN(self, self.OnLeftDown)          EVT_LEFT_DOWN(self, self.OnLeftDown)
# Line 337  class MapCanvas(wxWindow, Publisher): Line 346  class MapCanvas(wxWindow, Publisher):
346          EVT_MOTION(self, self.OnMotion)          EVT_MOTION(self, self.OnMotion)
347          EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)          EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)
348          wx.EVT_SIZE(self, self.OnSize)          wx.EVT_SIZE(self, self.OnSize)
349            wx.EVT_IDLE(self, self.OnIdle)
350    
351      def __del__(self):      def __del__(self):
352          wxWindow.__del__(self)          wxWindow.__del__(self)
# Line 375  class MapCanvas(wxWindow, Publisher): Line 385  class MapCanvas(wxWindow, Publisher):
385    
386      def OnPaint(self, event):      def OnPaint(self, event):
387          dc = wxPaintDC(self)          dc = wxPaintDC(self)
         clear = self.map is None or not self.map.HasLayers()  
388    
389          wxBeginBusyCursor()          if self.map is not None and self.map.HasLayers():
390          try:              if self.bitmap in (None, -1):
391              if not clear:                  # set the flag that we should redraw the
392                  self.do_redraw()                  # bitmap in idle time
393                  try:                  self.bitmap = -1
394                      pass                  return
                 except:  
                     print "Error during drawing:", sys.exc_info()[0]  
                     clear = True  
   
             if clear:  
                 # If we've got no map or if the map is empty, simply clear  
                 # the screen.  
   
                 # XXX it's probably possible to get rid of this. The  
                 # background color of the window is already white and the  
                 # only thing we may have to do is to call self.Refresh()  
                 # with a true argument in the right places.  
                 dc.BeginDrawing()  
                 dc.Clear()  
                 dc.EndDrawing()  
         finally:  
             wxEndBusyCursor()  
395    
396      def do_redraw(self):              # blit the bitmap to the screen
397          # This should only be called if we have a non-empty map.              dc.BeginDrawing()
398                dc.DrawBitmap(self.bitmap, 0, 0)
399                dc.EndDrawing()
400            else:
401                # If we've got no map or if the map is empty, simply clear
402                # the screen.
403    
404          # Get the window size.              # XXX it's probably possible to get rid of this. The
405          width, height = self.GetSizeTuple()              # background color of the window is already white and the
406                # only thing we may have to do is to call self.Refresh()
407                # with a true argument in the right places.
408                dc.BeginDrawing()
409                dc.SetBackground(self.backgroundColor)
410                dc.Clear()
411                dc.EndDrawing()
412    
413        def OnIdle(self, event):
414            # render the screen if necessary
415    
416            if self.bitmap != -1:
417                return
418    
419            wxBeginBusyCursor()
420            try:
421                width, height = self.GetSizeTuple()
422    
         # If self.bitmap's still there, reuse it. Otherwise redraw it  
         if self.bitmap is not None:  
             bitmap = self.bitmap  
         else:  
423              bitmap = wx.wxEmptyBitmap(width, height)              bitmap = wx.wxEmptyBitmap(width, height)
424              dc = wx.wxMemoryDC()              dc = wx.wxMemoryDC()
425              dc.SelectObject(bitmap)              dc.SelectObject(bitmap)
426              dc.BeginDrawing()              dc.BeginDrawing()
427    
428              # clear the background              dc.SetBackground(self.backgroundColor)
             #dc.SetBrush(wx.wxWHITE_BRUSH)  
             #dc.SetPen(wx.wxTRANSPARENT_PEN)  
             #dc.DrawRectangle(0, 0, width, height)  
             dc.SetBackground(wx.wxWHITE_BRUSH)  
429              dc.Clear()              dc.Clear()
430    
431              selected_layer = self.selection.SelectedLayer()              selected_layer = self.selection.SelectedLayer()
# Line 436  class MapCanvas(wxWindow, Publisher): Line 441  class MapCanvas(wxWindow, Publisher):
441    
442              dc.EndDrawing()              dc.EndDrawing()
443              dc.SelectObject(wx.wxNullBitmap)              dc.SelectObject(wx.wxNullBitmap)
444    
445              self.bitmap = bitmap              self.bitmap = bitmap
446            finally:
447                wxEndBusyCursor()
448                pass
449    
450          # blit the bitmap to the screen          # This causes a paint event that then draws the bitmap
451          dc = wx.wxMemoryDC()          self.redraw()
         dc.SelectObject(bitmap)  
         clientdc = wxClientDC(self)  
         clientdc.BeginDrawing()  
         clientdc.Blit(0, 0, width, height, dc, 0, 0)  
         clientdc.EndDrawing()  
452    
453      def Export(self):      def Export(self):
454          if self.scale == 0:          if self.scale == 0:
# Line 502  class MapCanvas(wxWindow, Publisher): Line 506  class MapCanvas(wxWindow, Publisher):
506              for channel in redraw_channels:              for channel in redraw_channels:
507                  self.map.Unsubscribe(channel, self.full_redraw)                  self.map.Unsubscribe(channel, self.full_redraw)
508              self.map.Unsubscribe(MAP_PROJECTION_CHANGED,              self.map.Unsubscribe(MAP_PROJECTION_CHANGED,
509                                   self.projection_changed)                                   self.map_projection_changed)
510                self.map.Unsubscribe(LAYER_PROJECTION_CHANGED,
511                                     self.layer_projection_changed)
512          self.map = map          self.map = map
513            self.current_map_proj = self.map.GetProjection()
514          self.selection.ClearSelection()          self.selection.ClearSelection()
515          if self.map is not None:          if self.map is not None:
516              for channel in redraw_channels:              for channel in redraw_channels:
517                  self.map.Subscribe(channel, self.full_redraw)                  self.map.Subscribe(channel, self.full_redraw)
518              self.map.Subscribe(MAP_PROJECTION_CHANGED, self.projection_changed)              self.map.Subscribe(MAP_PROJECTION_CHANGED, self.map_projection_changed)
519                self.map.Subscribe(LAYER_PROJECTION_CHANGED, self.layer_projection_changed)
520          self.FitMapToWindow()          self.FitMapToWindow()
521          # force a redraw. If map is not empty, it's already been called          # force a redraw. If map is not empty, it's already been called
522          # by FitMapToWindow but if map is empty it hasn't been called          # by FitMapToWindow but if map is empty it hasn't been called
# Line 520  class MapCanvas(wxWindow, Publisher): Line 528  class MapCanvas(wxWindow, Publisher):
528          return self.map          return self.map
529    
530      def redraw(self, *args):      def redraw(self, *args):
531          self.Refresh(0)          self.Refresh(False)
532    
533      def full_redraw(self, *args):      def full_redraw(self, *args):
534          self.bitmap = None          self.bitmap = None
535          self.redraw()          self.redraw()
536    
537      def projection_changed(self, *args):      def map_projection_changed(self, *args):
538          self.FitMapToWindow()  
539            proj = self.current_map_proj
540            self.current_map_proj = self.map.GetProjection()
541    
542            bbox = None
543    
544            if proj is not None and self.current_map_proj is not None:
545                width, height = self.GetSizeTuple()
546                llx, lly = self.win_to_proj(0, height)
547                urx, ury = self.win_to_proj(width, 0)
548                bbox = proj.Inverse(llx, lly) + proj.Inverse(urx, ury)
549                bbox = self.current_map_proj.ForwardBBox(bbox)
550    
551            if bbox is not None:
552                self.FitRectToWindow(bbox)
553            else:
554                self.FitMapToWindow()
555    
556            self.full_redraw()
557    
558        def layer_projection_changed(self, *args):
559          self.full_redraw()          self.full_redraw()
560    
561      def set_view_transform(self, scale, offset):      def set_view_transform(self, scale, offset):
562            # width/height of the projected bbox
563            llx, lly, urx, ury = bbox = self.map.ProjectedBoundingBox()
564            pwidth = float(urx - llx)
565            pheight = float(ury - lly)
566    
567            # width/height of the window
568            wwidth, wheight = self.GetSizeTuple()
569    
570            # The window's center in projected coordinates assuming the new
571            # scale/offset
572            pcenterx = (wwidth/2 - offset[0]) / scale
573            pcentery = (offset[1] - wheight/2) / scale
574    
575            # The window coordinates used when drawing the shapes must fit
576            # into 16bit signed integers.
577            max_len = max(pwidth, pheight)
578            if max_len:
579                max_scale = 32000.0 / max_len
580            else:
581                # FIXME: What to do in this case? The bbox is effectively
582                # empty so any scale should work.
583                max_scale = scale
584    
585            # The minimal scale is somewhat arbitrarily set to half that of
586            # the bbox fit into the window
587            scales = []
588            if pwidth:
589                scales.append(wwidth / pwidth)
590            if pheight:
591                scales.append(wheight / pheight)
592            if scales:
593                min_scale = 0.5 * min(scales)
594            else:
595                min_scale = scale
596    
597            if scale > max_scale:
598                scale = max_scale
599            elif scale < min_scale:
600                scale = min_scale
601    
602          self.scale = scale          self.scale = scale
603    
604          self.offset = offset          # determine new offset to preserve the center
605            self.offset = (wwidth/2 - scale * pcenterx,
606                           wheight/2 + scale * pcentery)
607          self.full_redraw()          self.full_redraw()
608          self.issue(SCALE_CHANGED, scale)          self.issue(SCALE_CHANGED, scale)
609    
# Line 581  class MapCanvas(wxWindow, Publisher): Line 651  class MapCanvas(wxWindow, Publisher):
651          Set the scale so that the map fits exactly into the window and          Set the scale so that the map fits exactly into the window and
652          center it in the window.          center it in the window.
653          """          """
654          bbox = self.map.ProjectedBoundingBox()          if self.map is not None:
655          if bbox is not None:              bbox = self.map.ProjectedBoundingBox()
656              self.FitRectToWindow(bbox)              if bbox is not None:
657                    self.FitRectToWindow(bbox)
658    
659      def FitLayerToWindow(self, layer):      def FitLayerToWindow(self, layer):
660          """Fit the given layer to the window.          """Fit the given layer to the window.
# Line 870  class MapCanvas(wxWindow, Publisher): Line 941  class MapCanvas(wxWindow, Publisher):
941              layer = layers[layer_index]              layer = layers[layer_index]
942    
943              # search only in visible layers              # search only in visible layers
944              if not layer.Visible():              if not layer.Visible() or not layer.HasShapes():
945                  continue                  continue
946    
947              filled = layer.GetClassification().GetDefaultFill() \              filled = layer.GetClassification().GetDefaultFill() \
948                       is not Color.Transparent                       is not Transparent
949              stroked = layer.GetClassification().GetDefaultLineColor() \              stroked = layer.GetClassification().GetDefaultLineColor() \
950                        is not Color.Transparent                        is not Transparent
951    
952              layer_proj = layer.projection              layer_proj = layer.projection
953              if layer_proj is not None:              if layer_proj is not None:
# Line 903  class MapCanvas(wxWindow, Publisher): Line 974  class MapCanvas(wxWindow, Publisher):
974    
975              if shapetype == SHAPETYPE_POLYGON:              if shapetype == SHAPETYPE_POLYGON:
976                  for i in shape_ids:                  for i in shape_ids:
977                      result = point_in_polygon_shape(layer.shapefile.cobject(),                      shapefile = layer.ShapeStore().Shapefile().cobject()
978                                                      i,                      result = point_in_polygon_shape(shapefile, i,
979                                                      filled, stroked,                                                      filled, stroked,
980                                                      map_proj, layer_proj,                                                      map_proj, layer_proj,
981                                                      scale, -scale, offx, offy,                                                      scale, -scale, offx, offy,
# Line 914  class MapCanvas(wxWindow, Publisher): Line 985  class MapCanvas(wxWindow, Publisher):
985                          break                          break
986              elif shapetype == SHAPETYPE_ARC:              elif shapetype == SHAPETYPE_ARC:
987                  for i in shape_ids:                  for i in shape_ids:
988                      result = point_in_polygon_shape(layer.shapefile.cobject(),                      shapefile = layer.ShapeStore().Shapefile().cobject()
989                        result = point_in_polygon_shape(shapefile,
990                                                      i, 0, 1,                                                      i, 0, 1,
991                                                      map_proj, layer_proj,                                                      map_proj, layer_proj,
992                                                      scale, -scale, offx, offy,                                                      scale, -scale, offx, offy,
# Line 976  class MapCanvas(wxWindow, Publisher): Line 1048  class MapCanvas(wxWindow, Publisher):
1048              # a label was selected              # a label was selected
1049              label_layer.RemoveLabel(shape_index)              label_layer.RemoveLabel(shape_index)
1050          elif layer is not None:          elif layer is not None:
1051              text = labeldialog.run_label_dialog(self, layer.table, shape_index)              text = labeldialog.run_label_dialog(self,
1052                                                    layer.ShapeStore().Table(),
1053                                                    shape_index)
1054              if text:              if text:
1055                  proj = self.map.projection                  proj = self.map.projection
1056                  if proj is not None:                  if proj is not None:
# Line 991  class MapCanvas(wxWindow, Publisher): Line 1065  class MapCanvas(wxWindow, Publisher):
1065    
1066                  shapetype = layer.ShapeType()                  shapetype = layer.ShapeType()
1067                  if shapetype == SHAPETYPE_POLYGON:                  if shapetype == SHAPETYPE_POLYGON:
1068                      x, y = shape_centroid(layer.shapefile.cobject(),                      shapefile = layer.ShapeStore().Shapefile().cobject()
1069                                            shape_index,                      x, y = shape_centroid(shapefile, shape_index,
1070                                            map_proj, layer_proj, 1, 1, 0, 0)                                            map_proj, layer_proj, 1, 1, 0, 0)
1071                      if map_proj is not None:                      if map_proj is not None:
1072                          x, y = map_proj.Inverse(x, y)                          x, y = map_proj.Inverse(x, y)

Legend:
Removed from v.1105  
changed lines
  Added in v.1344

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26