GRASS Programmer's Manual  6.4.2(2012)
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
mapdisp.py
Go to the documentation of this file.
1 """!
2 @package mapdisp.py
3 
4 @brief GIS map display canvas, with toolbar for various display
5 management functions, and additional toolbars (vector digitizer, 3d
6 view).
7 
8 Can be used either from Layer Manager or as p.mon backend.
9 
10 Classes:
11 - MapFrame
12 - MapApp
13 
14 Usage:
15 python mapdisp.py monitor-identifier /path/to/command/file
16 
17 (C) 2006-2011 by the GRASS Development Team
18 This program is free software under the GNU General Public
19 License (>=v2). Read the file COPYING that comes with GRASS
20 for details.
21 
22 @author Michael Barton
23 @author Jachym Cepicky
24 @author Martin Landa <landa.martin gmail.com>
25 """
26 
27 import os
28 import sys
29 import glob
30 import math
31 import tempfile
32 import copy
33 
34 import globalvar
35 import wx
36 import wx.aui
37 
38 try:
39  import subprocess
40 except:
41  CompatPath = os.path.join(globalvar.ETCWXDIR)
42  sys.path.append(CompatPath)
43  from compat import subprocess
44 
45 gmpath = os.path.join(globalvar.ETCWXDIR, "icons")
46 sys.path.append(gmpath)
47 
48 grassPath = os.path.join(globalvar.ETCDIR, "python")
49 sys.path.append(grassPath)
50 
51 import render
52 import toolbars
53 import menuform
54 import gselect
55 import disp_print
56 import gcmd
57 import dbm
58 import dbm_dialogs
59 import histogram
60 import profile
61 import globalvar
62 import utils
63 import gdialogs
64 from grass.script import core as grass
65 from debug import Debug
66 from icon import Icons
67 from preferences import globalSettings as UserSettings
68 
69 from mapdisp_command import Command
70 from mapdisp_window import BufferedWindow
71 
72 # for standalone app
73 cmdfilename = None
74 
75 haveCtypes = False
76 
77 class MapFrame(wx.Frame):
78  """!Main frame for map display window. Drawing takes place in
79  child double buffered drawing window.
80  """
81  def __init__(self, parent = None, id = wx.ID_ANY, title = _("GRASS GIS - Map display"),
82  style = wx.DEFAULT_FRAME_STYLE, toolbars = ["map"],
83  tree = None, notebook = None, lmgr = None, page = None,
84  Map = None, auimgr = None, **kwargs):
85  """!Main map display window with toolbars, statusbar and
86  DrawWindow
87 
88  @param toolbars array of activated toolbars, e.g. ['map', 'digit']
89  @param tree reference to layer tree
90  @param notebook control book ID in Layer Manager
91  @param lmgr Layer Manager
92  @param page notebook page with layer tree
93  @param Map instance of render.Map
94  @param auimgs AUI manager
95  @param kwargs wx.Frame attribures
96  """
97  self._layerManager = lmgr # Layer Manager object
98  self.Map = Map # instance of render.Map
99  self.tree = tree # Layer Manager layer tree object
100  self.page = page # Notebook page holding the layer tree
101  self.layerbook = notebook # Layer Manager layer tree notebook
102  self.parent = parent
103 
104  if 'name' not in kwargs:
105  kwargs['name'] = 'MapWindow'
106  wx.Frame.__init__(self, parent, id, title, style = style, **kwargs)
107 
108  # available cursors
109  self.cursors = {
110  # default: cross
111  # "default" : wx.StockCursor(wx.CURSOR_DEFAULT),
112  "default" : wx.StockCursor(wx.CURSOR_ARROW),
113  "cross" : wx.StockCursor(wx.CURSOR_CROSS),
114  "hand" : wx.StockCursor(wx.CURSOR_HAND),
115  "pencil" : wx.StockCursor(wx.CURSOR_PENCIL),
116  "sizenwse": wx.StockCursor(wx.CURSOR_SIZENWSE)
117  }
118 
119  #
120  # set the size & system icon
121  #
122  self.SetClientSize(self.GetSize())
123  self.iconsize = (16, 16)
124 
125  self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_map.ico'), wx.BITMAP_TYPE_ICO))
126 
127  #
128  # Fancy gui
129  #
130  self._mgr = wx.aui.AuiManager(self)
131 
132  #
133  # Add toolbars
134  #
135  self.toolbars = { 'map' : None,
136  'vdigit' : None,
137  'georect' : None,
138  'gcpdisp' : None,
139  'nviz' : None }
140  for toolb in toolbars:
141  self.AddToolbar(toolb)
142 
143  #
144  # Add statusbar
145  #
146  self.statusbar = self.CreateStatusBar(number = 4, style = 0)
147  self.statusbar.SetStatusWidths([-5, -2, -1, -1])
148  self.statusbarWin = dict()
149  self.statusbarWin['toggle'] = wx.Choice(self.statusbar, wx.ID_ANY,
150  choices = globalvar.MAP_DISPLAY_STATUSBAR_MODE)
151  self.statusbarWin['toggle'].SetSelection(UserSettings.Get(group = 'display',
152  key = 'statusbarMode',
153  subkey = 'selection'))
154  self.statusbar.Bind(wx.EVT_CHOICE, self.OnToggleStatus, self.statusbarWin['toggle'])
155  # auto-rendering checkbox
156  self.statusbarWin['render'] = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
157  label = _("Render"))
158  self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleRender, self.statusbarWin['render'])
159  self.statusbarWin['render'].SetValue(UserSettings.Get(group = 'display',
160  key = 'autoRendering',
161  subkey = 'enabled'))
162  self.statusbarWin['render'].SetToolTip(wx.ToolTip (_("Enable/disable auto-rendering")))
163  # show region
164  self.statusbarWin['region'] = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
165  label = _("Show computational extent"))
166  self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleShowRegion, self.statusbarWin['region'])
167 
168  self.statusbarWin['region'].SetValue(False)
169  self.statusbarWin['region'].Hide()
170  self.statusbarWin['region'].SetToolTip(wx.ToolTip (_("Show/hide computational "
171  "region extent (set with g.region). "
172  "Display region drawn as a blue box inside the "
173  "computational region, "
174  "computational region inside a display region "
175  "as a red box).")))
176  # set resolution
177  self.statusbarWin['resolution'] = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
178  label = _("Constrain display resolution to computational settings"))
179  self.statusbar.Bind(wx.EVT_CHECKBOX, self.OnToggleResolution, self.statusbarWin['resolution'])
180  self.statusbarWin['resolution'].SetValue(UserSettings.Get(group = 'display', key = 'compResolution', subkey = 'enabled'))
181  self.statusbarWin['resolution'].Hide()
182  self.statusbarWin['resolution'].SetToolTip(wx.ToolTip (_("Constrain display resolution "
183  "to computational region settings. "
184  "Default value for new map displays can "
185  "be set up in 'User GUI settings' dialog.")))
186  # map scale
187  self.statusbarWin['mapscale'] = wx.ComboBox(parent = self.statusbar, id = wx.ID_ANY,
188  style = wx.TE_PROCESS_ENTER,
189  size = (150, -1))
190  self.statusbarWin['mapscale'].SetItems(['1:1000',
191  '1:5000',
192  '1:10000',
193  '1:25000',
194  '1:50000',
195  '1:100000',
196  '1:1000000'])
197  self.statusbarWin['mapscale'].Hide()
198  self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnChangeMapScale, self.statusbarWin['mapscale'])
199  self.statusbar.Bind(wx.EVT_COMBOBOX, self.OnChangeMapScale, self.statusbarWin['mapscale'])
200 
201  # go to
202  self.statusbarWin['goto'] = wx.TextCtrl(parent = self.statusbar, id = wx.ID_ANY,
203  value = "", style = wx.TE_PROCESS_ENTER,
204  size = (300, -1))
205  self.statusbarWin['goto'].Hide()
206  self.statusbar.Bind(wx.EVT_TEXT_ENTER, self.OnGoTo, self.statusbarWin['goto'])
207 
208  # projection
209  self.statusbarWin['projection'] = wx.CheckBox(parent = self.statusbar, id = wx.ID_ANY,
210  label = _("Use defined projection"))
211  self.statusbarWin['projection'].SetValue(False)
212  size = self.statusbarWin['projection'].GetSize()
213  self.statusbarWin['projection'].SetMinSize((size[0] + 150, size[1]))
214  self.statusbarWin['projection'].SetToolTip(wx.ToolTip (_("Reproject coordinates displayed "
215  "in the statusbar. Projection can be "
216  "defined in GUI preferences dialog "
217  "(tab 'Display')")))
218  self.statusbarWin['projection'].Hide()
219 
220  # mask
221  self.statusbarWin['mask'] = wx.StaticText(parent = self.statusbar, id = wx.ID_ANY,
222  label = '')
223  self.statusbarWin['mask'].SetForegroundColour(wx.Colour(255, 0, 0))
224 
225  # on-render gauge
226  self.statusbarWin['progress'] = wx.Gauge(parent = self.statusbar, id = wx.ID_ANY,
227  range = 0, style = wx.GA_HORIZONTAL)
228  self.statusbarWin['progress'].Hide()
229 
230  self.StatusbarReposition() # reposition statusbar
231 
232  #
233  # Init map display (buffered DC & set default cursor)
234  #
235  self.MapWindow2D = BufferedWindow(self, id = wx.ID_ANY,
236  Map = self.Map, tree = self.tree, lmgr = self._layerManager)
237  # default is 2D display mode
238  self.MapWindow = self.MapWindow2D
239  self.MapWindow.SetCursor(self.cursors["default"])
240  # used by vector digitizer
241  self.MapWindowVDigit = None
242  # used by Nviz (3D display mode)
243  self.MapWindow3D = None
244 
245  #
246  # initialize region values
247  #
248  self._initDisplay()
249 
250  #
251  # Bind various events
252  #
253  self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
254  self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
255  self.Bind(render.EVT_UPDATE_PRGBAR, self.OnUpdateProgress)
256 
257  #
258  # Update fancy gui style
259  #
260  self._mgr.AddPane(self.MapWindow, wx.aui.AuiPaneInfo().CentrePane().
261  Dockable(False).BestSize((-1,-1)).
262  CloseButton(False).DestroyOnClose(True).
263  Layer(0))
264  self._mgr.Update()
265 
266  #
267  # Init print module and classes
268  #
270 
271  #
272  # Init zoom history
273  #
274  self.MapWindow.ZoomHistory(self.Map.region['n'],
275  self.Map.region['s'],
276  self.Map.region['e'],
277  self.Map.region['w'])
278 
279  #
280  # Re-use dialogs
281  #
282  self.dialogs = {}
283  self.dialogs['attributes'] = None
284  self.dialogs['category'] = None
285  self.dialogs['barscale'] = None
286  self.dialogs['legend'] = None
287 
288  self.decorationDialog = None # decoration/overlays
289 
290  def _addToolbarVDigit(self):
291  """!Add vector digitizer toolbar
292  """
293  from vdigit import haveVDigit
294 
295  if not haveVDigit:
296  from vdigit import errorMsg
297  msg = _("Unable to start wxGUI vector digitizer.\nDo you want to start "
298  "TCL/TK digitizer (v.digit) instead?\n\n"
299  "Details: %s" % errorMsg)
300 
301  self.toolbars['map'].combo.SetValue(_("2D view"))
302  dlg = wx.MessageDialog(parent = self,
303  message = msg,
304  caption=_("Vector digitizer failed"),
305  style = wx.YES_NO | wx.CENTRE)
306  if dlg.ShowModal() == wx.ID_YES:
307  mapName = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetName()
308  self._layerManager.goutput.RunCmd(['v.digit', 'map=%s' % mapName],
309  switchPage = False)
310  dlg.Destroy()
311 
312  self.toolbars['map'].combo.SetValue(_("2D view"))
313  return
314 
315  if self._layerManager:
316  log = self._layerManager.goutput
317  else:
318  log = None
319 
320  if not self.MapWindowVDigit:
321  from mapdisp_vdigit import VDigitWindow
322  self.MapWindowVDigit = VDigitWindow(self, id = wx.ID_ANY,
323  Map = self.Map, tree = self.tree,
324  lmgr = self._layerManager)
325  self.MapWindowVDigit.Show()
326 
327  self.MapWindow = self.MapWindowVDigit
328 
329  self._mgr.DetachPane(self.MapWindow2D)
330  self.MapWindow2D.Hide()
331 
332  self.toolbars['vdigit'] = toolbars.VDigitToolbar(parent = self, mapcontent = self.Map,
333  layerTree = self.tree,
334  log = log)
335  self.MapWindowVDigit.SetToolbar(self.toolbars['vdigit'])
336 
337  self._mgr.AddPane(self.MapWindowVDigit, wx.aui.AuiPaneInfo().CentrePane().
338  Dockable(False).BestSize((-1,-1)).
339  CloseButton(False).DestroyOnClose(True).
340  Layer(0))
341  self._mgr.AddPane(self.toolbars['vdigit'],
342  wx.aui.AuiPaneInfo().
343  Name("vdigittoolbar").Caption(_("Vector Digitizer Toolbar")).
344  ToolbarPane().Top().Row(1).
345  LeftDockable(False).RightDockable(False).
346  BottomDockable(False).TopDockable(True).
347  CloseButton(False).Layer(2).
348  BestSize((self.toolbars['vdigit'].GetBestSize())))
349  # change mouse to draw digitized line
350  self.MapWindow.mouse['box'] = "point"
351  self.MapWindow.zoomtype = 0
352  self.MapWindow.pen = wx.Pen(colour = 'red', width = 2, style = wx.SOLID)
353  self.MapWindow.polypen = wx.Pen(colour = 'green', width = 2, style = wx.SOLID)
354 
355  def _addToolbarNviz(self):
356  """!Add 3D view mode toolbar
357  """
358  import nviz
359 
360  # check for GLCanvas and OpenGL
361  if not nviz.haveNviz:
362  self.toolbars['map'].combo.SetValue (_("2D view"))
363  gcmd.GError(parent = self,
364  message = _("Unable to switch to 3D display mode.\nThe Nviz python extension "
365  "was not found or loaded properly.\n"
366  "Switching back to 2D display mode.\n\nDetails: %s" % nviz.errorMsg))
367  return
368 
369  # add Nviz toolbar and disable 2D display mode tools
370  self.toolbars['nviz'] = toolbars.NvizToolbar(self, self.Map)
371  self.toolbars['map'].Enable2D(False)
372 
373  # update status bar
374  self.statusbarWin['toggle'].Enable(False)
375 
376  # erase map window
377  self.MapWindow.EraseMap()
378 
379  self._layerManager.goutput.WriteCmdLog(_("Starting 3D view mode..."))
380  self.statusbar.SetStatusText(_("Please wait, loading data..."), 0)
381 
382  # create GL window & NVIZ toolbar
383  if not self.MapWindow3D:
384  self.MapWindow3D = nviz.GLWindow(self, id = wx.ID_ANY,
385  Map = self.Map, tree = self.tree, lmgr = self._layerManager)
386  self.MapWindow = self.MapWindow3D
387  self.MapWindow.SetCursor(self.cursors["default"])
388 
389  # add Nviz notebookpage
390  self._layerManager.AddNviz()
391 
392  self.MapWindow3D.OnPaint(None) # -> LoadData
393  self.MapWindow3D.Show()
394  self.MapWindow3D.UpdateView(None)
395  else:
396  self.MapWindow = self.MapWindow3D
397  # add Nviz notebookpage
398  self._layerManager.AddNviz()
399  self._layerManager.nviz.UpdatePage('view')
400  self._layerManager.nviz.UpdatePage('light')
401 
402  # switch from MapWindow to MapWindowGL
403  # add nviz toolbar
404  self._mgr.DetachPane(self.MapWindow2D)
405  self.MapWindow2D.Hide()
406  self._mgr.AddPane(self.MapWindow3D, wx.aui.AuiPaneInfo().CentrePane().
407  Dockable(False).BestSize((-1,-1)).
408  CloseButton(False).DestroyOnClose(True).
409  Layer(0))
410  self._mgr.AddPane(self.toolbars['nviz'],
411  wx.aui.AuiPaneInfo().
412  Name("nviztoolbar").Caption(_("3D View Toolbar")).
413  ToolbarPane().Top().Row(1).
414  LeftDockable(False).RightDockable(False).
415  BottomDockable(False).TopDockable(True).
416  CloseButton(False).Layer(2).
417  BestSize((self.toolbars['nviz'].GetBestSize())))
418 
419  self.SetStatusText("", 0)
420 
421  def AddToolbar(self, name):
422  """!Add defined toolbar to the window
423 
424  Currently known toolbars are:
425  - 'map' - basic map toolbar
426  - 'vdigit' - vector digitizer
427  - 'gcpdisp' - GCP Manager Display
428  - 'georect' - georectifier
429  - 'nviz' - 3D view mode
430  """
431  # default toolbar
432  if name == "map":
433  self.toolbars['map'] = toolbars.MapToolbar(self, self.Map)
434 
435  self._mgr.AddPane(self.toolbars['map'],
436  wx.aui.AuiPaneInfo().
437  Name("maptoolbar").Caption(_("Map Toolbar")).
438  ToolbarPane().Top().
439  LeftDockable(False).RightDockable(False).
440  BottomDockable(False).TopDockable(True).
441  CloseButton(False).Layer(2).
442  BestSize((self.toolbars['map'].GetBestSize())))
443 
444  # vector digitizer
445  elif name == "vdigit":
446  self._addToolbarVDigit()
447  # georectifier
448  elif name == "georect":
449  self.toolbars['georect'] = toolbars.GRToolbar(self, self.Map)
450 
451  self._mgr.AddPane(self.toolbars['georect'],
452  wx.aui.AuiPaneInfo().
453  Name("georecttoolbar").Caption(_("Georectification Toolbar")).
454  ToolbarPane().Top().
455  LeftDockable(False).RightDockable(False).
456  BottomDockable(False).TopDockable(True).
457  CloseButton(False).Layer(2).
458  BestSize((self.toolbars['georect'].GetBestSize())))
459  # nviz
460  elif name == "nviz":
461  self._addToolbarNviz()
462 
463  self._mgr.Update()
464 
465  def RemoveToolbar (self, name):
466  """!Removes defined toolbar from the window
467 
468  @todo Only hide, activate by calling AddToolbar()
469  """
470  # cannot hide main toolbar
471  if name == "map":
472  return
473 
474  self._mgr.DetachPane(self.toolbars[name])
475  self.toolbars[name].Destroy()
476  self.toolbars[name] = None
477 
478  if name == 'vdigit':
479  self._mgr.DetachPane(self.MapWindowVDigit)
480  self.MapWindowVDigit.Hide()
481  self.MapWindow2D.Show()
482  self._mgr.AddPane(self.MapWindow2D, wx.aui.AuiPaneInfo().CentrePane().
483  Dockable(False).BestSize((-1,-1)).
484  CloseButton(False).DestroyOnClose(True).
485  Layer(0))
486  self.MapWindow = self.MapWindow2D
487 
488  elif name == 'nviz':
489  # unload data
490  # self.MapWindow3D.Reset()
491  # switch from MapWindowGL to MapWindow
492  self._mgr.DetachPane(self.MapWindow3D)
493  self.MapWindow3D.Hide()
494  self.MapWindow2D.Show()
495  self._mgr.AddPane(self.MapWindow2D, wx.aui.AuiPaneInfo().CentrePane().
496  Dockable(False).BestSize((-1,-1)).
497  CloseButton(False).DestroyOnClose(True).
498  Layer(0))
499  self.MapWindow = self.MapWindow2D
500  # remove nviz notebook page
501  self._layerManager.RemoveNviz()
502 
503  self.MapWindow.UpdateMap()
504 
505  self.toolbars['map'].combo.SetValue(_("2D view"))
506  self.toolbars['map'].Enable2D(True)
507  self.statusbarWin['toggle'].Enable(True)
508 
509  self._mgr.Update()
510 
511  def _initDisplay(self):
512  """!Initialize map display, set dimensions and map region
513  """
514  if not grass.find_program('g.region', ['--help']):
515  sys.exit(_("GRASS module '%s' not found. Unable to start map "
516  "display window.") % 'g.region')
517 
518  self.width, self.height = self.GetClientSize()
519 
520  Debug.msg(2, "MapFrame._initDisplay():")
521  self.Map.ChangeMapSize(self.GetClientSize())
522  self.Map.region = self.Map.GetRegion() # g.region -upgc
523  # self.Map.SetRegion() # adjust region to match display window
524 
525  def OnUpdateProgress(self, event):
526  """!Update progress bar info
527  """
528  self.statusbarWin['progress'].SetValue(event.value)
529 
530  event.Skip()
531 
532  def OnFocus(self, event):
533  """
534  Change choicebook page to match display.
535  Or set display for georectifying
536  """
537  if self._layerManager and \
538  self._layerManager.georectifying:
539  # in georectifying session; display used to get geographic
540  # coordinates for GCPs
541  self.OnPointer(event)
542  else:
543  # change bookcontrol page to page associated with display
544  if self.page:
545  pgnum = self.layerbook.GetPageIndex(self.page)
546  if pgnum > -1:
547  self.layerbook.SetSelection(pgnum)
548 
549  event.Skip()
550 
551  def OnDraw(self, event):
552  """!Re-display current map composition
553  """
554  self.MapWindow.UpdateMap(render = False)
555 
556  def OnRender(self, event):
557  """!Re-render map composition (each map layer)
558  """
559  # delete tmp map layers (queries)
560  qlayer = self.Map.GetListOfLayers(l_name = globalvar.QUERYLAYER)
561  for layer in qlayer:
562  self.Map.DeleteLayer(layer)
563 
564  # delete tmp lines
565  if self.MapWindow.mouse["use"] in ("measure",
566  "profile"):
567  self.MapWindow.polycoords = []
568  self.MapWindow.ClearLines()
569 
570  # deselect features in vdigit
571  if self.toolbars['vdigit']:
572  if self.MapWindow.digit:
573  self.MapWindow.digit.GetDisplay().SetSelected([])
574  self.MapWindow.UpdateMap(render = True, renderVector = True)
575  else:
576  self.MapWindow.UpdateMap(render = True)
577 
578  # update statusbar
579  self.StatusbarUpdate()
580 
581  def OnPointer(self, event):
582  """!Pointer button clicked
583  """
584  if self.toolbars['map']:
585  if event:
586  self.toolbars['map'].OnTool(event)
587  self.toolbars['map'].action['desc'] = ''
588 
589  self.MapWindow.mouse['use'] = "pointer"
590  self.MapWindow.mouse['box'] = "point"
591 
592  # change the cursor
593  if self.toolbars['vdigit']:
594  # digitization tool activated
595  self.MapWindow.SetCursor(self.cursors["cross"])
596 
597  # reset mouse['box'] if needed
598  if self.toolbars['vdigit'].GetAction() in ['addLine']:
599  if self.toolbars['vdigit'].GetAction('type') in ['point', 'centroid']:
600  self.MapWindow.mouse['box'] = 'point'
601  else: # line, boundary
602  self.MapWindow.mouse['box'] = 'line'
603  elif self.toolbars['vdigit'].GetAction() in ['addVertex', 'removeVertex', 'splitLine',
604  'editLine', 'displayCats', 'queryMap',
605  'copyCats']:
606  self.MapWindow.mouse['box'] = 'point'
607  else: # moveLine, deleteLine
608  self.MapWindow.mouse['box'] = 'box'
609 
610  elif self._layerManager and self._layerManager.georectifying:
611  self.MapWindow.SetCursor(self.cursors["cross"])
612 
613  else:
614  self.MapWindow.SetCursor(self.cursors["default"])
615 
616  def OnZoomIn(self, event):
617  """
618  Zoom in the map.
619  Set mouse cursor, zoombox attributes, and zoom direction
620  """
621  if self.toolbars['map']:
622  self.toolbars['map'].OnTool(event)
623  self.toolbars['map'].action['desc'] = ''
624 
625  self.MapWindow.mouse['use'] = "zoom"
626  self.MapWindow.mouse['box'] = "box"
627  self.MapWindow.zoomtype = 1
628  self.MapWindow.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH)
629 
630  # change the cursor
631  self.MapWindow.SetCursor(self.cursors["cross"])
632 
633  def OnZoomOut(self, event):
634  """
635  Zoom out the map.
636  Set mouse cursor, zoombox attributes, and zoom direction
637  """
638  if self.toolbars['map']:
639  self.toolbars['map'].OnTool(event)
640  self.toolbars['map'].action['desc'] = ''
641 
642  self.MapWindow.mouse['use'] = "zoom"
643  self.MapWindow.mouse['box'] = "box"
644  self.MapWindow.zoomtype = -1
645  self.MapWindow.pen = wx.Pen(colour = 'Red', width = 2, style = wx.SHORT_DASH)
646 
647  # change the cursor
648  self.MapWindow.SetCursor(self.cursors["cross"])
649 
650  def OnZoomBack(self, event):
651  """
652  Zoom last (previously stored position)
653  """
654  self.MapWindow.ZoomBack()
655 
656  def OnPan(self, event):
657  """
658  Panning, set mouse to drag
659  """
660  if self.toolbars['map']:
661  self.toolbars['map'].OnTool(event)
662  self.toolbars['map'].action['desc'] = ''
663 
664  self.MapWindow.mouse['use'] = "pan"
665  self.MapWindow.mouse['box'] = "pan"
666  self.MapWindow.zoomtype = 0
667 
668  # change the cursor
669  self.MapWindow.SetCursor(self.cursors["hand"])
670 
671  def OnErase(self, event):
672  """
673  Erase the canvas
674  """
675  self.MapWindow.EraseMap()
676 
677  def OnZoomRegion(self, event):
678  """
679  Zoom to region
680  """
681  self.Map.getRegion()
682  self.Map.getResolution()
683  self.UpdateMap()
684  # event.Skip()
685 
686  def OnAlignRegion(self, event):
687  """
688  Align region
689  """
690  if not self.Map.alignRegion:
691  self.Map.alignRegion = True
692  else:
693  self.Map.alignRegion = False
694  # event.Skip()
695 
696  def OnToggleRender(self, event):
697  """!Enable/disable auto-rendering
698  """
699  if self.statusbarWin['render'].GetValue():
700  self.OnRender(None)
701 
702  def IsAutoRendered(self):
703  """!Check if auto-rendering is enabled"""
704  return self.statusbarWin['render'].IsChecked()
705 
706  def OnToggleShowRegion(self, event):
707  """!Show/Hide extent in map canvas
708  """
709  if self.statusbarWin['region'].GetValue():
710  # show extent
711  self.MapWindow.regionCoords = []
712  else:
713  del self.MapWindow.regionCoords
714 
715  # redraw map if auto-rendering is enabled
716  if self.statusbarWin['render'].GetValue():
717  self.OnRender(None)
718 
719  def OnToggleResolution(self, event):
720  """
721  Use resolution of computation region settings
722  for redering image instead of display resolution
723  """
724  # redraw map if auto-rendering is enabled
725  if self.statusbarWin['render'].GetValue():
726  self.OnRender(None)
727 
728  def OnToggleStatus(self, event):
729  """
730  Toggle status text
731  """
732  self.StatusbarUpdate()
733 
734  def OnChangeMapScale(self, event):
735  """
736  Map scale changed by user
737  """
738  scale = event.GetString()
739 
740  try:
741  if scale[:2] != '1:':
742  raise ValueError
743  value = int(scale[2:])
744  except ValueError:
745  self.statusbarWin['mapscale'].SetValue('1:%ld' % int(self.mapScaleValue))
746  return
747 
748  dEW = value * (self.Map.region['cols'] / self.ppm[0])
749  dNS = value * (self.Map.region['rows'] / self.ppm[1])
750  self.Map.region['n'] = self.Map.region['center_northing'] + dNS / 2.
751  self.Map.region['s'] = self.Map.region['center_northing'] - dNS / 2.
752  self.Map.region['w'] = self.Map.region['center_easting'] - dEW / 2.
753  self.Map.region['e'] = self.Map.region['center_easting'] + dEW / 2.
754 
755  # add to zoom history
756  self.MapWindow.ZoomHistory(self.Map.region['n'], self.Map.region['s'],
757  self.Map.region['e'], self.Map.region['w'])
758 
759  # redraw a map
760  self.MapWindow.UpdateMap()
761  self.statusbarWin['mapscale'].SetFocus()
762 
763  def OnGoTo(self, event):
764  """
765  Go to position
766  """
767  try:
768  if self.statusbarWin['projection'].IsChecked():
769  if not UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4'):
770  self.statusbar.SetStatusText(_("Projection not defined (check the settings)"), 0)
771  else:
772  # reproject values
773  projIn = UserSettings.Get(group = 'projection',
774  key = 'statusbar',
775  subkey = 'proj4')
776  projOut = gcmd.RunCommand('g.proj',
777  flags = 'jf',
778  read = True)
779  proj = projIn.split(' ')[0].split('=')[1]
780  if proj in ('ll', 'latlong', 'longlat'):
781  e, n = self.statusbarWin['goto'].GetValue().split(';')
782  e, n = utils.DMS2Deg(e, n)
783  proj, coord1 = utils.ReprojectCoordinates(coord = (e, n),
784  projIn = projIn,
785  projOut = projOut, flags = 'd')
786  e, n = coord1
787  else:
788  e, n = map(float, self.statusbarWin['goto'].GetValue().split(';'))
789  proj, coord1 = utils.ReprojectCoordinates(coord = (e, n),
790  projIn = projIn,
791  projOut = projOut, flags = 'd')
792  e, n = coord1
793  else:
794  if self.Map.projinfo['proj'] == 'll':
795  e, n = self.statusbarWin['goto'].GetValue().split(';')
796  else:
797  e, n = map(float, self.statusbarWin['goto'].GetValue().split(';'))
798 
799  region = self.Map.GetCurrentRegion()
800  if self.statusbarWin['projection'].IsChecked():
801  if not UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4'):
802  self.statusbar.SetStatusText(_("Projection not defined (check the settings)"), 0)
803  else:
804  region['center_easting'], region['center_northing'] = e, n
805  else:
806  if self.Map.projinfo['proj'] == 'll':
807  region['center_easting'], region['center_northing'] = utils.DMS2Deg(e, n)
808  else:
809  region['center_easting'], region['center_northing'] = e, n
810  except ValueError:
811  region = self.Map.GetCurrentRegion()
812  precision = int(UserSettings.Get(group = 'projection', key = 'format',
813  subkey = 'precision'))
814  format = UserSettings.Get(group = 'projection', key = 'format',
815  subkey = 'll')
816  if self.Map.projinfo['proj'] == 'll' and format == 'DMS':
817  self.statusbarWin['goto'].SetValue("%s" % utils.Deg2DMS(region['center_easting'],
818  region['center_northing'],
819  precision = precision))
820  else:
821  self.statusbarWin['goto'].SetValue("%.*f; %.*f" % \
822  (precision, region['center_easting'],
823  precision, region['center_northing']))
824  return
825 
826 
827  dn = (region['nsres'] * region['rows']) / 2.
828  region['n'] = region['center_northing'] + dn
829  region['s'] = region['center_northing'] - dn
830  de = (region['ewres'] * region['cols']) / 2.
831  region['e'] = region['center_easting'] + de
832  region['w'] = region['center_easting'] - de
833 
834  self.Map.AdjustRegion()
835 
836  # add to zoom history
837  self.MapWindow.ZoomHistory(region['n'], region['s'],
838  region['e'], region['w'])
839 
840  # redraw a map
841  self.MapWindow.UpdateMap()
842  self.statusbarWin['goto'].SetFocus()
843 
844  def StatusbarUpdate(self):
845  """!Update statusbar content"""
846 
847  self.statusbarWin['region'].Hide()
848  self.statusbarWin['resolution'].Hide()
849  self.statusbarWin['mapscale'].Hide()
850  self.statusbarWin['goto'].Hide()
851  self.statusbarWin['projection'].Hide()
852  self.mapScaleValue = self.ppm = None
853 
854  if self.statusbarWin['toggle'].GetSelection() == 0: # Coordinates
855  self.statusbar.SetStatusText("", 0)
856  # enable long help
858 
859  elif self.statusbarWin['toggle'].GetSelection() in (1, 2): # Extent
860  sel = self.statusbarWin['toggle'].GetSelection()
861  if sel == 1:
862  region = self.Map.region
863  else:
864  region = self.Map.GetRegion() # computation region
865 
866  precision = int(UserSettings.Get(group = 'projection', key = 'format',
867  subkey = 'precision'))
868  format = UserSettings.Get(group = 'projection', key = 'format',
869  subkey = 'll')
870 
871  if self.statusbarWin['projection'].IsChecked():
872  if not UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'proj4'):
873  self.statusbar.SetStatusText(_("Projection not defined (check the settings)"), 0)
874  else:
875  projOut = UserSettings.Get(group = 'projection',
876  key = 'statusbar',
877  subkey = 'proj4')
878  proj, coord1 = utils.ReprojectCoordinates(coord = (region["w"], region["s"]),
879  projOut = projOut, flags = 'd')
880  proj, coord2 = utils.ReprojectCoordinates(coord = (region["e"], region["n"]),
881  projOut = projOut, flags = 'd')
882  if sel == 2:
883  proj, coord3 = utils.ReprojectCoordinates(coord = (0.0, 0.0),
884  projOut = projOut, flags = 'd')
885  proj, coord4 = utils.ReprojectCoordinates(coord = (region["ewres"], region["nsres"]),
886  projOut = projOut, flags = 'd')
887  if coord1 and coord2:
888  if proj in ('ll', 'latlong', 'longlat') and format == 'DMS':
889  w, s = utils.Deg2DMS(coord1[0], coord1[1], string = False,
890  precision = precision)
891  e, n = utils.Deg2DMS(coord2[0], coord2[1], string = False,
892  precision = precision)
893  if sel == 1:
894  self.statusbar.SetStatusText("%s - %s, %s - %s" %
895  (w, e, s, n), 0)
896  else:
897  ewres, nsres = utils.Deg2DMS(abs(coord3[0]) - abs(coord4[0]),
898  abs(coord3[1]) - abs(coord4[1]),
899  string = False, hemisphere = False,
900  precision = precision)
901  self.statusbar.SetStatusText("%s - %s, %s - %s (%s, %s)" %
902  (w, e, s, n, ewres, nsres), 0)
903  else:
904  w, s = coord1
905  e, n = coord2
906  if sel == 1:
907  self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f" %
908  (precision, w, precision, e,
909  precision, s, precision, n), 0)
910  else:
911  ewres, nsres = coord3
912  self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f (%.*f, %.*f)" %
913  (precision, w, precision, e,
914  precision, s, precision, n,
915  precision, ewres, precision, nsres), 0)
916  else:
917  self.statusbar.SetStatusText(_("Error in projection (check the settings)"), 0)
918  else:
919  if self.Map.projinfo['proj'] == 'll' and format == 'DMS':
920  w, s = utils.Deg2DMS(region["w"], region["s"],
921  string = False, precision = precision)
922  e, n = utils.Deg2DMS(region["e"], region["n"],
923  string = False, precision = precision)
924  if sel == 1:
925  self.statusbar.SetStatusText("%s - %s, %s - %s" %
926  (w, e, s, n), 0)
927  else:
928  ewres, nsres = utils.Deg2DMS(region['ewres'], region['nsres'],
929  string = False, precision = precision)
930  self.statusbar.SetStatusText("%s - %s, %s - %s (%s, %s)" %
931  (w, e, s, n, ewres, nsres), 0)
932  else:
933  w, s = region["w"], region["s"]
934  e, n = region["e"], region["n"]
935  if sel == 1:
936  self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f" %
937  (precision, w, precision, e,
938  precision, s, precision, n), 0)
939  else:
940  ewres, nsres = region['ewres'], region['nsres']
941  self.statusbar.SetStatusText("%.*f - %.*f, %.*f - %.*f (%.*f, %.*f)" %
942  (precision, w, precision, e,
943  precision, s, precision, n,
944  precision, ewres, precision, nsres), 0)
945  # enable long help
947 
948  elif self.statusbarWin['toggle'].GetSelection() == 3: # Show comp. extent
949  self.statusbar.SetStatusText("", 0)
950  self.statusbarWin['region'].Show()
951  # disable long help
952  self.StatusbarEnableLongHelp(False)
953 
954  elif self.statusbarWin['toggle'].GetSelection() == 4: # Display mode
955  self.statusbar.SetStatusText("", 0)
956  self.statusbarWin['resolution'].Show()
957  # disable long help
958  self.StatusbarEnableLongHelp(False)
959 
960  elif self.statusbarWin['toggle'].GetSelection() == 5: # Display geometry
961  self.statusbar.SetStatusText("rows=%d; cols=%d; nsres=%.2f; ewres=%.2f" %
962  (self.Map.region["rows"], self.Map.region["cols"],
963  self.Map.region["nsres"], self.Map.region["ewres"]), 0)
964  # enable long help
966 
967  elif self.statusbarWin['toggle'].GetSelection() == 6: # Map scale
968  # TODO: need to be fixed...
969  ### screen X region problem
970  ### user should specify ppm
971  dc = wx.ScreenDC()
972  dpSizePx = wx.DisplaySize() # display size in pixels
973  dpSizeMM = wx.DisplaySizeMM() # display size in mm (system)
974  dpSizeIn = (dpSizeMM[0] / 25.4, dpSizeMM[1] / 25.4) # inches
975  sysPpi = dc.GetPPI()
976  comPpi = (dpSizePx[0] / dpSizeIn[0],
977  dpSizePx[1] / dpSizeIn[1])
978 
979  ppi = comPpi # pixel per inch
980  self.ppm = ((ppi[0] / 2.54) * 100, # pixel per meter
981  (ppi[1] / 2.54) * 100)
982 
983  Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): size: px=%d,%d mm=%f,%f "
984  "in=%f,%f ppi: sys=%d,%d com=%d,%d; ppm=%f,%f" % \
985  (dpSizePx[0], dpSizePx[1], dpSizeMM[0], dpSizeMM[1],
986  dpSizeIn[0], dpSizeIn[1],
987  sysPpi[0], sysPpi[1], comPpi[0], comPpi[1],
988  self.ppm[0], self.ppm[1]))
989 
990  region = self.Map.region
991 
992  heightCm = region['rows'] / self.ppm[1] * 100
993  widthCm = region['cols'] / self.ppm[0] * 100
994 
995  Debug.msg(4, "MapFrame.StatusbarUpdate(mapscale): width_cm=%f, height_cm=%f" %
996  (widthCm, heightCm))
997 
998  xscale = (region['e'] - region['w']) / (region['cols'] / self.ppm[0])
999  yscale = (region['n'] - region['s']) / (region['rows'] / self.ppm[1])
1000  scale = (xscale + yscale) / 2.
1001 
1002  Debug.msg(3, "MapFrame.StatusbarUpdate(mapscale): xscale=%f, yscale=%f -> scale=%f" % \
1003  (xscale, yscale, scale))
1004 
1005  self.statusbar.SetStatusText("")
1006  try:
1007  self.statusbarWin['mapscale'].SetValue("1:%ld" % (scale + 0.5))
1008  except TypeError:
1009  pass
1010  self.mapScaleValue = scale
1011  self.statusbarWin['mapscale'].Show()
1012 
1013  # disable long help
1014  self.StatusbarEnableLongHelp(False)
1015 
1016  elif self.statusbarWin['toggle'].GetSelection() == 7: # go to
1017  self.statusbar.SetStatusText("")
1018  region = self.Map.GetCurrentRegion()
1019  precision = int(UserSettings.Get(group = 'projection', key = 'format',
1020  subkey = 'precision'))
1021  format = UserSettings.Get(group = 'projection', key = 'format',
1022  subkey = 'll')
1023 
1024  if self.statusbarWin['projection'].IsChecked():
1025  if not UserSettings.Get(group='projection', key='statusbar', subkey='proj4'):
1026  self.statusbar.SetStatusText(_("Projection not defined (check the settings)"), 0)
1027  else:
1028  proj, coord = utils.ReprojectCoordinates(coord = (region['center_easting'],
1029  region['center_northing']),
1030  projOut = UserSettings.Get(group = 'projection',
1031  key = 'statusbar',
1032  subkey = 'proj4'),
1033  flags = 'd')
1034  if coord:
1035  if proj in ('ll', 'latlong', 'longlat') and format == 'DMS':
1036  self.statusbarWin['goto'].SetValue("%s" % utils.Deg2DMS(coord[0],
1037  coord[1],
1038  precision = precision))
1039  else:
1040  self.statusbarWin['goto'].SetValue("%.*f; %.*f" % (precision, coord[0],
1041  precision, coord[1]))
1042  else:
1043  self.statusbar.SetStatusText(_("Error in projection (check the settings)"), 0)
1044  else:
1045  if self.Map.projinfo['proj'] == 'll' and format == 'DMS':
1046  self.statusbarWin['goto'].SetValue("%s" % utils.Deg2DMS(region['center_easting'],
1047  region['center_northing'],
1048  precision = precision))
1049  else:
1050  self.statusbarWin['goto'].SetValue("%.*f; %.*f" % (precision, region['center_easting'],
1051  precision, region['center_northing']))
1052  self.statusbarWin['goto'].Show()
1053 
1054  # disable long help
1055  self.StatusbarEnableLongHelp(False)
1056 
1057  elif self.statusbarWin['toggle'].GetSelection() == 8: # projection
1058  self.statusbar.SetStatusText("")
1059  epsg = UserSettings.Get(group = 'projection', key = 'statusbar', subkey = 'epsg')
1060  if epsg:
1061  label = '%s (EPSG: %s)' % (_("Use defined projection"), epsg)
1062  self.statusbarWin['projection'].SetLabel(label)
1063  else:
1064  self.statusbarWin['projection'].SetLabel(_("Use defined projection"))
1065  self.statusbarWin['projection'].Show()
1066 
1067  # disable long help
1068  self.StatusbarEnableLongHelp(False)
1069 
1070  else:
1071  self.statusbar.SetStatusText("", 1)
1072 
1073  def StatusbarEnableLongHelp(self, enable = True):
1074  """!Enable/disable toolbars long help"""
1075  for toolbar in self.toolbars.itervalues():
1076  if toolbar:
1077  toolbar.EnableLongHelp(enable)
1078 
1080  """!Reposition checkbox in statusbar"""
1081  # reposition checkbox
1082  widgets = [(0, self.statusbarWin['region']),
1083  (0, self.statusbarWin['resolution']),
1084  (0, self.statusbarWin['mapscale']),
1085  (0, self.statusbarWin['progress']),
1086  (0, self.statusbarWin['projection']),
1087  (1, self.statusbarWin['toggle']),
1088  (2, self.statusbarWin['mask']),
1089  (3, self.statusbarWin['render'])]
1090  for idx, win in widgets:
1091  rect = self.statusbar.GetFieldRect(idx)
1092  if idx == 0: # show region / mapscale / process bar
1093  # -> size
1094  wWin, hWin = win.GetBestSize()
1095  if win == self.statusbarWin['progress']:
1096  wWin = rect.width - 6
1097  # -> position
1098  # if win == self.statusbarWin['region']:
1099  # x, y = rect.x + rect.width - wWin, rect.y - 1
1100  # align left
1101  # else:
1102  x, y = rect.x + 3, rect.y - 1
1103  w, h = wWin, rect.height + 2
1104  else: # choice || auto-rendering
1105  x, y = rect.x, rect.y - 1
1106  w, h = rect.width, rect.height + 2
1107  if idx == 2: # mask
1108  x += 5
1109  y += 4
1110  elif idx == 3: # render
1111  x += 5
1112  win.SetPosition((x, y))
1113  win.SetSize((w, h))
1114 
1115  def SaveToFile(self, event):
1116  """!Save map to image
1117  """
1118  if self.toolbars['nviz']:
1119  filetype = "PPM file (*.ppm)|*.ppm|TIF file (*.tif)|*.tif"
1120  ltype = [{ 'ext' : 'ppm', 'type' : -1 },
1121  { 'ext' : 'tif', 'type' : wx.BITMAP_TYPE_TIF }]
1122  else:
1123  img = self.MapWindow.img
1124  if not img:
1125  gcmd.GMessage(parent = self,
1126  message = _("Nothing to render (empty map). Operation canceled."))
1127  return
1128  filetype, ltype = gdialogs.GetImageHandlers(img)
1129 
1130  # get size
1131  dlg = gdialogs.ImageSizeDialog(self)
1132  dlg.CentreOnParent()
1133  if dlg.ShowModal() != wx.ID_OK:
1134  dlg.Destroy()
1135  return
1136  width, height = dlg.GetValues()
1137  dlg.Destroy()
1138 
1139  # get filename
1140  dlg = wx.FileDialog(parent = self,
1141  message = _("Choose a file name to save the image "
1142  "(no need to add extension)"),
1143  wildcard = filetype,
1144  style = wx.SAVE | wx.FD_OVERWRITE_PROMPT)
1145 
1146  if dlg.ShowModal() == wx.ID_OK:
1147  path = dlg.GetPath()
1148  if not path:
1149  dlg.Destroy()
1150  return
1151 
1152  base, ext = os.path.splitext(path)
1153  fileType = ltype[dlg.GetFilterIndex()]['type']
1154  extType = ltype[dlg.GetFilterIndex()]['ext']
1155  if ext != extType:
1156  path = base + '.' + extType
1157 
1158  self.MapWindow.SaveToFile(path, fileType,
1159  width, height)
1160 
1161  dlg.Destroy()
1162 
1163  def PrintMenu(self, event):
1164  """
1165  Print options and output menu for map display
1166  """
1167  point = wx.GetMousePosition()
1168  printmenu = wx.Menu()
1169  # Add items to the menu
1170  setup = wx.MenuItem(printmenu, wx.ID_ANY, _('Page setup'))
1171  printmenu.AppendItem(setup)
1172  self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup)
1173 
1174  preview = wx.MenuItem(printmenu, wx.ID_ANY, _('Print preview'))
1175  printmenu.AppendItem(preview)
1176  self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview)
1177 
1178  doprint = wx.MenuItem(printmenu, wx.ID_ANY, _('Print display'))
1179  printmenu.AppendItem(doprint)
1180  self.Bind(wx.EVT_MENU, self.printopt.OnDoPrint, doprint)
1181 
1182  # Popup the menu. If an item is selected then its handler
1183  # will be called before PopupMenu returns.
1184  self.PopupMenu(printmenu)
1185  printmenu.Destroy()
1186 
1187  def OnCloseWindow(self, event):
1188  """!Window closed.
1189  Also close associated layer tree page
1190  """
1191  pgnum = None
1192  self.Map.Clean()
1193 
1194  # close edited map and 3D tools properly
1195  if self.toolbars['vdigit']:
1196  maplayer = self.toolbars['vdigit'].GetLayer()
1197  if maplayer:
1198  self.toolbars['vdigit'].OnExit()
1199 
1200  if self.toolbars['nviz']:
1201  self.toolbars['nviz'].OnExit()
1202 
1203  if not self._layerManager:
1204  self.Destroy()
1205  elif self.page:
1206  pgnum = self.layerbook.GetPageIndex(self.page)
1207  if pgnum > -1:
1208  self.layerbook.DeletePage(pgnum)
1209 
1210  def GetRender(self):
1211  """!Returns current instance of render.Map()
1212  """
1213  return self.Map
1214 
1215  def GetWindow(self):
1216  """!Get map window"""
1217  return self.MapWindow
1218 
1219  def OnNvizQuerySurface(self, event):
1220  """!Query current surface in 3D view mode"""
1221  if self.toolbars['map'].GetAction() == 'nvizQuerySurface':
1222  self.toolbars['map'].SelectDefault(event)
1223  return
1224 
1225  self.toolbars['map'].action['desc'] = 'nvizQuerySurface'
1226 
1227  self.MapWindow.mouse['use'] = "nvizQuerySurface"
1228  self._OnQuery()
1229 
1230  def OnNvizQueryVector(self, event):
1231  """!Query current vector in 3D view mode"""
1232  if self.toolbars['map'].GetAction() == 'nvizQueryVector':
1233  self.toolbars['map'].SelectDefault(event)
1234  return
1235 
1236  self.toolbars['map'].action['desc'] = 'nvizQueryVector'
1237 
1238  self.MapWindow.mouse['use'] = "nvizQueryVector"
1239  self._OnQuery()
1240 
1241  def QueryMap(self, x, y):
1242  """!Query raster or vector map layers by r/v.what
1243 
1244  @param x,y coordinates
1245  """
1246  # set query snap distance for v.what at map unit equivalent of 10 pixels
1247  qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) / self.Map.width)
1248  east, north = self.MapWindow.Pixel2Cell((x, y))
1249 
1250  if not self.IsStandalone():
1251  num = 0
1252  for layer in self.tree.GetSelections():
1253  ltype = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
1254  if ltype in ('raster', 'rgb', 'his',
1255  'vector', 'thememap', 'themechart'):
1256  num += 1
1257 
1258  if num < 1:
1259  gcmd.GMessage(parent = self,
1260  message = _('No raster or vector map layer selected for querying.'))
1261  return
1262 
1263  rast = list()
1264  vect = list()
1265  rcmd = ['r.what', '--v']
1266  vcmd = ['v.what', '--v']
1267 
1268  if self.IsStandalone():
1269  pass
1270  else:
1271  for layer in self.tree.GetSelections():
1272  ltype = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
1273  dcmd = self.tree.GetPyData(layer)[0]['cmd']
1274  name, found = utils.GetLayerNameFromCmd(dcmd)
1275 
1276  if not found:
1277  continue
1278  if ltype == 'raster':
1279  rast.append(name)
1280  elif ltype in ('rgb', 'his'):
1281  for iname in name.split('\n'):
1282  rast.append(iname)
1283  elif ltype in ('vector', 'thememap', 'themechart'):
1284  vect.append(name)
1285 
1286  # use display region settings instead of computation region settings
1287  self.tmpreg = os.getenv("GRASS_REGION")
1288  os.environ["GRASS_REGION"] = self.Map.SetRegion(windres = False)
1289 
1290  # build query commands for any selected rasters and vectors
1291  if rast:
1292  rcmd.append('-f')
1293  rcmd.append('-n')
1294  rcmd.append('input=%s' % ','.join(rast))
1295  rcmd.append('east_north=%f,%f' % (float(east), float(north)))
1296 
1297  if vect:
1298  # check for vector maps open to be edited
1299  digitToolbar = self.toolbars['vdigit']
1300  if digitToolbar:
1301  lmap = digitToolbar.GetLayer().GetName()
1302  for name in vect:
1303  if lmap == name:
1304  self._layerManager.goutput.WriteWarning(_("Vector map <%s> "
1305  "opened for editing - skipped.") % map)
1306  vect.remove(name)
1307 
1308  if len(vect) < 1:
1309  self._layerManager.goutput.WriteCmdLog(_("Nothing to query."))
1310  return
1311 
1312  vcmd.append('-a')
1313  vcmd.append('map=%s' % ','.join(vect))
1314  vcmd.append('east_north=%f,%f' % (float(east), float(north)))
1315  vcmd.append('distance=%f' % float(qdist))
1316 
1317  Debug.msg(1, "QueryMap(): raster=%s vector=%s" % (','.join(rast),
1318  ','.join(vect)))
1319  # parse query command(s)
1320  if not self.IsStandalone():
1321  if rast:
1322  self._layerManager.goutput.RunCmd(rcmd,
1323  compReg = False,
1324  onDone = self._QueryMapDone)
1325  if vect:
1326  self._layerManager.goutput.RunCmd(vcmd,
1327  onDone = self._QueryMapDone)
1328  else:
1329  if rast:
1330  gcmd.RunCommand(rcmd)
1331  if vect:
1332  gcmd.RunCommand(vcmd)
1333 
1334  def _QueryMapDone(self, cmd, returncode):
1335  """!Restore settings after querying (restore GRASS_REGION)
1336 
1337  @param returncode command return code
1338  """
1339  if hasattr(self, "tmpreg"):
1340  if self.tmpreg:
1341  os.environ["GRASS_REGION"] = self.tmpreg
1342  elif 'GRASS_REGION' in os.environ:
1343  del os.environ["GRASS_REGION"]
1344  elif 'GRASS_REGION' in os.environ:
1345  del os.environ["GRASS_REGION"]
1346 
1347  if hasattr(self, "tmpreg"):
1348  del self.tmpreg
1349 
1350  def QueryVector(self, x, y):
1351  """!Query vector map layer features
1352 
1353  Attribute data of selected vector object are displayed in GUI dialog.
1354  Data can be modified (On Submit)
1355  """
1356  if not self.tree.layer_selected or \
1357  self.tree.GetPyData(self.tree.layer_selected)[0]['type'] != 'vector':
1358  gcmd.GMessage(parent = self,
1359  message = _("No map layer selected for querying."))
1360  return
1361 
1362  posWindow = self.ClientToScreen((x + self.MapWindow.dialogOffset,
1363  y + self.MapWindow.dialogOffset))
1364 
1365  qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) /
1366  self.Map.width)
1367 
1368  east, north = self.MapWindow.Pixel2Cell((x, y))
1369 
1370  mapName = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name
1371 
1372  if self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetMapset() != \
1373  grass.gisenv()['MAPSET']:
1374  mode = 'display'
1375  else:
1376  mode = 'update'
1377 
1378  if self.dialogs['attributes'] is None:
1379  dlg = dbm_dialogs.DisplayAttributesDialog(parent = self.MapWindow,
1380  map = mapName,
1381  query = ((east, north), qdist),
1382  pos = posWindow,
1383  action = mode)
1384  self.dialogs['attributes'] = dlg
1385 
1386  else:
1387  # selection changed?
1388  if not self.dialogs['attributes'].mapDBInfo or \
1389  self.dialogs['attributes'].mapDBInfo.map != mapName:
1390  self.dialogs['attributes'].UpdateDialog(map = mapName, query = ((east, north), qdist),
1391  action = mode)
1392  else:
1393  self.dialogs['attributes'].UpdateDialog(query = ((east, north), qdist),
1394  action = mode)
1395  if not self.dialogs['attributes'].IsFound():
1396  self._layerManager.goutput.WriteLog(_('Nothing found.'))
1397 
1398  cats = self.dialogs['attributes'].GetCats()
1399 
1400  try:
1401  qlayer = self.Map.GetListOfLayers(l_name = globalvar.QUERYLAYER)[0]
1402  except IndexError:
1403  qlayer = None
1404 
1405  if self.dialogs['attributes'].mapDBInfo and cats:
1406  # highlight feature & re-draw map
1407  if qlayer:
1408  qlayer.SetCmd(self.AddTmpVectorMapLayer(mapName, cats,
1409  useId = False,
1410  addLayer = False))
1411  else:
1412  qlayer = self.AddTmpVectorMapLayer(mapName, cats, useId = False)
1413 
1414  # set opacity based on queried layer
1415  opacity = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetOpacity(float = True)
1416  qlayer.SetOpacity(opacity)
1417 
1418  self.MapWindow.UpdateMap(render = False, renderVector = False)
1419  if not self.dialogs['attributes'].IsShown():
1420  self.dialogs['attributes'].Show()
1421  else:
1422  if qlayer:
1423  self.Map.DeleteLayer(qlayer)
1424  self.MapWindow.UpdateMap(render = False, renderVector = False)
1425  if self.dialogs['attributes'].IsShown():
1426  self.dialogs['attributes'].Hide()
1427 
1428  def OnQuery(self, event):
1429  """!Query tools menu"""
1430  if self.toolbars['map']:
1431  self.toolbars['map'].OnTool(event)
1432  action = self.toolbars['map'].GetAction()
1433 
1434  if self.toolbars['nviz']:
1435  toolsmenu = wx.Menu()
1436  raster = wx.MenuItem(parentMenu = toolsmenu, id = wx.ID_ANY,
1437  text = _("Query surface (raster map)"),
1438  kind = wx.ITEM_CHECK)
1439  toolsmenu.AppendItem(raster)
1440  self.Bind(wx.EVT_MENU, self.OnNvizQuerySurface, raster)
1441  if action == "nvizQuerySurface":
1442  raster.Check(True)
1443  vector = wx.MenuItem(parentMenu = toolsmenu, id = wx.ID_ANY,
1444  text = _("Query vector map"),
1445  kind = wx.ITEM_CHECK)
1446  toolsmenu.AppendItem(vector)
1447  self.Bind(wx.EVT_MENU, self.OnNvizQueryVector, vector)
1448  if action == "nvizQueryVector":
1449  vector.Check(True)
1450 
1451  self.PopupMenu(toolsmenu)
1452  toolsmenu.Destroy()
1453  else:
1454  self.toolbars['map'].action['desc'] = 'queryMap'
1455  self.MapWindow.mouse['use'] = "query"
1456 
1457  if not self.IsStandalone():
1458  # switch to output console to show query results
1459  self._layerManager.notebook.SetSelectionByName('output')
1460 
1461  self.MapWindow.mouse['box'] = "point"
1462  self.MapWindow.zoomtype = 0
1463 
1464  # change the cursor
1465  self.MapWindow.SetCursor(self.cursors["cross"])
1466 
1467  def AddTmpVectorMapLayer(self, name, cats, useId = False, addLayer = True):
1468  """!Add temporal vector map layer to map composition
1469 
1470  @param name name of map layer
1471  @param useId use feature id instead of category
1472  """
1473  # color settings from ATM
1474  color = UserSettings.Get(group = 'atm', key = 'highlight', subkey = 'color')
1475  colorStr = str(color[0]) + ":" + \
1476  str(color[1]) + ":" + \
1477  str(color[2])
1478 
1479  # icon used in vector display and its size
1480  icon = ''
1481  size = 0
1482  vparam = self.tree.GetPyData(self.tree.layer_selected)[0]['cmd']
1483  for p in vparam:
1484  if '=' in p:
1485  parg,pval = p.split('=')
1486  if parg == 'icon': icon = pval
1487  elif parg == 'size': size = int(pval)
1488 
1489  pattern = ["d.vect",
1490  "map=%s" % name,
1491  "color=%s" % colorStr,
1492  "fcolor=%s" % colorStr,
1493  "width=%d" % UserSettings.Get(group = 'atm', key = 'highlight', subkey = 'width')]
1494  if icon != '':
1495  pattern.append('icon=%s' % icon)
1496  if size > 0:
1497  pattern.append('size=%i' % size)
1498 
1499  if useId:
1500  cmd = pattern
1501  cmd.append('-i')
1502  cmd.append('cats=%s' % str(cats))
1503  else:
1504  cmd = []
1505  for layer in cats.keys():
1506  cmd.append(copy.copy(pattern))
1507  lcats = cats[layer]
1508  cmd[-1].append("layer=%d" % layer)
1509  cmd[-1].append("cats=%s" % utils.ListOfCatsToRange(lcats))
1510 
1511  if addLayer:
1512  if useId:
1513  return self.Map.AddLayer(type = 'vector', name = globalvar.QUERYLAYER, command = cmd,
1514  l_active = True, l_hidden = True, l_opacity = 1.0)
1515  else:
1516  return self.Map.AddLayer(type = 'command', name = globalvar.QUERYLAYER, command = cmd,
1517  l_active = True, l_hidden = True, l_opacity = 1.0)
1518  else:
1519  return cmd
1520 
1521  def OnAnalyze(self, event):
1522  """!Analysis tools menu
1523  """
1524  point = wx.GetMousePosition()
1525  toolsmenu = wx.Menu()
1526  icons = Icons['displayWindow']
1527 
1528  # Add items to the menu
1529  measure = wx.MenuItem(toolsmenu, wx.ID_ANY, icons["measure"].GetLabel())
1530  measure.SetBitmap(icons["measure"].GetBitmap(self.iconsize))
1531  toolsmenu.AppendItem(measure)
1532  self.Bind(wx.EVT_MENU, self.OnMeasure, measure)
1533 
1534  profile = wx.MenuItem(toolsmenu, wx.ID_ANY, icons["profile"].GetLabel())
1535  profile.SetBitmap(icons["profile"].GetBitmap(self.iconsize))
1536  toolsmenu.AppendItem(profile)
1537  self.Bind(wx.EVT_MENU, self.Profile, profile)
1538 
1539  histogram = wx.MenuItem(toolsmenu, wx.ID_ANY, icons["histogram"].GetLabel())
1540  histogram.SetBitmap(icons["histogram"].GetBitmap(self.iconsize))
1541  toolsmenu.AppendItem(histogram)
1542  self.Bind(wx.EVT_MENU, self.Histogram, histogram)
1543 
1544  # Popup the menu. If an item is selected then its handler
1545  # will be called before PopupMenu returns.
1546  self.PopupMenu(toolsmenu)
1547  toolsmenu.Destroy()
1548 
1549  def OnMeasure(self, event):
1550  """!Init measurement routine that calculates map distance
1551  along transect drawn on map display
1552  """
1553  self.totaldist = 0.0 # total measured distance
1554 
1555  # switch Layer Manager to output console to show measure results
1556  self._layerManager.notebook.SetSelectionByName('output')
1557 
1558  # change mouse to draw line for measurement
1559  self.MapWindow.mouse['use'] = "measure"
1560  self.MapWindow.mouse['box'] = "line"
1561  self.MapWindow.zoomtype = 0
1562  self.MapWindow.pen = wx.Pen(colour = 'red', width = 2, style = wx.SHORT_DASH)
1563  self.MapWindow.polypen = wx.Pen(colour = 'green', width = 2, style = wx.SHORT_DASH)
1564 
1565  # change the cursor
1566  self.MapWindow.SetCursor(self.cursors["pencil"])
1567 
1568  # initiating output
1569  style = self._layerManager.goutput.cmd_output.StyleWarning
1570  self._layerManager.goutput.WriteLog(_('Click and drag with left mouse button '
1571  'to measure.%s'
1572  'Double click with left button to clear.') % \
1573  (os.linesep), style)
1574  if self.Map.projinfo['proj'] != 'xy':
1575  units = self.Map.projinfo['units']
1576  self._layerManager.goutput.WriteCmdLog(_('Measuring distance') + ' ('
1577  + units + '):')
1578  else:
1579  self._layerManager.goutput.WriteCmdLog(_('Measuring distance:'))
1580 
1581  if self.Map.projinfo['proj'] == 'll':
1582  try:
1583  import grass.lib.gis as gislib
1584  global haveCtypes
1585  haveCtypes = True
1586 
1587  gislib.G_begin_distance_calculations()
1588  except ImportError, e:
1589  self._layerManager.goutput.WriteWarning(_('Geodesic distance is not yet '
1590  'supported by this tool.\n'
1591  'Reason: %s' % e))
1592 
1593  def MeasureDist(self, beginpt, endpt):
1594  """!Calculate map distance from screen distance
1595  and print to output window
1596  """
1597  self._layerManager.notebook.SetSelectionByName('output')
1598 
1599  dist, (north, east) = self.MapWindow.Distance(beginpt, endpt)
1600 
1601  dist = round(dist, 3)
1602  d, dunits = self.FormatDist(dist)
1603 
1604  self.totaldist += dist
1605  td, tdunits = self.FormatDist(self.totaldist)
1606 
1607  strdist = str(d)
1608  strtotdist = str(td)
1609 
1610  if self.Map.projinfo['proj'] == 'xy' or 'degree' not in self.Map.projinfo['unit']:
1611  angle = int(math.degrees(math.atan2(north,east)) + 0.5)
1612  angle = 180 - angle
1613  if angle < 0:
1614  angle = 360 + angle
1615 
1616  mstring = '%s = %s %s\n%s = %s %s\n%s = %d %s\n%s' \
1617  % (_('segment'), strdist, dunits,
1618  _('total distance'), strtotdist, tdunits,
1619  _('bearing'), angle, _('deg'),
1620  '-' * 60)
1621  else:
1622  mstring = '%s = %s %s\n%s = %s %s\n%s' \
1623  % (_('segment'), strdist, dunits,
1624  _('total distance'), strtotdist, tdunits,
1625  '-' * 60)
1626 
1627  self._layerManager.goutput.WriteLog(mstring)
1628 
1629  return dist
1630 
1631  def Profile(self, event):
1632  """!Init profile canvas and tools
1633  """
1634  raster = []
1635  if self.tree.layer_selected and \
1636  self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
1637  raster.append(self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
1638 
1640  id = wx.ID_ANY, pos = wx.DefaultPosition, size = (700,300),
1641  style = wx.DEFAULT_FRAME_STYLE, rasterList = raster)
1642  self.profile.Show()
1643  # Open raster select dialog to make sure that a raster (and the desired raster)
1644  # is selected to be profiled
1645  self.profile.OnSelectRaster(None)
1646 
1647  def FormatDist(self, dist):
1648  """!Format length numbers and units in a nice way,
1649  as a function of length. From code by Hamish Bowman
1650  Grass Development Team 2006"""
1651 
1652  mapunits = self.Map.projinfo['units']
1653  if mapunits == 'metres':
1654  mapunits = 'meters'
1655  outunits = mapunits
1656  dist = float(dist)
1657  divisor = 1.0
1658 
1659  # figure out which units to use
1660  if mapunits == 'meters':
1661  if dist > 2500.0:
1662  outunits = 'km'
1663  divisor = 1000.0
1664  else: outunits = 'm'
1665  elif mapunits == 'feet':
1666  # nano-bug: we match any "feet", but US Survey feet is really
1667  # 5279.9894 per statute mile, or 10.6' per 1000 miles. As >1000
1668  # miles the tick markers are rounded to the nearest 10th of a
1669  # mile (528'), the difference in foot flavours is ignored.
1670  if dist > 5280.0:
1671  outunits = 'miles'
1672  divisor = 5280.0
1673  else:
1674  outunits = 'ft'
1675  elif 'degree' in mapunits and \
1676  not haveCtypes:
1677  if dist < 1:
1678  outunits = 'min'
1679  divisor = (1/60.0)
1680  else:
1681  outunits = 'deg'
1682  else:
1683  outunits = 'meters'
1684 
1685  # format numbers in a nice way
1686  if (dist/divisor) >= 2500.0:
1687  outdist = round(dist/divisor)
1688  elif (dist/divisor) >= 1000.0:
1689  outdist = round(dist/divisor,1)
1690  elif (dist/divisor) > 0.0:
1691  outdist = round(dist/divisor,int(math.ceil(3-math.log10(dist/divisor))))
1692  else:
1693  outdist = float(dist/divisor)
1694 
1695  return (outdist, outunits)
1696 
1697  def Histogram(self, event):
1698  """!Init histogram display canvas and tools
1699  """
1701  id = wx.ID_ANY, size = globalvar.HIST_WINDOW_SIZE,
1702  style = wx.DEFAULT_FRAME_STYLE)
1703 
1704  #show new display
1705  self.histogram.Show()
1706  self.histogram.Refresh()
1707  self.histogram.Update()
1708 
1709 
1710  def OnDecoration(self, event):
1711  """!Decorations overlay menu
1712  """
1713  point = wx.GetMousePosition()
1714  decmenu = wx.Menu()
1715  icons = Icons['displayWindow']
1716 
1717  # Add items to the menu
1718  AddScale = wx.MenuItem(decmenu, wx.ID_ANY, icons["addBarscale"].GetLabel())
1719  AddScale.SetBitmap(icons["addBarscale"].GetBitmap(self.iconsize))
1720  decmenu.AppendItem(AddScale)
1721  self.Bind(wx.EVT_MENU, self.OnAddBarscale, AddScale)
1722 
1723  AddLegend = wx.MenuItem(decmenu, wx.ID_ANY, icons["addLegend"].GetLabel())
1724  AddLegend.SetBitmap(icons["addLegend"].GetBitmap(self.iconsize))
1725  decmenu.AppendItem(AddLegend)
1726  self.Bind(wx.EVT_MENU, self.OnAddLegend, AddLegend)
1727 
1728  AddText = wx.MenuItem(decmenu, wx.ID_ANY, icons["addText"].GetLabel())
1729  AddText.SetBitmap(icons["addText"].GetBitmap(self.iconsize))
1730  decmenu.AppendItem(AddText)
1731  self.Bind(wx.EVT_MENU, self.OnAddText, AddText)
1732 
1733  # Popup the menu. If an item is selected then its handler
1734  # will be called before PopupMenu returns.
1735  self.PopupMenu(decmenu)
1736  decmenu.Destroy()
1737 
1738  def OnAddBarscale(self, event):
1739  """!Handler for scale/arrow map decoration menu selection.
1740  """
1741  if self.dialogs['barscale']:
1742  return
1743 
1744  id = 0 # unique index for overlay layer
1745 
1746  # If location is latlon, only display north arrow (scale won't work)
1747  # proj = self.Map.projinfo['proj']
1748  # if proj == 'll':
1749  # barcmd = 'd.barscale -n'
1750  # else:
1751  # barcmd = 'd.barscale'
1752 
1753  # decoration overlay control dialog
1754  self.dialogs['barscale'] = \
1755  gdialogs.DecorationDialog(parent = self, title = _('Scale and North arrow'),
1756  size = (350, 200),
1757  style = wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
1758  cmd = ['d.barscale', 'at=0,5'],
1759  ovlId = id,
1760  name = 'barscale',
1761  checktxt = _("Show/hide scale and North arrow"),
1762  ctrltxt = _("scale object"))
1763 
1764  self.dialogs['barscale'].CentreOnParent()
1765  ### dialog cannot be show as modal - in the result d.barscale is not selectable
1766  ### self.dialogs['barscale'].ShowModal()
1767  self.dialogs['barscale'].Show()
1768  self.MapWindow.mouse['use'] = 'pointer'
1769 
1770  def OnAddLegend(self, event):
1771  """!Handler for legend map decoration menu selection.
1772  """
1773  if self.dialogs['legend']:
1774  return
1775 
1776  id = 1 # index for overlay layer in render
1777 
1778  cmd = ['d.legend', 'at=5,50,2,5']
1779  if self.tree.layer_selected and \
1780  self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
1781  cmd.append('map=%s' % self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
1782 
1783  # Decoration overlay control dialog
1784  self.dialogs['legend'] = \
1785  gdialogs.DecorationDialog(parent = self, title = ('Legend'),
1786  size = (350, 200),
1787  style = wx.DEFAULT_DIALOG_STYLE | wx.CENTRE,
1788  cmd = cmd,
1789  ovlId = id,
1790  name = 'legend',
1791  checktxt = _("Show/hide legend"),
1792  ctrltxt = _("legend object"))
1793 
1794  self.dialogs['legend'].CentreOnParent()
1795  ### dialog cannot be show as modal - in the result d.legend is not selectable
1796  ### self.dialogs['legend'].ShowModal()
1797  self.dialogs['legend'].Show()
1798  self.MapWindow.mouse['use'] = 'pointer'
1799 
1800  def OnAddText(self, event):
1801  """!Handler for text decoration menu selection.
1802  """
1803  if self.MapWindow.dragid > -1:
1804  id = self.MapWindow.dragid
1805  else:
1806  # index for overlay layer in render
1807  if len(self.MapWindow.textdict.keys()) > 0:
1808  id = self.MapWindow.textdict.keys()[-1] + 1
1809  else:
1810  id = 101
1811 
1812  self.dialogs['text'] = gdialogs.TextLayerDialog(parent = self, ovlId = id,
1813  title = _('Add text layer'),
1814  size = (400, 200))
1815  self.dialogs['text'].CenterOnParent()
1816 
1817  # If OK button pressed in decoration control dialog
1818  if self.dialogs['text'].ShowModal() == wx.ID_OK:
1819  text = self.dialogs['text'].GetValues()['text']
1820  active = self.dialogs['text'].GetValues()['active']
1821  coords, w, h = self.MapWindow.TextBounds(self.dialogs['text'].GetValues())
1822 
1823  # delete object if it has no text or is not active
1824  if text == '' or active == False:
1825  try:
1826  self.MapWindow.pdc.ClearId(id)
1827  self.MapWindow.pdc.RemoveId(id)
1828  del self.MapWindow.textdict[id]
1829  except:
1830  pass
1831  return
1832 
1833  self.MapWindow.pdc.ClearId(id)
1834  self.MapWindow.pdc.SetId(id)
1835  self.MapWindow.textdict[id] = self.dialogs['text'].GetValues()
1836 
1837  self.MapWindow.Draw(self.MapWindow.pdcDec, img = self.MapWindow.textdict[id],
1838  drawid = id, pdctype = 'text', coords = coords)
1839 
1840  self.MapWindow.UpdateMap(render = False, renderVector = False)
1841 
1842  self.MapWindow.mouse['use'] = 'pointer'
1843 
1844  def GetOptData(self, dcmd, type, params, propwin):
1845  """!Callback method for decoration overlay command generated by
1846  dialog created in menuform.py
1847  """
1848  # Reset comand and rendering options in render.Map. Always render decoration.
1849  # Showing/hiding handled by PseudoDC
1850  self.Map.ChangeOverlay(ovltype = type, type = 'overlay', name = '', command = dcmd,
1851  l_active = True, l_render = False)
1852  self.params[type] = params
1853  self.propwin[type] = propwin
1854 
1855  def OnZoomToMap(self, event):
1856  """!Set display extents to match selected raster (including
1857  NULLs) or vector map.
1858  """
1859  self.MapWindow.ZoomToMap()
1860 
1861  def OnZoomToRaster(self, event):
1862  """!Set display extents to match selected raster map (ignore NULLs)
1863  """
1864  self.MapWindow.ZoomToMap(ignoreNulls = True)
1865 
1866  def OnZoomToWind(self, event):
1867  """!Set display geometry to match computational region
1868  settings (set with g.region)
1869  """
1870  self.MapWindow.ZoomToWind()
1871 
1872  def OnZoomToDefault(self, event):
1873  """!Set display geometry to match default region settings
1874  """
1875  self.MapWindow.ZoomToDefault()
1876 
1877  def OnZoomToSaved(self, event):
1878  """!Set display geometry to match extents in
1879  saved region file
1880  """
1881  self.MapWindow.ZoomToSaved()
1882 
1883  def OnDisplayToWind(self, event):
1884  """!Set computational region (WIND file) to match display
1885  extents
1886  """
1887  self.MapWindow.DisplayToWind()
1888 
1889  def SaveDisplayRegion(self, event):
1890  """!Save display extents to named region file.
1891  """
1892  self.MapWindow.SaveDisplayRegion()
1893 
1894  def OnZoomMenu(self, event):
1895  """!Popup Zoom menu
1896  """
1897  point = wx.GetMousePosition()
1898  zoommenu = wx.Menu()
1899  # Add items to the menu
1900 
1901  zoomwind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to computational region (set with g.region)'))
1902  zoommenu.AppendItem(zoomwind)
1903  self.Bind(wx.EVT_MENU, self.OnZoomToWind, zoomwind)
1904 
1905  zoomdefault = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to default region'))
1906  zoommenu.AppendItem(zoomdefault)
1907  self.Bind(wx.EVT_MENU, self.OnZoomToDefault, zoomdefault)
1908 
1909  zoomsaved = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to saved region'))
1910  zoommenu.AppendItem(zoomsaved)
1911  self.Bind(wx.EVT_MENU, self.OnZoomToSaved, zoomsaved)
1912 
1913  savewind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Set computational region from display extent'))
1914  zoommenu.AppendItem(savewind)
1915  self.Bind(wx.EVT_MENU, self.OnDisplayToWind, savewind)
1916 
1917  savezoom = wx.MenuItem(zoommenu, wx.ID_ANY, _('Save display geometry to named region'))
1918  zoommenu.AppendItem(savezoom)
1919  self.Bind(wx.EVT_MENU, self.SaveDisplayRegion, savezoom)
1920 
1921  # Popup the menu. If an item is selected then its handler
1922  # will be called before PopupMenu returns.
1923  self.PopupMenu(zoommenu)
1924  zoommenu.Destroy()
1925 
1926  def SetProperties(self, render = False, mode = 0, showCompExtent = False,
1927  constrainRes = False, projection = False):
1928  """!Set properies of map display window"""
1929  self.statusbarWin['render'].SetValue(render)
1930  self.statusbarWin['toggle'].SetSelection(mode)
1931  self.StatusbarUpdate()
1932  self.statusbarWin['region'].SetValue(showCompExtent)
1933  self.statusbarWin['resolution'].SetValue(constrainRes)
1934  self.statusbarWin['projection'].SetValue(projection)
1935  if showCompExtent:
1936  self.MapWindow.regionCoords = []
1937 
1938  def IsStandalone(self):
1939  """!Check if Map display is standalone"""
1940  if self._layerManager:
1941  return False
1942 
1943  return True
1944 
1945  def GetLayerManager(self):
1946  """!Get reference to Layer Manager
1947 
1948  @return window reference
1949  @return None (if standalone)
1950  """
1951  return self._layerManager
1952 
1953 # end of class MapFrame
1954 
1955 class MapApp(wx.App):
1956  def OnInit(self):
1957  wx.InitAllImageHandlers()
1958  if __name__ == "__main__":
1959  Map = render.Map() # instance of Map class to render GRASS display output to PPM file
1960  else:
1961  Map = None
1962 
1963  self.mapFrm = MapFrame(parent = None, id = wx.ID_ANY, Map = Map,
1964  size = globalvar.MAP_WINDOW_SIZE)
1965  #self.SetTopWindow(Map)
1966  self.mapFrm.Show()
1967 
1968  if __name__ == "__main__":
1969  # redraw map, if new command appears
1970  self.redraw = False
1971  status = Command(self, Map, cmdfilename)
1972  status.start()
1973  self.timer = wx.PyTimer(self.watcher)
1974  # check each 0.1s
1975  self.timer.Start(100)
1976 
1977  return 1
1978 
1979  def OnExit(self):
1980  if __name__ == "__main__":
1981  # stop the timer
1982  self.timer.Stop()
1983  # terminate thread (a bit ugly)
1984  os.system("""!echo "quit" >> %s""" % (cmdfilename))
1985 
1986  def watcher(self):
1987  """!Redraw, if new layer appears"""
1988  if self.redraw:
1989  self.mapFrm.OnDraw(None)
1990  self.redraw = False
1991  return
1992 # end of class MapApp
1993 
1994 if __name__ == "__main__":
1995 
1996  ###### SET command variable
1997  if len(sys.argv) != 3:
1998  print __doc__
1999  sys.exit()
2000 
2001  title = sys.argv[1]
2002  cmdfilename = sys.argv[2]
2003 
2004  import gettext
2005  gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
2006 
2007  print >> sys.stderr, "\nStarting monitor <%s>...\n" % (title)
2008 
2009  gm_map = MapApp(0)
2010  # set title
2011  gm_map.mapFrm.SetTitle(_("GRASS GIS Map Display: " +
2012  title +
2013  " - Location: " + grass.gisenv()["LOCATION_NAME"]))
2014 
2015  gm_map.MainLoop()
2016 
2017  if grass.gisenv().has_key("MONITOR"):
2018  os.system("d.mon sel=%s" % grass.gisenv()["MONITOR"])
2019 
2020  os.remove(cmdfilename)
2021  os.system("""!g.gisenv set="GRASS_PYCMDFILE" """)
2022 
2023  print >> sys.stderr, "\nStoping monitor <%s>...\n" % (title)
2024 
2025  sys.exit(0)