GRASS Programmer's Manual  6.4.2(2012)
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gcpmapdisp.py
Go to the documentation of this file.
1 """!
2 @package gcpmapdisp.py
3 
4 @brief display to manage ground control points with two toolbars, one for
5 various display management functions, one for manipulating GCPs.
6 
7 Classes:
8 - MapFrame
9 
10 (C) 2006-2010 by the GRASS Development Team
11 This program is free software under the GNU General Public
12 License (>=v2). Read the file COPYING that comes with GRASS
13 for details.
14 
15 Derived from mapdisp.py
16 
17 @author Markus Metz
18 """
19 
20 import os
21 import sys
22 import glob
23 import math
24 import tempfile
25 import copy
26 import platform
27 
28 import globalvar
29 import wx
30 import wx.aui
31 
32 try:
33  import subprocess
34 except:
35  CompatPath = os.path.join(globalvar.ETCWXDIR)
36  sys.path.append(CompatPath)
37  from compat import subprocess
38 
39 gmpath = os.path.join(globalvar.ETCWXDIR, "icons")
40 sys.path.append(gmpath)
41 
42 grassPath = os.path.join(globalvar.ETCDIR, "python")
43 sys.path.append(grassPath)
44 
45 import render
46 import toolbars
47 import menuform
48 import gselect
49 import disp_print
50 import gcmd
51 import dbm
52 import dbm_dialogs
53 import globalvar
54 import utils
55 import gdialogs
56 from grass.script import core as grass
57 from debug import Debug
58 from icon import Icons
59 from preferences import globalSettings as UserSettings
60 
61 from mapdisp_command import Command
62 from mapdisp_window import BufferedWindow
63 
64 # for standalone app
65 cmdfilename = None
66 
67 class MapFrame(wx.Frame):
68  """!Main frame for map display window. Drawing takes place in
69  child double buffered drawing window.
70  """
71  def __init__(self, parent=None, id=wx.ID_ANY, title=_("GRASS GIS Manage Ground Control Points"),
72  style=wx.DEFAULT_FRAME_STYLE, toolbars=["gcpdisp"],
73  tree=None, notebook=None, lmgr=None, page=None,
74  Map=None, auimgr=None, **kwargs):
75  """!Main map display window with toolbars, statusbar and
76  DrawWindow
77 
78  @param toolbars array of activated toolbars, e.g. ['map', 'digit']
79  @param tree reference to layer tree
80  @param notebook control book ID in Layer Manager
81  @param lmgr Layer Manager
82  @param page notebook page with layer tree
83  @param Map instance of render.Map
84  @param auimgs AUI manager
85  @param kwargs wx.Frame attribures
86  """
87  self._layerManager = lmgr # Layer Manager object
88  self.Map = Map # instance of render.Map
89  self.tree = tree # Layer Manager layer tree object
90  self.page = page # Notebook page holding the layer tree
91  self.layerbook = notebook # Layer Manager layer tree notebook
92  self.parent = parent
93 
94  if 'name' not in kwargs:
95  kwargs['name'] = 'GCPMapWindow'
96  wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
97 
98  # available cursors
99  self.cursors = {
100  # default: cross
101  # "default" : wx.StockCursor(wx.CURSOR_DEFAULT),
102  "default" : wx.StockCursor(wx.CURSOR_ARROW),
103  "cross" : wx.StockCursor(wx.CURSOR_CROSS),
104  "hand" : wx.StockCursor(wx.CURSOR_HAND),
105  "pencil" : wx.StockCursor(wx.CURSOR_PENCIL),
106  "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
107  }
108 
109  #
110  # set the size & system icon
111  #
112  self.SetClientSize(self.GetSize())
113  self.iconsize = (16, 16)
114 
115  self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_map.ico'), wx.BITMAP_TYPE_ICO))
116 
117  #
118  # Fancy gui
119  #
120  self._mgr = wx.aui.AuiManager(self)
121 
122  #
123  # Add toolbars
124  #
125  self.toolbars = { 'map' : None,
126  'vdigit' : None,
127  'georect' : None,
128  'gcpdisp' : None,
129  'gcpman' : None,
130  'nviz' : None }
131 
132  for toolb in toolbars:
133  self.AddToolbar(toolb)
134 
135  self.activemap = self.toolbars['gcpdisp'].togglemap
136  self.activemap.SetSelection(0)
137  self.SrcMap = self.grwiz.SrcMap # instance of render.Map
138  self.TgtMap = self.grwiz.TgtMap # instance of render.Map
139  self._mgr.SetDockSizeConstraint(0.5, 0.5)
140 
141  #
142  # Add statusbar
143  #
144  self.statusbar = self.CreateStatusBar(number=4, style=0)
145  self.statusbar.SetStatusWidths([-5, -2, -1, -1])
146  self.statusbarWin = dict()
147  self.statusbarWin['toggle'] = wx.Choice(self.statusbar, wx.ID_ANY,
148  choices = [_("Coordinates"),
149  _("Extent"),
150  _("Comp. region"),
151  _("Show comp. extent"),
152  _("Display mode"),
153  _("Display geometry"),
154  _("Map scale"),
155  _("Go to GCP No."),
156  _("RMS error")])
157  # set StatusBar to Go to GCP No.
158  self.statusbarWin['toggle'].SetSelection(7)
159 
160  self.statusbar.Bind(wx.EVT_CHOICE, self.OnToggleStatus, self.statusbarWin['toggle'])
161  # auto-rendering checkbox
162  self.statusbarWin['render'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
163  label=_("Render"))
164  self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleRender, self.statusbarWin['render'])
165  self.statusbarWin['render'].SetValue(UserSettings.Get(group='display',
166  key='autoRendering',
167  subkey='enabled'))
168  self.statusbarWin['render'].SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering")))
169  # show region
170  self.statusbarWin['region'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
171  label=_("Show computational extent"))
172  self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion, self.statusbarWin['region'])
173 
174  self.statusbarWin['region'].SetValue(False)
175  self.statusbarWin['region'].Hide()
176  self.statusbarWin['region'].SetToolTip(wx.ToolTip (_("Show/hide computational "
177  "region extent (set with g.region). "
178  "Display region drawn as a blue box inside the "
179  "computational region, "
180  "computational region inside a display region "
181  "as a red box).")))
182  # set resolution
183  self.statusbarWin['resolution'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
184  label=_("Constrain display resolution to computational settings"))
185  self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleResolution, self.statusbarWin['resolution'])
186  self.statusbarWin['resolution'].SetValue(UserSettings.Get(group='display', key='compResolution', subkey='enabled'))
187  self.statusbarWin['resolution'].Hide()
188  self.statusbarWin['resolution'].SetToolTip(wx.ToolTip (_("Constrain display resolution "
189  "to computational region settings. "
190  "Default value for new map displays can "
191  "be set up in 'User GUI settings' dialog.")))
192  # map scale
193  self.statusbarWin['mapscale'] = wx.ComboBox(parent = self.statusbar, id = wx.ID_ANY,
194  style = wx.TE_PROCESS_ENTER,
195  size=(150, -1))
196  self.statusbarWin['mapscale'].SetItems(['1:1000',
197  '1:5000',
198  '1:10000',
199  '1:25000',
200  '1:50000',
201  '1:100000',
202  '1:1000000'])
203  self.statusbarWin['mapscale'].Hide()
204  self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale, self.statusbarWin['mapscale'])
205  self.statusbar.Bind(wx.EVT_COMBOBOX, self.OnChangeMapScale, self.statusbarWin['mapscale'])
206 
207  # go to
208  self.statusbarWin['goto'] = wx.SpinCtrl(parent=self.statusbar, id=wx.ID_ANY,
209  min=0)
210  self.statusbar.Bind(wx.EVT_SPINCTRL, self.OnGoTo, self.statusbarWin['goto'])
211  self.statusbarWin['goto'].Hide()
212  self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnGoTo, self.statusbarWin['goto'])
213 
214  # projection, unused but BufferedWindow checks for it
215  self.statusbarWin['projection'] = wx.CheckBox(parent=self.statusbar, id=wx.ID_ANY,
216  label=_("Use defined projection"))
217  self.statusbarWin['projection'].SetValue(False)
218  size = self.statusbarWin['projection'].GetSize()
219  self.statusbarWin['projection'].SetMinSize((size[0] + 150, size[1]))
220  self.statusbarWin['projection'].SetToolTip(wx.ToolTip (_("Reproject coordinates displayed "
221  "in the statusbar. Projection can be "
222  "defined in GUI preferences dialog "
223  "(tab 'Display')")))
224  self.statusbarWin['projection'].Hide()
225 
226  # mask
227  self.statusbarWin['mask'] = wx.StaticText(parent = self.statusbar, id = wx.ID_ANY,
228  label = '')
229  self.statusbarWin['mask'].SetForegroundColour(wx.Colour(255, 0, 0))
230 
231  # on-render gauge
232  self.statusbarWin['progress'] = wx.Gauge(parent=self.statusbar, id=wx.ID_ANY,
233  range=0, style=wx.GA_HORIZONTAL)
234  self.statusbarWin['progress'].Hide()
235 
236  self.StatusbarReposition() # reposition statusbar
237 
238  #
239  # Init map display (buffered DC & set default cursor)
240  #
241  self.grwiz.SwitchEnv('source')
242  self.SrcMapWindow = BufferedWindow(self, id=wx.ID_ANY,
243  Map=self.SrcMap, tree=self.tree, lmgr=self._layerManager)
244 
245  self.grwiz.SwitchEnv('target')
246  self.TgtMapWindow = BufferedWindow(self, id=wx.ID_ANY,
247  Map=self.TgtMap, tree=self.tree, lmgr=self._layerManager)
249  self.Map = self.SrcMap
250  self.SrcMapWindow.SetCursor(self.cursors["cross"])
251  self.TgtMapWindow.SetCursor(self.cursors["cross"])
252 
253  #
254  # initialize region values
255  #
256  self.__InitDisplay()
257 
258  #
259  # Bind various events
260  #
261  self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
262  self.Bind(render.EVT_UPDATE_PRGBAR, self.OnUpdateProgress)
263  self.Bind(wx.EVT_SIZE, self.OnDispResize)
264  self.activemap.Bind(wx.EVT_CHOICE, self.OnUpdateActive)
265 
266  #
267  # Update fancy gui style
268  #
269  # AuiManager wants a CentrePane, workaround to get two equally sized windows
270  self.list = self.CreateGCPList()
271 
272  #self.SrcMapWindow.SetSize((300, 300))
273  #self.TgtMapWindow.SetSize((300, 300))
274  self.list.SetSize((100, 150))
275  self._mgr.AddPane(self.list, wx.aui.AuiPaneInfo().
276  Name("gcplist").Caption(_("GCP List")).LeftDockable(False).
277  RightDockable(False).PinButton().FloatingSize((600,200)).
278  CloseButton(False).DestroyOnClose(True).
279  Top().Layer(1).MinSize((200,100)))
280  self._mgr.AddPane(self.SrcMapWindow, wx.aui.AuiPaneInfo().
281  Name("source").Caption(_("Source Display")).Dockable(False).
282  CloseButton(False).DestroyOnClose(True).Floatable(False).
283  Centre())
284  self._mgr.AddPane(self.TgtMapWindow, wx.aui.AuiPaneInfo().
285  Name("target").Caption(_("Target Display")).Dockable(False).
286  CloseButton(False).DestroyOnClose(True).Floatable(False).
287  Right().Layer(0))
288 
289  srcwidth, srcheight = self.SrcMapWindow.GetSize()
290  tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
291  srcwidth = (srcwidth + tgtwidth) / 2
292  self._mgr.GetPane("target").Hide()
293  self._mgr.Update()
294  self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
295  self._mgr.GetPane("target").BestSize((srcwidth, srcheight))
296  if self.show_target:
297  self._mgr.GetPane("target").Show()
298  else:
299  self.activemap.Enable(False)
300  # needed by Mac OS, does not harm on Linux, breaks display on Windows
301  if platform.system() != 'Windows':
302  self._mgr.Update()
303 
304  #
305  # Init print module and classes
306  #
308 
309  #
310  # Initialization of digitization tool
311  #
312  self.digit = None
313 
314  # set active map
315  self.MapWindow = self.SrcMapWindow
316  self.Map = self.SrcMap
317 
318  # do not init zoom history here, that happens when zooming to map(s)
319 
320  #
321  # Re-use dialogs
322  #
323  self.dialogs = {}
324  self.dialogs['attributes'] = None
325  self.dialogs['category'] = None
326  self.dialogs['barscale'] = None
327  self.dialogs['legend'] = None
328 
329  self.decorationDialog = None # decoration/overlays
330 
331  def AddToolbar(self, name):
332  """!Add defined toolbar to the window
333 
334  Currently known toolbars are:
335  - 'map' - basic map toolbar
336  - 'vdigit' - vector digitizer
337  - 'gcpdisp' - GCP Manager, Display
338  - 'gcpman' - GCP Manager, points management
339  - 'georect' - georectifier
340  - 'nviz' - 3D view mode
341  """
342  # default toolbar
343  if name == "map":
344  self.toolbars['map'] = toolbars.MapToolbar(self, self.Map)
345 
346  self._mgr.AddPane(self.toolbars['map'],
347  wx.aui.AuiPaneInfo().
348  Name("maptoolbar").Caption(_("Map Toolbar")).
349  ToolbarPane().Top().
350  LeftDockable(False).RightDockable(False).
351  BottomDockable(False).TopDockable(True).
352  CloseButton(False).Layer(2).
353  BestSize((self.toolbars['map'].GetSize())))
354 
355  # GCP display
356  elif name == "gcpdisp":
357  self.toolbars['gcpdisp'] = toolbars.GCPDisplayToolbar(self)
358 
359  self._mgr.AddPane(self.toolbars['gcpdisp'],
360  wx.aui.AuiPaneInfo().
361  Name("gcpdisplaytoolbar").Caption(_("GCP Display toolbar")).
362  ToolbarPane().Top().
363  LeftDockable(False).RightDockable(False).
364  BottomDockable(False).TopDockable(True).
365  CloseButton(False).Layer(2))
366 
367  if self.show_target == False:
368  self.toolbars['gcpdisp'].Enable('zoommenu', enable = False)
369 
370  self.toolbars['gcpman'] = toolbars.GCPManToolbar(self)
371 
372  self._mgr.AddPane(self.toolbars['gcpman'],
373  wx.aui.AuiPaneInfo().
374  Name("gcpmanagertoolbar").Caption(_("GCP Manager toolbar")).
375  ToolbarPane().Top().Row(1).
376  LeftDockable(False).RightDockable(False).
377  BottomDockable(False).TopDockable(True).
378  CloseButton(False).Layer(2))
379 
380  self._mgr.Update()
381 
382  def __InitDisplay(self):
383  """
384  Initialize map display, set dimensions and map region
385  """
386  self.width, self.height = self.GetClientSize()
387 
388  Debug.msg(2, "MapFrame.__InitDisplay():")
389  self.grwiz.SwitchEnv('source')
390  self.SrcMap.ChangeMapSize(self.GetClientSize())
391  self.SrcMap.region = self.SrcMap.GetRegion() # g.region -upgc
392  self.grwiz.SwitchEnv('target')
393  self.TgtMap.ChangeMapSize(self.GetClientSize())
394  self.TgtMap.region = self.TgtMap.GetRegion() # g.region -upgc
395  # self.SrcMap.SetRegion() # adjust region to match display window
396  # self.TgtMap.SetRegion() # adjust region to match display window
397 
398  def OnUpdateProgress(self, event):
399  """
400  Update progress bar info
401  """
402  self.statusbarWin['progress'].SetValue(event.value)
403 
404  event.Skip()
405 
406  def OnFocus(self, event):
407  """
408  Change choicebook page to match display.
409  Or set display for georectifying
410  """
411  if self._layerManager and \
412  self._layerManager.gcpmanagement:
413  # in GCP Management, set focus to current MapWindow for mouse actions
414  self.OnPointer(event)
415  self.MapWindow.SetFocus()
416  else:
417  # change bookcontrol page to page associated with display
418  # GCP Manager: use bookcontrol?
419  if self.page:
420  pgnum = self.layerbook.GetPageIndex(self.page)
421  if pgnum > -1:
422  self.layerbook.SetSelection(pgnum)
423 
424  event.Skip()
425 
426  def OnDraw(self, event):
427  """!Re-display current map composition
428  """
429  self.MapWindow.UpdateMap(render = False)
430 
431  def OnRender(self, event):
432  """!Re-render map composition (each map layer)
433  """
434  # delete tmp map layers (queries)
435  qlayer = self.Map.GetListOfLayers(l_name=globalvar.QUERYLAYER)
436  for layer in qlayer:
437  self.Map.DeleteLayer(layer)
438 
439  self.SrcMapWindow.UpdateMap(render=True)
440  if self.show_target:
441  self.TgtMapWindow.UpdateMap(render=True)
442 
443  # update statusbar
444  self.StatusbarUpdate()
445 
446  def OnPointer(self, event):
447  """!Pointer button clicked
448  """
449  # change the cursor
450  self.SrcMapWindow.SetCursor(self.cursors["cross"])
451  self.SrcMapWindow.mouse['use'] = "pointer"
452  self.SrcMapWindow.mouse['box'] = "point"
453  self.TgtMapWindow.SetCursor(self.cursors["cross"])
454  self.TgtMapWindow.mouse['use'] = "pointer"
455  self.TgtMapWindow.mouse['box'] = "point"
456 
457  def OnZoomIn(self, event):
458  """
459  Zoom in the map.
460  Set mouse cursor, zoombox attributes, and zoom direction
461  """
462  if self.toolbars['map']:
463  self.toolbars['map'].OnTool(event)
464  self.toolbars['map'].action['desc'] = ''
465 
466  self.MapWindow.mouse['use'] = "zoom"
467  self.MapWindow.mouse['box'] = "box"
468  self.MapWindow.zoomtype = 1
469  self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
470 
471  # change the cursor
472  self.MapWindow.SetCursor(self.cursors["cross"])
473 
474  if self.MapWindow == self.SrcMapWindow:
475  win = self.TgtMapWindow
476  elif self.MapWindow == self.TgtMapWindow:
477  win = self.SrcMapWindow
478 
479  win.mouse['use'] = "zoom"
480  win.mouse['box'] = "box"
481  win.zoomtype = 1
482  win.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
483 
484  # change the cursor
485  win.SetCursor(self.cursors["cross"])
486 
487  def OnZoomOut(self, event):
488  """
489  Zoom out the map.
490  Set mouse cursor, zoombox attributes, and zoom direction
491  """
492  if self.toolbars['map']:
493  self.toolbars['map'].OnTool(event)
494  self.toolbars['map'].action['desc'] = ''
495 
496  self.MapWindow.mouse['use'] = "zoom"
497  self.MapWindow.mouse['box'] = "box"
498  self.MapWindow.zoomtype = -1
499  self.MapWindow.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
500 
501  # change the cursor
502  self.MapWindow.SetCursor(self.cursors["cross"])
503 
504  if self.MapWindow == self.SrcMapWindow:
505  win = self.TgtMapWindow
506  elif self.MapWindow == self.TgtMapWindow:
507  win = self.SrcMapWindow
508 
509  win.mouse['use'] = "zoom"
510  win.mouse['box'] = "box"
511  win.zoomtype = -1
512  win.pen = wx.Pen(colour='Red', width=2, style=wx.SHORT_DASH)
513 
514  # change the cursor
515  win.SetCursor(self.cursors["cross"])
516 
517  def OnZoomBack(self, event):
518  """
519  Zoom last (previously stored position)
520  """
521  self.MapWindow.ZoomBack()
522 
523  def OnPan(self, event):
524  """
525  Panning, set mouse to drag
526  """
527  if self.toolbars['map']:
528  self.toolbars['map'].OnTool(event)
529  self.toolbars['map'].action['desc'] = ''
530 
531  self.MapWindow.mouse['use'] = "pan"
532  self.MapWindow.mouse['box'] = "pan"
533  self.MapWindow.zoomtype = 0
534 
535  # change the cursor
536  self.MapWindow.SetCursor(self.cursors["hand"])
537 
538  if self.MapWindow == self.SrcMapWindow:
539  win = self.TgtMapWindow
540  elif self.MapWindow == self.TgtMapWindow:
541  win = self.SrcMapWindow
542 
543  win.mouse['use'] = "pan"
544  win.mouse['box'] = "pan"
545  win.zoomtype = 0
546 
547  # change the cursor
548  win.SetCursor(self.cursors["hand"])
549 
550  def OnErase(self, event):
551  """
552  Erase the canvas
553  """
554  self.MapWindow.EraseMap()
555 
556  if self.MapWindow == self.SrcMapWindow:
557  win = self.TgtMapWindow
558  elif self.MapWindow == self.TgtMapWindow:
559  win = self.SrcMapWindow
560 
561  win.EraseMap()
562 
563  def OnZoomRegion(self, event):
564  """
565  Zoom to region
566  """
567  self.Map.getRegion()
568  self.Map.getResolution()
569  self.UpdateMap()
570  # event.Skip()
571 
572  def OnAlignRegion(self, event):
573  """
574  Align region
575  """
576  if not self.Map.alignRegion:
577  self.Map.alignRegion = True
578  else:
579  self.Map.alignRegion = False
580  # event.Skip()
581 
582  def OnToggleRender(self, event):
583  """
584  Enable/disable auto-rendering
585  """
586  if self.statusbarWin['render'].GetValue():
587  self.OnRender(None)
588 
589  def OnToggleShowRegion(self, event):
590  """
591  Show/Hide extent in map canvas
592  """
593  if self.statusbarWin['region'].GetValue():
594  # show extent
595  self.MapWindow.regionCoords = []
596  else:
597  del self.MapWindow.regionCoords
598 
599  # redraw map if auto-rendering is enabled
600  if self.statusbarWin['render'].GetValue():
601  self.OnRender(None)
602 
603  def OnToggleResolution(self, event):
604  """
605  Use resolution of computation region settings
606  for redering image instead of display resolution
607  """
608  # redraw map if auto-rendering is enabled
609  if self.statusbarWin['render'].GetValue():
610  self.OnRender(None)
611 
612  def OnToggleStatus(self, event):
613  """
614  Toggle status text
615  """
616  self.StatusbarUpdate()
617 
618  def OnChangeMapScale(self, event):
619  """
620  Map scale changed by user
621  """
622  scale = event.GetString()
623 
624  try:
625  if scale[:2] != '1:':
626  raise ValueError
627  value = int(scale[2:])
628  except ValueError:
629  self.statusbarWin['mapscale'].SetValue('1:%ld' % int(self.mapScaleValue))
630  return
631 
632  dEW = value * (self.Map.region['cols'] / self.ppm[0])
633  dNS = value * (self.Map.region['rows'] / self.ppm[1])
634  self.Map.region['n'] = self.Map.region['center_northing'] + dNS / 2.
635  self.Map.region['s'] = self.Map.region['center_northing'] - dNS / 2.
636  self.Map.region['w'] = self.Map.region['center_easting'] - dEW / 2.
637  self.Map.region['e'] = self.Map.region['center_easting'] + dEW / 2.
638 
639  # add to zoom history
640  self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
641  self.Map.region['e'], self.Map.region['w'])
642 
643  # redraw a map
644  self.MapWindow.UpdateMap()
645  self.statusbarWin['mapscale'].SetFocus()
646 
647  def OnGoTo(self, event):
648  """
649  Go to position
650  """
651  #GCPNo = int(event.GetString())
652  GCPNo = self.statusbarWin['goto'].GetValue()
653 
654  if GCPNo < 0 or GCPNo > len(self.mapcoordlist):
655  wx.MessageBox(parent=self,
656  message="%s 1 - %s." % (_("Valid Range:"),
657  len(self.mapcoordlist)),
658  caption=_("Invalid GCP Number"), style=wx.OK | wx.ICON_ERROR | wx.CENTRE)
659  return
660 
661  if GCPNo == 0:
662  return
663 
664  self.list.selectedkey = GCPNo
665  self.list.selected = self.list.FindItemData(-1, GCPNo)
666  self.list.render = False
667  self.list.SetItemState(self.list.selected,
668  wx.LIST_STATE_SELECTED,
669  wx.LIST_STATE_SELECTED)
670  self.list.render = True
671 
672  # Source MapWindow:
673  begin = (self.mapcoordlist[GCPNo][1], self.mapcoordlist[GCPNo][2])
674  begin = self.SrcMapWindow.Cell2Pixel(begin)
675  end = begin
676  self.SrcMapWindow.Zoom(begin, end, 0)
677 
678  # redraw map
679  self.SrcMapWindow.UpdateMap()
680 
681  if self.show_target:
682  # Target MapWindow:
683  begin = (self.mapcoordlist[GCPNo][3], self.mapcoordlist[GCPNo][4])
684  begin = self.TgtMapWindow.Cell2Pixel(begin)
685  end = begin
686  self.TgtMapWindow.Zoom(begin, end, 0)
687 
688  # redraw map
689  self.TgtMapWindow.UpdateMap()
690 
691  self.statusbarWin['goto'].SetFocus()
692 
693  def StatusbarUpdate(self):
694  """!Update statusbar content"""
695 
696  self.statusbarWin['region'].Hide()
697  self.statusbarWin['resolution'].Hide()
698  self.statusbarWin['mapscale'].Hide()
699  self.statusbarWin['goto'].Hide()
700  self.mapScaleValue = self.ppm = None
701 
702  if self.statusbarWin['toggle'].GetSelection() == 0: # Coordinates
703  self.statusbar.SetStatusText("", 0)
704  # enable long help
706 
707  elif self.statusbarWin['toggle'].GetSelection() in (1, 2): # Extent
708  sel = self.statusbarWin['toggle'].GetSelection()
709  if sel == 1:
710  region = self.Map.region
711  else:
712  region = self.Map.GetRegion() # computation region
713 
714  precision = int(UserSettings.Get(group = 'projection', key = 'format',
715  subkey = 'precision'))
716  format = UserSettings.Get(group = 'projection', key = 'format',
717  subkey = 'll')
718 
719  if self.Map.projinfo['proj'] == 'll' and format == 'DMS':
720  w, s = utils.Deg2DMS(region["w"], region["s"],
721  string = False, precision = precision)
722  e, n = utils.Deg2DMS(region["e"], region["n"],
723  string = False, precision = precision)
724  if sel == 1:
725  self.statusbar.SetStatusText("%s - %s, %s - %s" %
726  (w, e, s, n), 0)
727  else:
728  ewres, nsres = utils.Deg2DMS(region['ewres'], region['nsres'],
729  string = False, precision = precision)
730  self.statusbar.SetStatusText("%s - %s, %s - %s (%s, %s)" %
731  (w, e, s, n, ewres, nsres), 0)
732  else:
733  w, s = region["w"], region["s"]
734  e, n = region["e"], region["n"]
735  if sel == 1:
736  self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f" %
737  (precision, w, precision, e,
738  precision, s, precision, n), 0)
739  else:
740  ewres, nsres = region['ewres'], region['nsres']
741  self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f (%.*f, %.*f)" %
742  (precision, w, precision, e,
743  precision, s, precision, n,
744  precision, ewres, precision, nsres), 0)
745  # enable long help
747 
748  elif self.statusbarWin['toggle'].GetSelection() == 3: # Show comp. extent
749  self.statusbar.SetStatusText("", 0)
750  self.statusbarWin['region'].Show()
751  # disable long help
752  self.StatusbarEnableLongHelp(False)
753 
754  elif self.statusbarWin['toggle'].GetSelection() == 4: # Display mode
755  self.statusbar.SetStatusText("", 0)
756  self.statusbarWin['resolution'].Show()
757  # disable long help
758  self.StatusbarEnableLongHelp(False)
759 
760  elif self.statusbarWin['toggle'].GetSelection() == 5: # Display geometry
761  self.statusbar.SetStatusText("rows=%d; cols=%d; nsres=%.2f; ewres=%.2f" %
762  (self.Map.region["rows"], self.Map.region["cols"],
763  self.Map.region["nsres"], self.Map.region["ewres"]), 0)
764  # enable long help
766 
767  elif self.statusbarWin['toggle'].GetSelection() == 6: # Map scale
768  # TODO: need to be fixed...
769  ### screen X region problem
770  ### user should specify ppm
771  dc = wx.ScreenDC()
772  dpSizePx = wx.DisplaySize() # display size in pixels
773  dpSizeMM = wx.DisplaySizeMM() # display size in mm (system)
774  dpSizeIn = (dpSizeMM[0] / 25.4, dpSizeMM[1] / 25.4) # inches
775  sysPpi = dc.GetPPI()
776  comPpi = (dpSizePx[0] / dpSizeIn[0],
777  dpSizePx[1] / dpSizeIn[1])
778 
779  ppi = comPpi # pixel per inch
780  self.ppm = ((ppi[0] / 2.54) * 100, # pixel per meter
781  (ppi[1] / 2.54) * 100)
782 
783  Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): size: px=%d,%d mm=%f,%f "
784  "in=%f,%f ppi: sys=%d,%d com=%d,%d; ppm=%f,%f" % \
785  (dpSizePx[0], dpSizePx[1], dpSizeMM[0], dpSizeMM[1],
786  dpSizeIn[0], dpSizeIn[1],
787  sysPpi[0], sysPpi[1], comPpi[0], comPpi[1],
788  self.ppm[0], self.ppm[1]))
789 
790  region = self.Map.region
791 
792  heightCm = region['rows'] / self.ppm[1] * 100
793  widthCm = region['cols'] / self.ppm[0] * 100
794 
795  Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): width_cm=%f, height_cm=%f" %
796  (widthCm, heightCm))
797 
798  xscale = (region['e'] - region['w']) / (region['cols'] / self.ppm[0])
799  yscale = (region['n'] - region['s']) / (region['rows'] / self.ppm[1])
800  scale = (xscale + yscale) / 2.
801 
802  Debug.msg(3, "MapFrame.StatusbarUpdate(mapscale): xscale=%f, yscale=%f -> scale=%f" % \
803  (xscale, yscale, scale))
804 
805  self.statusbar.SetStatusText("")
806  try:
807  self.statusbarWin['mapscale'].SetValue("1:%ld" % (scale + 0.5))
808  except TypeError:
809  pass
810  self.mapScaleValue = scale
811  self.statusbarWin['mapscale'].Show()
812 
813  # disable long help
814  self.StatusbarEnableLongHelp(False)
815 
816  elif self.statusbarWin['toggle'].GetSelection() == 7: # go to
817 
818  self.statusbar.SetStatusText("")
819  max = self.list.GetItemCount()
820  if max < 1:
821  max = 1
822  self.statusbarWin['goto'].SetRange(0, max)
823 
824  self.statusbarWin['goto'].Show()
825 
826  # disable long help
827  self.StatusbarEnableLongHelp(False)
828 
829  elif self.statusbarWin['toggle'].GetSelection() == 8: # RMS error
830  self.statusbar.SetStatusText(_("Forward: %(forw)s, Backward: %(back)s") %
831  { 'forw' : self.fwd_rmserror,
832  'back' : self.bkw_rmserror })
833  # disable long help
834  # self.StatusbarEnableLongHelp(False)
835 
836  else:
837  self.statusbar.SetStatusText("", 1)
838 
839  def StatusbarEnableLongHelp(self, enable=True):
840  """!Enable/disable toolbars long help"""
841  for toolbar in self.toolbars.itervalues():
842  if toolbar:
843  toolbar.EnableLongHelp(enable)
844 
846  """!Reposition checkbox in statusbar"""
847  # reposition checkbox
848  widgets = [(0, self.statusbarWin['region']),
849  (0, self.statusbarWin['resolution']),
850  (0, self.statusbarWin['mapscale']),
851  (0, self.statusbarWin['progress']),
852  (0, self.statusbarWin['goto']),
853  (1, self.statusbarWin['toggle']),
854  (2, self.statusbarWin['mask']),
855  (3, self.statusbarWin['render'])]
856  for idx, win in widgets:
857  rect = self.statusbar.GetFieldRect(idx)
858  wWin, hWin = win.GetBestSize()
859  if idx == 0: # show region / mapscale / process bar
860  # -> size
861  if win == self.statusbarWin['progress']:
862  wWin = rect.width - 6
863  # -> position
864  # if win == self.statusbarWin['region']:
865  # x, y = rect.x + rect.width - wWin, rect.y - 1
866  # align left
867  # else:
868  x, y = rect.x + 3, rect.y - 1
869  w, h = wWin, rect.height + 2
870  else: # choice || auto-rendering
871  x, y = rect.x, rect.y - 1
872  w, h = rect.width, rect.height + 2
873  if idx == 1: # choice
874  h = hWin
875  elif idx == 2: # mask
876  x += 5
877  y += 4
878  elif idx == 3: # render
879  x += 5
880 
881  win.SetPosition((x, y))
882  win.SetSize((w, h))
883 
884  def SaveToFile(self, event):
885  """!Save map to image
886  """
887  img = self.MapWindow.img
888  if not img:
889  gcmd.GMessage(parent = self,
890  message = _("Nothing to render (empty map). Operation canceled."))
891  return
892  filetype, ltype = gdialogs.GetImageHandlers(img)
893 
894  # get size
895  dlg = gdialogs.ImageSizeDialog(self)
896  dlg.CentreOnParent()
897  if dlg.ShowModal() != wx.ID_OK:
898  dlg.Destroy()
899  return
900  width, height = dlg.GetValues()
901  dlg.Destroy()
902 
903  # get filename
904  dlg = wx.FileDialog(parent = self,
905  message = _("Choose a file name to save the image "
906  "(no need to add extension)"),
907  wildcard = filetype,
908  style=wx.SAVE | wx.FD_OVERWRITE_PROMPT)
909 
910  if dlg.ShowModal() == wx.ID_OK:
911  path = dlg.GetPath()
912  if not path:
913  dlg.Destroy()
914  return
915 
916  base, ext = os.path.splitext(path)
917  fileType = ltype[dlg.GetFilterIndex()]['type']
918  extType = ltype[dlg.GetFilterIndex()]['ext']
919  if ext != extType:
920  path = base + '.' + extType
921 
922  self.MapWindow.SaveToFile(path, fileType,
923  width, height)
924 
925  dlg.Destroy()
926 
927  def PrintMenu(self, event):
928  """
929  Print options and output menu for map display
930  """
931  point = wx.GetMousePosition()
932  printmenu = wx.Menu()
933  # Add items to the menu
934  setup = wx.MenuItem(printmenu, wx.ID_ANY, _('Page setup'))
935  printmenu.AppendItem(setup)
936  self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup)
937 
938  preview = wx.MenuItem(printmenu, wx.ID_ANY, _('Print preview'))
939  printmenu.AppendItem(preview)
940  self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview)
941 
942  doprint = wx.MenuItem(printmenu, wx.ID_ANY, _('Print display'))
943  printmenu.AppendItem(doprint)
944  self.Bind(wx.EVT_MENU, self.printopt.OnDoPrint, doprint)
945 
946  # Popup the menu. If an item is selected then its handler
947  # will be called before PopupMenu returns.
948  self.PopupMenu(printmenu)
949  printmenu.Destroy()
950 
951  def GetRender(self):
952  """!Returns current instance of render.Map()
953  """
954  return self.Map
955 
956  def GetWindow(self):
957  """!Get map window"""
958  return self.MapWindow
959 
960  def FormatDist(self, dist):
961  """!Format length numbers and units in a nice way,
962  as a function of length. From code by Hamish Bowman
963  Grass Development Team 2006"""
964 
965  mapunits = self.Map.projinfo['units']
966  if mapunits == 'metres': mapunits = 'meters'
967  outunits = mapunits
968  dist = float(dist)
969  divisor = 1.0
970 
971  # figure out which units to use
972  if mapunits == 'meters':
973  if dist > 2500.0:
974  outunits = 'km'
975  divisor = 1000.0
976  else: outunits = 'm'
977  elif mapunits == 'feet':
978  # nano-bug: we match any "feet", but US Survey feet is really
979  # 5279.9894 per statute mile, or 10.6' per 1000 miles. As >1000
980  # miles the tick markers are rounded to the nearest 10th of a
981  # mile (528'), the difference in foot flavours is ignored.
982  if dist > 5280.0:
983  outunits = 'miles'
984  divisor = 5280.0
985  else:
986  outunits = 'ft'
987  elif 'degree' in mapunits:
988  if dist < 1:
989  outunits = 'min'
990  divisor = (1/60.0)
991  else:
992  outunits = 'deg'
993 
994  # format numbers in a nice way
995  if (dist/divisor) >= 2500.0:
996  outdist = round(dist/divisor)
997  elif (dist/divisor) >= 1000.0:
998  outdist = round(dist/divisor,1)
999  elif (dist/divisor) > 0.0:
1000  outdist = round(dist/divisor,int(math.ceil(3-math.log10(dist/divisor))))
1001  else:
1002  outdist = float(dist/divisor)
1003 
1004  return (outdist, outunits)
1005 
1006  def OnZoomToMap(self, event):
1007  """!
1008  Set display extents to match selected raster (including NULLs)
1009  or vector map.
1010  """
1011  self.MapWindow.ZoomToMap(layers = self.Map.GetListOfLayers())
1012 
1013  def OnZoomToRaster(self, event):
1014  """!
1015  Set display extents to match selected raster map (ignore NULLs)
1016  """
1017  self.MapWindow.ZoomToMap(ignoreNulls = True)
1018 
1019  def OnZoomToWind(self, event):
1020  """!Set display geometry to match computational region
1021  settings (set with g.region)
1022  """
1023  self.MapWindow.ZoomToWind()
1024 
1025  def OnZoomToDefault(self, event):
1026  """!Set display geometry to match default region settings
1027  """
1028  self.MapWindow.ZoomToDefault()
1029 
1030  def OnZoomToSaved(self, event):
1031  """!Set display geometry to match extents in
1032  saved region file
1033  """
1034  self.MapWindow.ZoomToSaved()
1035 
1036  def OnDisplayToWind(self, event):
1037  """!Set computational region (WIND file) to match display
1038  extents
1039  """
1040  self.MapWindow.DisplayToWind()
1041 
1042  def SaveDisplayRegion(self, event):
1043  """!Save display extents to named region file.
1044  """
1045  self.MapWindow.SaveDisplayRegion()
1046 
1047  def OnZoomMenu(self, event):
1048  """!Popup Zoom menu
1049  """
1050  point = wx.GetMousePosition()
1051  zoommenu = wx.Menu()
1052  # Add items to the menu
1053 
1054  zoomwind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to computational region (set with g.region)'))
1055  zoommenu.AppendItem(zoomwind)
1056  self.Bind(wx.EVT_MENU, self.OnZoomToWind, zoomwind)
1057 
1058  zoomdefault = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to default region'))
1059  zoommenu.AppendItem(zoomdefault)
1060  self.Bind(wx.EVT_MENU, self.OnZoomToDefault, zoomdefault)
1061 
1062  zoomsaved = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to saved region'))
1063  zoommenu.AppendItem(zoomsaved)
1064  self.Bind(wx.EVT_MENU, self.OnZoomToSaved, zoomsaved)
1065 
1066  savewind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Set computational region from display'))
1067  zoommenu.AppendItem(savewind)
1068  self.Bind(wx.EVT_MENU, self.OnDisplayToWind, savewind)
1069 
1070  savezoom = wx.MenuItem(zoommenu, wx.ID_ANY, _('Save display geometry to named region'))
1071  zoommenu.AppendItem(savezoom)
1072  self.Bind(wx.EVT_MENU, self.SaveDisplayRegion, savezoom)
1073 
1074  # Popup the menu. If an item is selected then its handler
1075  # will be called before PopupMenu returns.
1076  self.PopupMenu(zoommenu)
1077  zoommenu.Destroy()
1078 
1079  def SetProperties(self, render=False, mode=0, showCompExtent=False,
1080  constrainRes=False, projection=False):
1081  """!Set properies of map display window"""
1082  self.statusbarWin['render'].SetValue(render)
1083  self.statusbarWin['toggle'].SetSelection(mode)
1084  self.StatusbarUpdate()
1085  self.statusbarWin['region'].SetValue(showCompExtent)
1086  self.statusbarWin['resolution'].SetValue(constrainRes)
1087  if showCompExtent:
1088  self.MapWindow.regionCoords = []
1089 
1090  def IsStandalone(self):
1091  """!Check if Map display is standalone"""
1092  if self._layerManager:
1093  return False
1094 
1095  return True
1096 
1097  def GetLayerManager(self):
1098  """!Get reference to Layer Manager
1099 
1100  @return window reference
1101  @return None (if standalone)
1102  """
1103  return self._layerManager
1104 
1105 # end of class MapFrame