GRASS Programmer's Manual  6.4.2(2012)
gcpmapdisp.py
Go to the documentation of this file.
00001 """!
00002 @package gcpmapdisp.py
00003 
00004 @brief display to manage ground control points with two toolbars, one for
00005 various display management functions, one for manipulating GCPs.
00006 
00007 Classes:
00008 - MapFrame
00009 
00010 (C) 2006-2010 by the GRASS Development Team
00011 This program is free software under the GNU General Public
00012 License (>=v2). Read the file COPYING that comes with GRASS
00013 for details.
00014 
00015 Derived from mapdisp.py
00016 
00017 @author Markus Metz
00018 """
00019 
00020 import os
00021 import sys
00022 import glob
00023 import math
00024 import tempfile
00025 import copy
00026 import platform
00027 
00028 import globalvar
00029 import wx
00030 import wx.aui
00031 
00032 try:
00033     import subprocess
00034 except:
00035     CompatPath = os.path.join(globalvar.ETCWXDIR)
00036     sys.path.append(CompatPath)
00037     from compat import subprocess
00038 
00039 gmpath = os.path.join(globalvar.ETCWXDIR, "icons")
00040 sys.path.append(gmpath)
00041 
00042 grassPath = os.path.join(globalvar.ETCDIR, "python")
00043 sys.path.append(grassPath)
00044 
00045 import render
00046 import toolbars
00047 import menuform
00048 import gselect
00049 import disp_print
00050 import gcmd
00051 import dbm
00052 import dbm_dialogs
00053 import globalvar
00054 import utils
00055 import gdialogs
00056 from grass.script import core as grass
00057 from debug import Debug
00058 from icon  import Icons
00059 from preferences import globalSettings as UserSettings
00060 
00061 from mapdisp_command import Command
00062 from mapdisp_window import BufferedWindow
00063 
00064 # for standalone app
00065 cmdfilename = None
00066 
00067 class MapFrame(wx.Frame):
00068     """!Main frame for map display window. Drawing takes place in
00069     child double buffered drawing window.
00070     """
00071     def __init__(self, parent=None, id=wx.ID_ANY, title=_("GRASS GIS Manage Ground Control Points"),
00072                  style=wx.DEFAULT_FRAME_STYLE, toolbars=["gcpdisp"],
00073                  tree=None, notebook=None, lmgr=None, page=None,
00074                  Map=None, auimgr=None, **kwargs):
00075         """!Main map display window with toolbars, statusbar and
00076         DrawWindow
00077 
00078         @param toolbars array of activated toolbars, e.g. ['map', 'digit']
00079         @param tree reference to layer tree
00080         @param notebook control book ID in Layer Manager
00081         @param lmgr Layer Manager
00082         @param page notebook page with layer tree
00083         @param Map instance of render.Map
00084         @param auimgs AUI manager
00085         @param kwargs wx.Frame attribures
00086         """
00087         self._layerManager = lmgr   # Layer Manager object
00088         self.Map        = Map       # instance of render.Map
00089         self.tree       = tree      # Layer Manager layer tree object
00090         self.page       = page      # Notebook page holding the layer tree
00091         self.layerbook  = notebook  # Layer Manager layer tree notebook
00092         self.parent     = parent
00093         
00094         if 'name' not in kwargs:
00095             kwargs['name'] = 'GCPMapWindow'
00096         wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
00097         
00098         # available cursors
00099         self.cursors = {
00100             # default: cross
00101             # "default" : wx.StockCursor(wx.CURSOR_DEFAULT),
00102             "default" : wx.StockCursor(wx.CURSOR_ARROW),
00103             "cross"   : wx.StockCursor(wx.CURSOR_CROSS),
00104             "hand"    : wx.StockCursor(wx.CURSOR_HAND),
00105             "pencil"  : wx.StockCursor(wx.CURSOR_PENCIL),
00106             "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
00107             }
00108         
00109         #
00110         # set the size & system icon
00111         #
00112         self.SetClientSize(self.GetSize())
00113         self.iconsize = (16, 16)
00114 
00115         self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_map.ico'), wx.BITMAP_TYPE_ICO))
00116 
00117         #
00118         # Fancy gui
00119         #
00120         self._mgr = wx.aui.AuiManager(self)
00121 
00122         #
00123         # Add toolbars
00124         #
00125         self.toolbars = { 'map' : None,
00126                           'vdigit' : None,
00127                           'georect' : None, 
00128                           'gcpdisp' : None, 
00129                           'gcpman' : None, 
00130                           'nviz' : None }
00131 
00132         for toolb in toolbars:
00133             self.AddToolbar(toolb)
00134 
00135         self.activemap = self.toolbars['gcpdisp'].togglemap
00136         self.activemap.SetSelection(0)
00137         self.SrcMap        = self.grwiz.SrcMap       # instance of render.Map
00138         self.TgtMap        = self.grwiz.TgtMap       # instance of render.Map
00139         self._mgr.SetDockSizeConstraint(0.5, 0.5)
00140 
00141         #
00142         # Add statusbar
00143         #
00144         self.statusbar = self.CreateStatusBar(number=4, style=0)
00145         self.statusbar.SetStatusWidths([-5, -2, -1, -1])
00146         self.statusbarWin = dict()
00147         self.statusbarWin['toggle'] = wx.Choice(self.statusbar, wx.ID_ANY,
00148                                   choices = [_("Coordinates"),
00149                                              _("Extent"),
00150                                              _("Comp. region"),
00151                                              _("Show comp. extent"),
00152                                              _("Display mode"),
00153                                              _("Display geometry"),
00154                                              _("Map scale"),
00155                                              _("Go to GCP No."),
00156                                              _("RMS error")])
00157         # set StatusBar to Go to GCP No.
00158         self.statusbarWin['toggle'].SetSelection(7)
00159 
00160         self.statusbar.Bind(wx.EVT_CHOICE, self.OnToggleStatus, self.statusbarWin['toggle'])
00161         # auto-rendering checkbox
00162         self.statusbarWin['render'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
00163                                                   label=_("Render"))
00164         self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleRender, self.statusbarWin['render'])
00165         self.statusbarWin['render'].SetValue(UserSettings.Get(group='display',
00166                                                               key='autoRendering',
00167                                                               subkey='enabled'))
00168         self.statusbarWin['render'].SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering")))
00169         # show region
00170         self.statusbarWin['region'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
00171                                                   label=_("Show computational extent"))
00172         self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion, self.statusbarWin['region'])
00173         
00174         self.statusbarWin['region'].SetValue(False)
00175         self.statusbarWin['region'].Hide()
00176         self.statusbarWin['region'].SetToolTip(wx.ToolTip (_("Show/hide computational "
00177                                                              "region extent (set with g.region). "
00178                                                              "Display region drawn as a blue box inside the "
00179                                                              "computational region, "
00180                                                              "computational region inside a display region "
00181                                                              "as a red box).")))
00182         # set resolution
00183         self.statusbarWin['resolution'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
00184                                                       label=_("Constrain display resolution to computational settings"))
00185         self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleResolution, self.statusbarWin['resolution'])
00186         self.statusbarWin['resolution'].SetValue(UserSettings.Get(group='display', key='compResolution', subkey='enabled'))
00187         self.statusbarWin['resolution'].Hide()
00188         self.statusbarWin['resolution'].SetToolTip(wx.ToolTip (_("Constrain display resolution "
00189                                                                  "to computational region settings. "
00190                                                                  "Default value for new map displays can "
00191                                                                  "be set up in 'User GUI settings' dialog.")))
00192         # map scale
00193         self.statusbarWin['mapscale'] = wx.ComboBox(parent = self.statusbar, id = wx.ID_ANY,
00194                                                     style = wx.TE_PROCESS_ENTER,
00195                                                     size=(150, -1))
00196         self.statusbarWin['mapscale'].SetItems(['1:1000',
00197                                                 '1:5000',
00198                                                 '1:10000',
00199                                                 '1:25000',
00200                                                 '1:50000',
00201                                                 '1:100000',
00202                                                 '1:1000000'])
00203         self.statusbarWin['mapscale'].Hide()
00204         self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale, self.statusbarWin['mapscale'])
00205         self.statusbar.Bind(wx.EVT_COMBOBOX, self.OnChangeMapScale, self.statusbarWin['mapscale'])
00206 
00207         # go to
00208         self.statusbarWin['goto'] = wx.SpinCtrl(parent=self.statusbar, id=wx.ID_ANY,
00209                              min=0)
00210         self.statusbar.Bind(wx.EVT_SPINCTRL, self.OnGoTo, self.statusbarWin['goto'])
00211         self.statusbarWin['goto'].Hide()
00212         self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnGoTo, self.statusbarWin['goto'])
00213 
00214         # projection, unused but BufferedWindow checks for it
00215         self.statusbarWin['projection'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
00216                                                       label=_("Use defined projection"))
00217         self.statusbarWin['projection'].SetValue(False)
00218         size = self.statusbarWin['projection'].GetSize()
00219         self.statusbarWin['projection'].SetMinSize((size[0] + 150, size[1]))
00220         self.statusbarWin['projection'].SetToolTip(wx.ToolTip (_("Reproject coordinates displayed "
00221                                                                  "in the statusbar. Projection can be "
00222                                                                  "defined in GUI preferences dialog "
00223                                                                  "(tab 'Display')")))
00224         self.statusbarWin['projection'].Hide()
00225 
00226         # mask
00227         self.statusbarWin['mask'] = wx.StaticText(parent = self.statusbar, id = wx.ID_ANY,
00228                                                   label = '')
00229         self.statusbarWin['mask'].SetForegroundColour(wx.Colour(255, 0, 0))
00230         
00231         # on-render gauge
00232         self.statusbarWin['progress'] = wx.Gauge(parent=self.statusbar, id=wx.ID_ANY,
00233                                       range=0, style=wx.GA_HORIZONTAL)
00234         self.statusbarWin['progress'].Hide()
00235         
00236         self.StatusbarReposition() # reposition statusbar
00237 
00238         #
00239         # Init map display (buffered DC & set default cursor)
00240         #
00241         self.grwiz.SwitchEnv('source')
00242         self.SrcMapWindow = BufferedWindow(self, id=wx.ID_ANY,
00243                                           Map=self.SrcMap, tree=self.tree, lmgr=self._layerManager)
00244 
00245         self.grwiz.SwitchEnv('target')
00246         self.TgtMapWindow = BufferedWindow(self, id=wx.ID_ANY,
00247                                           Map=self.TgtMap, tree=self.tree, lmgr=self._layerManager)
00248         self.MapWindow = self.SrcMapWindow
00249         self.Map = self.SrcMap
00250         self.SrcMapWindow.SetCursor(self.cursors["cross"])
00251         self.TgtMapWindow.SetCursor(self.cursors["cross"])
00252 
00253         #
00254         # initialize region values
00255         #
00256         self.__InitDisplay() 
00257 
00258         #
00259         # Bind various events
00260         #
00261         self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
00262         self.Bind(render.EVT_UPDATE_PRGBAR, self.OnUpdateProgress)
00263         self.Bind(wx.EVT_SIZE,     self.OnDispResize)
00264         self.activemap.Bind(wx.EVT_CHOICE, self.OnUpdateActive)
00265         
00266         #
00267         # Update fancy gui style
00268         #
00269         # AuiManager wants a CentrePane, workaround to get two equally sized windows
00270         self.list = self.CreateGCPList()
00271 
00272         #self.SrcMapWindow.SetSize((300, 300))
00273         #self.TgtMapWindow.SetSize((300, 300))
00274         self.list.SetSize((100, 150))
00275         self._mgr.AddPane(self.list, wx.aui.AuiPaneInfo().
00276                   Name("gcplist").Caption(_("GCP List")).LeftDockable(False).
00277                   RightDockable(False).PinButton().FloatingSize((600,200)).
00278                   CloseButton(False).DestroyOnClose(True).
00279                   Top().Layer(1).MinSize((200,100)))
00280         self._mgr.AddPane(self.SrcMapWindow, wx.aui.AuiPaneInfo().
00281                   Name("source").Caption(_("Source Display")).Dockable(False).
00282                   CloseButton(False).DestroyOnClose(True).Floatable(False).
00283                   Centre())
00284         self._mgr.AddPane(self.TgtMapWindow, wx.aui.AuiPaneInfo().
00285                   Name("target").Caption(_("Target Display")).Dockable(False).
00286                   CloseButton(False).DestroyOnClose(True).Floatable(False).
00287                   Right().Layer(0))
00288 
00289         srcwidth, srcheight = self.SrcMapWindow.GetSize()
00290         tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
00291         srcwidth = (srcwidth + tgtwidth) / 2
00292         self._mgr.GetPane("target").Hide()
00293         self._mgr.Update()
00294         self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
00295         self._mgr.GetPane("target").BestSize((srcwidth, srcheight))
00296         if self.show_target:
00297             self._mgr.GetPane("target").Show()
00298         else:
00299             self.activemap.Enable(False)
00300         # needed by Mac OS, does not harm on Linux, breaks display on Windows
00301         if platform.system() != 'Windows':
00302             self._mgr.Update()
00303 
00304         #
00305         # Init print module and classes
00306         #
00307         self.printopt = disp_print.PrintOptions(self, self.MapWindow)
00308         
00309         #
00310         # Initialization of digitization tool
00311         #
00312         self.digit = None
00313 
00314         # set active map
00315         self.MapWindow = self.SrcMapWindow
00316         self.Map = self.SrcMap
00317         
00318         # do not init zoom history here, that happens when zooming to map(s)
00319 
00320         #
00321         # Re-use dialogs
00322         #
00323         self.dialogs = {}
00324         self.dialogs['attributes'] = None
00325         self.dialogs['category'] = None
00326         self.dialogs['barscale'] = None
00327         self.dialogs['legend'] = None
00328 
00329         self.decorationDialog = None # decoration/overlays
00330 
00331     def AddToolbar(self, name):
00332         """!Add defined toolbar to the window
00333         
00334         Currently known toolbars are:
00335          - 'map'     - basic map toolbar
00336          - 'vdigit'  - vector digitizer
00337          - 'gcpdisp' - GCP Manager, Display
00338          - 'gcpman'  - GCP Manager, points management
00339          - 'georect' - georectifier
00340          - 'nviz'    - 3D view mode
00341         """
00342         # default toolbar
00343         if name == "map":
00344             self.toolbars['map'] = toolbars.MapToolbar(self, self.Map)
00345 
00346             self._mgr.AddPane(self.toolbars['map'],
00347                               wx.aui.AuiPaneInfo().
00348                               Name("maptoolbar").Caption(_("Map Toolbar")).
00349                               ToolbarPane().Top().
00350                               LeftDockable(False).RightDockable(False).
00351                               BottomDockable(False).TopDockable(True).
00352                               CloseButton(False).Layer(2).
00353                               BestSize((self.toolbars['map'].GetSize())))
00354 
00355         # GCP display
00356         elif name == "gcpdisp":
00357             self.toolbars['gcpdisp'] = toolbars.GCPDisplayToolbar(self)
00358 
00359             self._mgr.AddPane(self.toolbars['gcpdisp'],
00360                               wx.aui.AuiPaneInfo().
00361                               Name("gcpdisplaytoolbar").Caption(_("GCP Display toolbar")).
00362                               ToolbarPane().Top().
00363                               LeftDockable(False).RightDockable(False).
00364                               BottomDockable(False).TopDockable(True).
00365                               CloseButton(False).Layer(2))
00366 
00367             if self.show_target == False:
00368                 self.toolbars['gcpdisp'].Enable('zoommenu', enable = False)
00369 
00370             self.toolbars['gcpman'] = toolbars.GCPManToolbar(self)
00371 
00372             self._mgr.AddPane(self.toolbars['gcpman'],
00373                               wx.aui.AuiPaneInfo().
00374                               Name("gcpmanagertoolbar").Caption(_("GCP Manager toolbar")).
00375                               ToolbarPane().Top().Row(1).
00376                               LeftDockable(False).RightDockable(False).
00377                               BottomDockable(False).TopDockable(True).
00378                               CloseButton(False).Layer(2))
00379             
00380         self._mgr.Update()
00381 
00382     def __InitDisplay(self):
00383         """
00384         Initialize map display, set dimensions and map region
00385         """
00386         self.width, self.height = self.GetClientSize()
00387 
00388         Debug.msg(2, "MapFrame.__InitDisplay():")
00389         self.grwiz.SwitchEnv('source')
00390         self.SrcMap.ChangeMapSize(self.GetClientSize())
00391         self.SrcMap.region = self.SrcMap.GetRegion() # g.region -upgc
00392         self.grwiz.SwitchEnv('target')
00393         self.TgtMap.ChangeMapSize(self.GetClientSize())
00394         self.TgtMap.region = self.TgtMap.GetRegion() # g.region -upgc
00395         # self.SrcMap.SetRegion() # adjust region to match display window
00396         # self.TgtMap.SetRegion() # adjust region to match display window
00397 
00398     def OnUpdateProgress(self, event):
00399         """
00400         Update progress bar info
00401         """
00402         self.statusbarWin['progress'].SetValue(event.value)
00403         
00404         event.Skip()
00405         
00406     def OnFocus(self, event):
00407         """
00408         Change choicebook page to match display.
00409         Or set display for georectifying
00410         """
00411         if self._layerManager and \
00412                 self._layerManager.gcpmanagement:
00413             # in GCP Management, set focus to current MapWindow for mouse actions
00414             self.OnPointer(event)
00415             self.MapWindow.SetFocus()
00416         else:
00417             # change bookcontrol page to page associated with display
00418             # GCP Manager: use bookcontrol?
00419             if self.page:
00420                 pgnum = self.layerbook.GetPageIndex(self.page)
00421                 if pgnum > -1:
00422                     self.layerbook.SetSelection(pgnum)
00423         
00424         event.Skip()
00425 
00426     def OnDraw(self, event):
00427         """!Re-display current map composition
00428         """
00429         self.MapWindow.UpdateMap(render = False)
00430         
00431     def OnRender(self, event):
00432         """!Re-render map composition (each map layer)
00433         """
00434         # delete tmp map layers (queries)
00435         qlayer = self.Map.GetListOfLayers(l_name=globalvar.QUERYLAYER)
00436         for layer in qlayer:
00437             self.Map.DeleteLayer(layer)
00438 
00439         self.SrcMapWindow.UpdateMap(render=True)
00440         if self.show_target:
00441             self.TgtMapWindow.UpdateMap(render=True)
00442         
00443         # update statusbar
00444         self.StatusbarUpdate()
00445 
00446     def OnPointer(self, event):
00447         """!Pointer button clicked
00448         """
00449         # change the cursor
00450         self.SrcMapWindow.SetCursor(self.cursors["cross"])
00451         self.SrcMapWindow.mouse['use'] = "pointer"
00452         self.SrcMapWindow.mouse['box'] = "point"
00453         self.TgtMapWindow.SetCursor(self.cursors["cross"])
00454         self.TgtMapWindow.mouse['use'] = "pointer"
00455         self.TgtMapWindow.mouse['box'] = "point"
00456 
00457     def OnZoomIn(self, event):
00458         """
00459         Zoom in the map.
00460         Set mouse cursor, zoombox attributes, and zoom direction
00461         """
00462         if self.toolbars['map']:
00463             self.toolbars['map'].OnTool(event)
00464             self.toolbars['map'].action['desc'] = ''
00465         
00466         self.MapWindow.mouse['use'] = "zoom"
00467         self.MapWindow.mouse['box'] = "box"
00468         self.MapWindow.zoomtype = 1
00469         self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
00470         
00471         # change the cursor
00472         self.MapWindow.SetCursor(self.cursors["cross"])
00473 
00474         if self.MapWindow == self.SrcMapWindow:
00475             win = self.TgtMapWindow
00476         elif self.MapWindow == self.TgtMapWindow:
00477             win = self.SrcMapWindow
00478 
00479         win.mouse['use'] = "zoom"
00480         win.mouse['box'] = "box"
00481         win.zoomtype = 1
00482         win.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
00483         
00484         # change the cursor
00485         win.SetCursor(self.cursors["cross"])
00486 
00487     def OnZoomOut(self, event):
00488         """
00489         Zoom out the map.
00490         Set mouse cursor, zoombox attributes, and zoom direction
00491         """
00492         if self.toolbars['map']:
00493             self.toolbars['map'].OnTool(event)
00494             self.toolbars['map'].action['desc'] = ''
00495         
00496         self.MapWindow.mouse['use'] = "zoom"
00497         self.MapWindow.mouse['box'] = "box"
00498         self.MapWindow.zoomtype = -1
00499         self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
00500         
00501         # change the cursor
00502         self.MapWindow.SetCursor(self.cursors["cross"])
00503 
00504         if self.MapWindow == self.SrcMapWindow:
00505             win = self.TgtMapWindow
00506         elif self.MapWindow == self.TgtMapWindow:
00507             win = self.SrcMapWindow
00508 
00509         win.mouse['use'] = "zoom"
00510         win.mouse['box'] = "box"
00511         win.zoomtype = -1
00512         win.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
00513         
00514         # change the cursor
00515         win.SetCursor(self.cursors["cross"])
00516 
00517     def OnZoomBack(self, event):
00518         """
00519         Zoom last (previously stored position)
00520         """
00521         self.MapWindow.ZoomBack()
00522 
00523     def OnPan(self, event):
00524         """
00525         Panning, set mouse to drag
00526         """
00527         if self.toolbars['map']:
00528             self.toolbars['map'].OnTool(event)
00529             self.toolbars['map'].action['desc'] = ''
00530         
00531         self.MapWindow.mouse['use'] = "pan"
00532         self.MapWindow.mouse['box'] = "pan"
00533         self.MapWindow.zoomtype = 0
00534         
00535         # change the cursor
00536         self.MapWindow.SetCursor(self.cursors["hand"])
00537 
00538         if self.MapWindow == self.SrcMapWindow:
00539             win = self.TgtMapWindow
00540         elif self.MapWindow == self.TgtMapWindow:
00541             win = self.SrcMapWindow
00542 
00543         win.mouse['use'] = "pan"
00544         win.mouse['box'] = "pan"
00545         win.zoomtype = 0
00546         
00547         # change the cursor
00548         win.SetCursor(self.cursors["hand"])
00549 
00550     def OnErase(self, event):
00551         """
00552         Erase the canvas
00553         """
00554         self.MapWindow.EraseMap()
00555 
00556         if self.MapWindow == self.SrcMapWindow:
00557             win = self.TgtMapWindow
00558         elif self.MapWindow == self.TgtMapWindow:
00559             win = self.SrcMapWindow
00560 
00561         win.EraseMap()
00562 
00563     def OnZoomRegion(self, event):
00564         """
00565         Zoom to region
00566         """
00567         self.Map.getRegion()
00568         self.Map.getResolution()
00569         self.UpdateMap()
00570         # event.Skip()
00571 
00572     def OnAlignRegion(self, event):
00573         """
00574         Align region
00575         """
00576         if not self.Map.alignRegion:
00577             self.Map.alignRegion = True
00578         else:
00579             self.Map.alignRegion = False
00580         # event.Skip()
00581 
00582     def OnToggleRender(self, event):
00583         """
00584         Enable/disable auto-rendering
00585         """
00586         if self.statusbarWin['render'].GetValue():
00587             self.OnRender(None)
00588 
00589     def OnToggleShowRegion(self, event):
00590         """
00591         Show/Hide extent in map canvas
00592         """
00593         if self.statusbarWin['region'].GetValue():
00594             # show extent
00595             self.MapWindow.regionCoords = []
00596         else:
00597             del self.MapWindow.regionCoords
00598 
00599         # redraw map if auto-rendering is enabled
00600         if self.statusbarWin['render'].GetValue():
00601             self.OnRender(None)
00602 
00603     def OnToggleResolution(self, event):
00604         """
00605         Use resolution of computation region settings
00606         for redering image instead of display resolution
00607         """
00608         # redraw map if auto-rendering is enabled
00609         if self.statusbarWin['render'].GetValue():
00610             self.OnRender(None)
00611         
00612     def OnToggleStatus(self, event):
00613         """
00614         Toggle status text
00615         """
00616         self.StatusbarUpdate()
00617 
00618     def OnChangeMapScale(self, event):
00619         """
00620         Map scale changed by user
00621         """
00622         scale = event.GetString()
00623 
00624         try:
00625             if scale[:2] != '1:':
00626                 raise ValueError
00627             value = int(scale[2:])
00628         except ValueError:
00629             self.statusbarWin['mapscale'].SetValue('1:%ld' % int(self.mapScaleValue))
00630             return
00631 
00632         dEW = value * (self.Map.region['cols'] / self.ppm[0])
00633         dNS = value * (self.Map.region['rows'] / self.ppm[1])
00634         self.Map.region['n'] = self.Map.region['center_northing'] + dNS / 2.
00635         self.Map.region['s'] = self.Map.region['center_northing'] - dNS / 2.
00636         self.Map.region['w'] = self.Map.region['center_easting']  - dEW / 2.
00637         self.Map.region['e'] = self.Map.region['center_easting']  + dEW / 2.
00638         
00639         # add to zoom history
00640         self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
00641                                    self.Map.region['e'], self.Map.region['w'])
00642         
00643         # redraw a map
00644         self.MapWindow.UpdateMap()
00645         self.statusbarWin['mapscale'].SetFocus()
00646         
00647     def OnGoTo(self, event):
00648         """
00649         Go to position
00650         """
00651         #GCPNo = int(event.GetString())
00652         GCPNo = self.statusbarWin['goto'].GetValue()
00653 
00654         if GCPNo < 0 or GCPNo > len(self.mapcoordlist):
00655             wx.MessageBox(parent=self,
00656                   message="%s 1 - %s." % (_("Valid Range:"),
00657                                  len(self.mapcoordlist)),
00658                   caption=_("Invalid GCP Number"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
00659             return
00660 
00661         if GCPNo == 0:
00662             return
00663 
00664         self.list.selectedkey = GCPNo
00665         self.list.selected = self.list.FindItemData(-1, GCPNo)
00666         self.list.render = False
00667         self.list.SetItemState(self.list.selected,
00668                           wx.LIST_STATE_SELECTED,
00669                           wx.LIST_STATE_SELECTED)
00670         self.list.render = True
00671         
00672         # Source MapWindow:
00673         begin = (self.mapcoordlist[GCPNo][1], self.mapcoordlist[GCPNo][2])
00674         begin = self.SrcMapWindow.Cell2Pixel(begin)
00675         end = begin
00676         self.SrcMapWindow.Zoom(begin, end, 0)
00677 
00678         # redraw map
00679         self.SrcMapWindow.UpdateMap()
00680 
00681         if self.show_target:
00682             # Target MapWindow:
00683             begin = (self.mapcoordlist[GCPNo][3], self.mapcoordlist[GCPNo][4])
00684             begin = self.TgtMapWindow.Cell2Pixel(begin)
00685             end = begin
00686             self.TgtMapWindow.Zoom(begin, end, 0)
00687 
00688             # redraw map
00689             self.TgtMapWindow.UpdateMap()
00690 
00691         self.statusbarWin['goto'].SetFocus()
00692         
00693     def StatusbarUpdate(self):
00694         """!Update statusbar content"""
00695 
00696         self.statusbarWin['region'].Hide()
00697         self.statusbarWin['resolution'].Hide()
00698         self.statusbarWin['mapscale'].Hide()
00699         self.statusbarWin['goto'].Hide()
00700         self.mapScaleValue = self.ppm = None
00701 
00702         if self.statusbarWin['toggle'].GetSelection() == 0: # Coordinates
00703             self.statusbar.SetStatusText("", 0)
00704             # enable long help
00705             self.StatusbarEnableLongHelp()
00706 
00707         elif self.statusbarWin['toggle'].GetSelection() in (1, 2): # Extent
00708             sel = self.statusbarWin['toggle'].GetSelection()
00709             if sel == 1:
00710                 region = self.Map.region
00711             else:
00712                 region = self.Map.GetRegion() # computation region
00713 
00714             precision = int(UserSettings.Get(group = 'projection', key = 'format',
00715                                              subkey = 'precision'))
00716             format = UserSettings.Get(group = 'projection', key = 'format',
00717                                       subkey = 'll')
00718             
00719             if self.Map.projinfo['proj'] == 'll' and format == 'DMS':
00720                 w, s = utils.Deg2DMS(region["w"], region["s"],
00721                                      string = False, precision = precision)
00722                 e, n = utils.Deg2DMS(region["e"], region["n"],
00723                                      string = False, precision = precision)
00724                 if sel == 1:
00725                     self.statusbar.SetStatusText("%s - %s, %s - %s" %
00726                                                  (w, e, s, n), 0)
00727                 else:
00728                     ewres, nsres = utils.Deg2DMS(region['ewres'], region['nsres'],
00729                                                  string = False, precision = precision)
00730                     self.statusbar.SetStatusText("%s - %s, %s - %s (%s, %s)" %
00731                                                  (w, e, s, n, ewres, nsres), 0)
00732             else:
00733                 w, s = region["w"], region["s"]
00734                 e, n = region["e"], region["n"]
00735                 if sel == 1:
00736                     self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f" %
00737                                                  (precision, w, precision, e,
00738                                                   precision, s, precision, n), 0)
00739                 else:
00740                     ewres, nsres = region['ewres'], region['nsres']
00741                     self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f (%.*f, %.*f)" %
00742                                                  (precision, w, precision, e,
00743                                                   precision, s, precision, n,
00744                                                   precision, ewres, precision, nsres), 0)
00745             # enable long help
00746             self.StatusbarEnableLongHelp()
00747 
00748         elif self.statusbarWin['toggle'].GetSelection() == 3: # Show comp. extent
00749             self.statusbar.SetStatusText("", 0)
00750             self.statusbarWin['region'].Show()
00751             # disable long help
00752             self.StatusbarEnableLongHelp(False)
00753 
00754         elif self.statusbarWin['toggle'].GetSelection() == 4: # Display mode
00755             self.statusbar.SetStatusText("", 0)
00756             self.statusbarWin['resolution'].Show()
00757             # disable long help
00758             self.StatusbarEnableLongHelp(False)
00759 
00760         elif self.statusbarWin['toggle'].GetSelection() == 5: # Display geometry
00761             self.statusbar.SetStatusText("rows=%d; cols=%d; nsres=%.2f; ewres=%.2f" %
00762                                          (self.Map.region["rows"], self.Map.region["cols"],
00763                                           self.Map.region["nsres"], self.Map.region["ewres"]), 0)
00764             # enable long help
00765             self.StatusbarEnableLongHelp()
00766 
00767         elif self.statusbarWin['toggle'].GetSelection() == 6: # Map scale
00768             # TODO: need to be fixed...
00769             ### screen X region problem
00770             ### user should specify ppm
00771             dc = wx.ScreenDC()
00772             dpSizePx = wx.DisplaySize()   # display size in pixels
00773             dpSizeMM = wx.DisplaySizeMM() # display size in mm (system)
00774             dpSizeIn = (dpSizeMM[0] / 25.4, dpSizeMM[1] / 25.4) # inches
00775             sysPpi  = dc.GetPPI()
00776             comPpi = (dpSizePx[0] / dpSizeIn[0],
00777                       dpSizePx[1] / dpSizeIn[1])
00778 
00779             ppi = comPpi                  # pixel per inch
00780             self.ppm = ((ppi[0] / 2.54) * 100, # pixel per meter
00781                         (ppi[1] / 2.54) * 100)
00782 
00783             Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): size: px=%d,%d mm=%f,%f "
00784                       "in=%f,%f ppi: sys=%d,%d com=%d,%d; ppm=%f,%f" % \
00785                           (dpSizePx[0], dpSizePx[1], dpSizeMM[0], dpSizeMM[1],
00786                            dpSizeIn[0], dpSizeIn[1],
00787                            sysPpi[0], sysPpi[1], comPpi[0], comPpi[1],
00788                            self.ppm[0], self.ppm[1]))
00789 
00790             region = self.Map.region
00791 
00792             heightCm = region['rows'] / self.ppm[1] * 100
00793             widthCm  = region['cols'] / self.ppm[0] * 100
00794 
00795             Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): width_cm=%f, height_cm=%f" %
00796                       (widthCm, heightCm))
00797 
00798             xscale = (region['e'] - region['w']) / (region['cols'] / self.ppm[0])
00799             yscale = (region['n'] - region['s']) / (region['rows'] / self.ppm[1])
00800             scale = (xscale + yscale) / 2.
00801             
00802             Debug.msg(3, "MapFrame.StatusbarUpdate(mapscale): xscale=%f, yscale=%f -> scale=%f" % \
00803                           (xscale, yscale, scale))
00804 
00805             self.statusbar.SetStatusText("")
00806             try:
00807                 self.statusbarWin['mapscale'].SetValue("1:%ld" % (scale + 0.5))
00808             except TypeError:
00809                 pass
00810             self.mapScaleValue = scale
00811             self.statusbarWin['mapscale'].Show()
00812 
00813             # disable long help
00814             self.StatusbarEnableLongHelp(False)
00815 
00816         elif self.statusbarWin['toggle'].GetSelection() == 7: # go to
00817 
00818             self.statusbar.SetStatusText("")
00819             max = self.list.GetItemCount()
00820             if max < 1:
00821                 max = 1
00822             self.statusbarWin['goto'].SetRange(0, max)
00823 
00824             self.statusbarWin['goto'].Show()
00825 
00826             # disable long help
00827             self.StatusbarEnableLongHelp(False)
00828         
00829         elif self.statusbarWin['toggle'].GetSelection() == 8: # RMS error
00830             self.statusbar.SetStatusText(_("Forward: %(forw)s, Backward: %(back)s") %
00831                                          { 'forw' : self.fwd_rmserror,
00832                                            'back' : self.bkw_rmserror })
00833             # disable long help
00834             # self.StatusbarEnableLongHelp(False)
00835             
00836         else:
00837             self.statusbar.SetStatusText("", 1)
00838 
00839     def StatusbarEnableLongHelp(self, enable=True):
00840         """!Enable/disable toolbars long help"""
00841         for toolbar in self.toolbars.itervalues():
00842             if toolbar:
00843                 toolbar.EnableLongHelp(enable)
00844                 
00845     def StatusbarReposition(self):
00846         """!Reposition checkbox in statusbar"""
00847         # reposition checkbox
00848         widgets = [(0, self.statusbarWin['region']),
00849                    (0, self.statusbarWin['resolution']),
00850                    (0, self.statusbarWin['mapscale']),
00851                    (0, self.statusbarWin['progress']),
00852                    (0, self.statusbarWin['goto']),
00853                    (1, self.statusbarWin['toggle']),
00854                    (2, self.statusbarWin['mask']),
00855                    (3, self.statusbarWin['render'])]
00856         for idx, win in widgets:
00857             rect = self.statusbar.GetFieldRect(idx)
00858             wWin, hWin = win.GetBestSize()
00859             if idx == 0: # show region / mapscale / process bar
00860                 # -> size
00861                 if win == self.statusbarWin['progress']:
00862                     wWin = rect.width - 6
00863                 # -> position
00864                 # if win == self.statusbarWin['region']:
00865                 # x, y = rect.x + rect.width - wWin, rect.y - 1
00866                 # align left
00867                 # else:
00868                 x, y = rect.x + 3, rect.y - 1
00869                 w, h = wWin, rect.height + 2
00870             else: # choice || auto-rendering
00871                 x, y = rect.x, rect.y - 1
00872                 w, h = rect.width, rect.height + 2
00873                 if idx == 1: # choice
00874                     h = hWin
00875                 elif idx == 2: # mask
00876                     x += 5
00877                     y += 4
00878                 elif idx == 3: # render
00879                     x += 5
00880 
00881             win.SetPosition((x, y))
00882             win.SetSize((w, h))
00883 
00884     def SaveToFile(self, event):
00885         """!Save map to image
00886         """
00887         img = self.MapWindow.img
00888         if not img:
00889             gcmd.GMessage(parent = self,
00890                           message = _("Nothing to render (empty map). Operation canceled."))
00891             return
00892         filetype, ltype = gdialogs.GetImageHandlers(img)
00893 
00894         # get size
00895         dlg = gdialogs.ImageSizeDialog(self)
00896         dlg.CentreOnParent()
00897         if dlg.ShowModal() != wx.ID_OK:
00898             dlg.Destroy()
00899             return
00900         width, height = dlg.GetValues()
00901         dlg.Destroy()
00902         
00903         # get filename
00904         dlg = wx.FileDialog(parent = self,
00905                             message = _("Choose a file name to save the image "
00906                                         "(no need to add extension)"),
00907                             wildcard = filetype,
00908                             style=wx.SAVE | wx.FD_OVERWRITE_PROMPT)
00909         
00910         if dlg.ShowModal() == wx.ID_OK:
00911             path = dlg.GetPath()
00912             if not path:
00913                 dlg.Destroy()
00914                 return
00915             
00916             base, ext = os.path.splitext(path)
00917             fileType = ltype[dlg.GetFilterIndex()]['type']
00918             extType  = ltype[dlg.GetFilterIndex()]['ext']
00919             if ext != extType:
00920                 path = base + '.' + extType
00921             
00922             self.MapWindow.SaveToFile(path, fileType,
00923                                       width, height)
00924             
00925         dlg.Destroy()
00926 
00927     def PrintMenu(self, event):
00928         """
00929         Print options and output menu for map display
00930         """
00931         point = wx.GetMousePosition()
00932         printmenu = wx.Menu()
00933         # Add items to the menu
00934         setup = wx.MenuItem(printmenu, wx.ID_ANY, _('Page setup'))
00935         printmenu.AppendItem(setup)
00936         self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup)
00937 
00938         preview = wx.MenuItem(printmenu, wx.ID_ANY, _('Print preview'))
00939         printmenu.AppendItem(preview)
00940         self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview)
00941 
00942         doprint = wx.MenuItem(printmenu, wx.ID_ANY, _('Print display'))
00943         printmenu.AppendItem(doprint)
00944         self.Bind(wx.EVT_MENU, self.printopt.OnDoPrint, doprint)
00945 
00946         # Popup the menu.  If an item is selected then its handler
00947         # will be called before PopupMenu returns.
00948         self.PopupMenu(printmenu)
00949         printmenu.Destroy()
00950 
00951     def GetRender(self):
00952         """!Returns current instance of render.Map()
00953         """
00954         return self.Map
00955 
00956     def GetWindow(self):
00957         """!Get map window"""
00958         return self.MapWindow
00959     
00960     def FormatDist(self, dist):
00961         """!Format length numbers and units in a nice way,
00962         as a function of length. From code by Hamish Bowman
00963         Grass Development Team 2006"""
00964 
00965         mapunits = self.Map.projinfo['units']
00966         if mapunits == 'metres': mapunits = 'meters'
00967         outunits = mapunits
00968         dist = float(dist)
00969         divisor = 1.0
00970 
00971         # figure out which units to use
00972         if mapunits == 'meters':
00973             if dist > 2500.0:
00974                 outunits = 'km'
00975                 divisor = 1000.0
00976             else: outunits = 'm'
00977         elif mapunits == 'feet':
00978             # nano-bug: we match any "feet", but US Survey feet is really
00979             #  5279.9894 per statute mile, or 10.6' per 1000 miles. As >1000
00980             #  miles the tick markers are rounded to the nearest 10th of a
00981             #  mile (528'), the difference in foot flavours is ignored.
00982             if dist > 5280.0:
00983                 outunits = 'miles'
00984                 divisor = 5280.0
00985             else:
00986                 outunits = 'ft'
00987         elif 'degree' in mapunits:
00988             if dist < 1:
00989                 outunits = 'min'
00990                 divisor = (1/60.0)
00991             else:
00992                 outunits = 'deg'
00993 
00994         # format numbers in a nice way
00995         if (dist/divisor) >= 2500.0:
00996             outdist = round(dist/divisor)
00997         elif (dist/divisor) >= 1000.0:
00998             outdist = round(dist/divisor,1)
00999         elif (dist/divisor) > 0.0:
01000             outdist = round(dist/divisor,int(math.ceil(3-math.log10(dist/divisor))))
01001         else:
01002             outdist = float(dist/divisor)
01003 
01004         return (outdist, outunits)
01005 
01006     def OnZoomToMap(self, event):
01007         """!
01008         Set display extents to match selected raster (including NULLs)
01009         or vector map.
01010         """
01011         self.MapWindow.ZoomToMap(layers = self.Map.GetListOfLayers())
01012 
01013     def OnZoomToRaster(self, event):
01014         """!
01015         Set display extents to match selected raster map (ignore NULLs)
01016         """
01017         self.MapWindow.ZoomToMap(ignoreNulls = True)
01018 
01019     def OnZoomToWind(self, event):
01020         """!Set display geometry to match computational region
01021         settings (set with g.region)
01022         """
01023         self.MapWindow.ZoomToWind()
01024         
01025     def OnZoomToDefault(self, event):
01026         """!Set display geometry to match default region settings
01027         """
01028         self.MapWindow.ZoomToDefault()
01029         
01030     def OnZoomToSaved(self, event):
01031         """!Set display geometry to match extents in
01032         saved region file
01033         """
01034         self.MapWindow.ZoomToSaved()
01035         
01036     def OnDisplayToWind(self, event):
01037         """!Set computational region (WIND file) to match display
01038         extents
01039         """
01040         self.MapWindow.DisplayToWind()
01041  
01042     def SaveDisplayRegion(self, event):
01043         """!Save display extents to named region file.
01044         """
01045         self.MapWindow.SaveDisplayRegion()
01046         
01047     def OnZoomMenu(self, event):
01048         """!Popup Zoom menu
01049         """
01050         point = wx.GetMousePosition()
01051         zoommenu = wx.Menu()
01052         # Add items to the menu
01053 
01054         zoomwind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to computational region (set with g.region)'))
01055         zoommenu.AppendItem(zoomwind)
01056         self.Bind(wx.EVT_MENU, self.OnZoomToWind, zoomwind)
01057 
01058         zoomdefault = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to default region'))
01059         zoommenu.AppendItem(zoomdefault)
01060         self.Bind(wx.EVT_MENU, self.OnZoomToDefault, zoomdefault)
01061 
01062         zoomsaved = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to saved region'))
01063         zoommenu.AppendItem(zoomsaved)
01064         self.Bind(wx.EVT_MENU, self.OnZoomToSaved, zoomsaved)
01065 
01066         savewind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Set computational region from display'))
01067         zoommenu.AppendItem(savewind)
01068         self.Bind(wx.EVT_MENU, self.OnDisplayToWind, savewind)
01069 
01070         savezoom = wx.MenuItem(zoommenu, wx.ID_ANY, _('Save display geometry to named region'))
01071         zoommenu.AppendItem(savezoom)
01072         self.Bind(wx.EVT_MENU, self.SaveDisplayRegion, savezoom)
01073 
01074         # Popup the menu. If an item is selected then its handler
01075         # will be called before PopupMenu returns.
01076         self.PopupMenu(zoommenu)
01077         zoommenu.Destroy()
01078         
01079     def SetProperties(self, render=False, mode=0, showCompExtent=False,
01080                       constrainRes=False, projection=False):
01081         """!Set properies of map display window"""
01082         self.statusbarWin['render'].SetValue(render)
01083         self.statusbarWin['toggle'].SetSelection(mode)
01084         self.StatusbarUpdate()
01085         self.statusbarWin['region'].SetValue(showCompExtent)
01086         self.statusbarWin['resolution'].SetValue(constrainRes)
01087         if showCompExtent:
01088             self.MapWindow.regionCoords = []
01089         
01090     def IsStandalone(self):
01091         """!Check if Map display is standalone"""
01092         if self._layerManager:
01093             return False
01094         
01095         return True
01096     
01097     def GetLayerManager(self):
01098         """!Get reference to Layer Manager
01099 
01100         @return window reference
01101         @return None (if standalone)
01102         """
01103         return self._layerManager
01104     
01105 # end of class MapFrame
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines