GRASS Programmer's Manual  6.4.4(2014)-r
mapdisp/frame.py
Go to the documentation of this file.
1 """!
2 @package mapdisp.frame
3 
4 @brief Map display with toolbar for various display management
5 functions, and additional toolbars (vector digitizer, 3d view).
6 
7 Can be used either from Layer Manager or as d.mon backend.
8 
9 Classes:
10  - mapdisp::MapFrame
11 
12 (C) 2006-2011 by the GRASS Development Team
13 
14 This program is free software under the GNU General Public License
15 (>=v2). Read the file COPYING that comes with GRASS for details.
16 
17 @author Michael Barton
18 @author Jachym Cepicky
19 @author Martin Landa <landa.martin gmail.com>
20 @author Vaclav Petras <wenzeslaus gmail.com> (MapFrameBase)
21 @author Anna Kratochvilova <kratochanna gmail.com> (MapFrameBase)
22 """
23 
24 import os
25 import sys
26 import math
27 import copy
28 
29 from core import globalvar
30 import wx
31 import wx.aui
32 
33 sys.path.append(os.path.join(globalvar.ETCWXDIR, "icons"))
34 sys.path.append(os.path.join(globalvar.ETCDIR, "python"))
35 
36 from core import globalvar
37 from core.render import EVT_UPDATE_PRGBAR
38 from vdigit.toolbars import VDigitToolbar
39 from mapdisp.toolbars import MapToolbar, NvizIcons
40 from mapdisp.gprint import PrintOptions
41 from core.gcmd import GError, GMessage, RunCommand
42 from dbmgr.dialogs import DisplayAttributesDialog
43 from core.utils import ListOfCatsToRange, GetLayerNameFromCmd, GetAllVectorLayers
44 from gui_core.dialogs import GetImageHandlers, ImageSizeDialog, DecorationDialog, TextLayerDialog, \
45  DECOR_DIALOG_LEGEND, DECOR_DIALOG_BARSCALE
46 from core.debug import Debug
47 from core.settings import UserSettings
48 from gui_core.mapdisp import MapFrameBase
49 from mapdisp.mapwindow import BufferedWindow
50 from mapdisp.overlays import LegendController, BarscaleController
51 from modules.histogram import HistogramFrame
52 from wxplot.profile import ProfileFrame
53 
54 from mapdisp import statusbar as sb
55 
56 import grass.script as grass
57 
58 haveCtypes = False
59 
60 class MapFrame(MapFrameBase):
61  """!Main frame for map display window. Drawing takes place in
62  child double buffered drawing window.
63  """
64  def __init__(self, parent = None, title = _("GRASS GIS - Map display"),
65  toolbars = ["map"], tree = None, notebook = None, lmgr = None,
66  page = None, Map = None, auimgr = None, name = 'MapWindow', **kwargs):
67  """!Main map display window with toolbars, statusbar and
68  BufferedWindow (map canvas)
69 
70  @param toolbars array of activated toolbars, e.g. ['map', 'digit']
71  @param tree reference to layer tree
72  @param notebook control book ID in Layer Manager
73  @param lmgr Layer Manager
74  @param page notebook page with layer tree
75  @param Map instance of render.Map
76  @param auimgs AUI manager
77  @param name frame name
78  @param kwargs wx.Frame attributes
79  """
80  MapFrameBase.__init__(self, parent = parent, title = title, toolbars = toolbars,
81  Map = Map, auimgr = auimgr, name = name, **kwargs)
82 
83  self._layerManager = lmgr # Layer Manager object
84  self.tree = tree # Layer Manager layer tree object
85  self.page = page # Notebook page holding the layer tree
86  self.layerbook = notebook # Layer Manager layer tree notebook
87  #
88  # Add toolbars
89  #
90  for toolb in toolbars:
91  self.AddToolbar(toolb)
92 
93  #
94  # Add statusbar
95  #
96 
97  # items for choice
98  self.statusbarItems = [sb.SbCoordinates,
99  sb.SbRegionExtent,
100  sb.SbCompRegionExtent,
101  sb.SbShowRegion,
102  sb.SbAlignExtent,
103  sb.SbResolution,
104  sb.SbDisplayGeometry,
105  sb.SbMapScale,
106  sb.SbGoTo,
107  sb.SbProjection]
108 
109  self.statusbarItemsHiddenInNviz = (sb.SbAlignExtent,
110  sb.SbDisplayGeometry,
111  sb.SbShowRegion,
112  sb.SbResolution,
113  sb.SbMapScale)
114 
115  # create statusbar and its manager
116  statusbar = self.CreateStatusBar(number = 4, style = 0)
117  statusbar.SetStatusWidths([-5, -2, -1, -1])
118  self.statusbarManager = sb.SbManager(mapframe = self, statusbar = statusbar)
119 
120  # fill statusbar manager
121  self.statusbarManager.AddStatusbarItemsByClass(self.statusbarItems, mapframe = self, statusbar = statusbar)
122  self.statusbarManager.AddStatusbarItem(sb.SbMask(self, statusbar = statusbar, position = 2))
123  self.statusbarManager.AddStatusbarItem(sb.SbRender(self, statusbar = statusbar, position = 3))
124 
125  self.statusbarManager.Update()
126 
127  # init decoration objects
128  self.decorations = {}
129  self.legend = LegendController(self.Map)
130  self.barscale = BarscaleController(self.Map)
131  self.decorations[self.legend.id] = self.legend
132  self.decorations[self.barscale.id] = self.barscale
133 
134  #
135  # Init map display (buffered DC & set default cursor)
136  #
137  self.MapWindow2D = BufferedWindow(self, id = wx.ID_ANY, overlays = self.decorations,
138  Map = self.Map, tree = self.tree, lmgr = self._layerManager)
139  # default is 2D display mode
140  self.MapWindow = self.MapWindow2D
141  self.MapWindow.SetCursor(self.cursors["default"])
142  # used by vector digitizer
143  self.MapWindowVDigit = None
144  # used by Nviz (3D display mode)
145  self.MapWindow3D = None
146 
147  #
148  # initialize region values
149  #
150  self._initMap(map = self.Map)
151 
152  #
153  # Bind various events
154  #
155  self.Bind(wx.EVT_ACTIVATE, self.OnFocus)
156  self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
157  self.Bind(EVT_UPDATE_PRGBAR, self.OnUpdateProgress)
158 
159  #
160  # Update fancy gui style
161  #
162  self._mgr.AddPane(self.MapWindow, wx.aui.AuiPaneInfo().CentrePane().
163  Dockable(False).BestSize((-1,-1)).Name('2d').
164  CloseButton(False).DestroyOnClose(True).
165  Layer(0))
166  self._mgr.Update()
167 
168  #
169  # Init print module and classes
170  #
171  self.printopt = PrintOptions(self, self.MapWindow)
172 
173  #
174  # Init zoom history
175  #
176  self.MapWindow.ZoomHistory(self.Map.region['n'],
177  self.Map.region['s'],
178  self.Map.region['e'],
179  self.Map.region['w'])
180 
181  #
182  # Re-use dialogs
183  #
184  self.dialogs = {}
185  self.dialogs['attributes'] = None
186  self.dialogs['category'] = None
187  self.dialogs['barscale'] = None
188  self.dialogs['legend'] = None
189 
190  self.decorationDialog = None # decoration/overlays
191 
192  def GetMapWindow(self):
193  return self.MapWindow
194 
195  def _addToolbarVDigit(self):
196  """!Add vector digitizer toolbar
197  """
198  from vdigit.main import haveVDigit
199 
200  if not haveVDigit:
201  from vdigit import errorMsg
202  msg = _("Unable to start wxGUI vector digitizer.\nDo you want to start "
203  "TCL/TK digitizer (v.digit) instead?\n\n"
204  "Details: %s" % errorMsg)
205 
206  self.toolbars['map'].combo.SetValue(_("2D view"))
207  dlg = wx.MessageDialog(parent = self,
208  message = msg,
209  caption=_("Vector digitizer failed"),
210  style = wx.YES_NO | wx.CENTRE)
211  if dlg.ShowModal() == wx.ID_YES:
212  mapName = self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].GetName()
213  self._layerManager.goutput.RunCmd(['v.digit', 'map=%s' % mapName],
214  switchPage = False)
215  dlg.Destroy()
216 
217  self.toolbars['map'].combo.SetValue(_("2D view"))
218  return
219 
220  if self._layerManager:
221  log = self._layerManager.goutput
222  else:
223  log = None
224 
225  if not self.MapWindowVDigit:
226  from vdigit.mapwindow import VDigitWindow
227  self.MapWindowVDigit = VDigitWindow(self, id = wx.ID_ANY,
228  Map = self.Map, tree = self.tree,
229  lmgr = self._layerManager)
230  self.MapWindowVDigit.Show()
231  self._mgr.AddPane(self.MapWindowVDigit, wx.aui.AuiPaneInfo().CentrePane().
232  Dockable(False).BestSize((-1,-1)).Name('vdigit').
233  CloseButton(False).DestroyOnClose(True).
234  Layer(0))
235 
236  self.MapWindow = self.MapWindowVDigit
237 
238  if self._mgr.GetPane('2d').IsShown():
239  self._mgr.GetPane('2d').Hide()
240  elif self._mgr.GetPane('3d').IsShown():
241  self._mgr.GetPane('3d').Hide()
242  self._mgr.GetPane('vdigit').Show()
243  self.toolbars['vdigit'] = VDigitToolbar(parent = self, mapcontent = self.Map,
244  layerTree = self.tree,
245  log = log)
246  self.MapWindowVDigit.SetToolbar(self.toolbars['vdigit'])
247 
248  self._mgr.AddPane(self.toolbars['vdigit'],
249  wx.aui.AuiPaneInfo().
250  Name("vdigittoolbar").Caption(_("Vector Digitizer Toolbar")).
251  ToolbarPane().Top().Row(1).
252  LeftDockable(False).RightDockable(False).
253  BottomDockable(False).TopDockable(True).
254  CloseButton(False).Layer(2).
255  BestSize((self.toolbars['vdigit'].GetBestSize())))
256  # change mouse to draw digitized line
257  self.MapWindow.mouse['box'] = "point"
258  self.MapWindow.zoomtype = 0
259  self.MapWindow.pen = wx.Pen(colour = 'red', width = 2, style = wx.SOLID)
260  self.MapWindow.polypen = wx.Pen(colour = 'green', width = 2, style = wx.SOLID)
261 
262  def AddNviz(self):
263  """!Add 3D view mode window
264  """
265  from nviz.main import haveNviz, GLWindow
266 
267  # check for GLCanvas and OpenGL
268  if not haveNviz:
269  self.toolbars['map'].combo.SetValue(_("2D view"))
270  GError(parent = self,
271  message = _("Unable to switch to 3D display mode.\nThe Nviz python extension "
272  "was not found or loaded properly.\n"
273  "Switching back to 2D display mode.\n\nDetails: %s" % nviz.errorMsg))
274  return
275 
276  # disable 3D mode for other displays
277  for page in range(0, self._layerManager.gm_cb.GetPageCount()):
278  if self._layerManager.gm_cb.GetPage(page) != self._layerManager.curr_page:
279  if '3D' in self._layerManager.gm_cb.GetPage(page).maptree.mapdisplay.toolbars['map'].combo.GetString(1):
280  self._layerManager.gm_cb.GetPage(page).maptree.mapdisplay.toolbars['map'].combo.Delete(1)
281  self.toolbars['map'].Enable2D(False)
282  # add rotate tool to map toolbar
283  self.toolbars['map'].InsertTool((('rotate', NvizIcons['rotate'],
284  self.OnRotate, wx.ITEM_CHECK, 7),)) # 7 is position
285  self.toolbars['map'].InsertTool((('flyThrough', NvizIcons['flyThrough'],
286  self.OnFlyThrough, wx.ITEM_CHECK, 8),))
287  self.toolbars['map'].ChangeToolsDesc(mode2d = False)
288  # update status bar
289 
290  self.statusbarManager.HideStatusbarChoiceItemsByClass(self.statusbarItemsHiddenInNviz)
291  self.statusbarManager.SetMode(0)
292 
293  # erase map window
294  self.MapWindow.EraseMap()
295 
296  self._layerManager.goutput.WriteCmdLog(_("Starting 3D view mode..."),
297  switchPage = False)
298  self.SetStatusText(_("Please wait, loading data..."), 0)
299 
300  # create GL window
301  if not self.MapWindow3D:
302  self.MapWindow3D = GLWindow(self, id = wx.ID_ANY,
303  Map = self.Map, tree = self.tree, lmgr = self._layerManager)
304  self.MapWindow = self.MapWindow3D
305  self.MapWindow.SetCursor(self.cursors["default"])
306 
307  # add Nviz notebookpage
308  self._layerManager.AddNvizTools()
309 
310  # switch from MapWindow to MapWindowGL
311  self._mgr.GetPane('2d').Hide()
312  self._mgr.AddPane(self.MapWindow3D, wx.aui.AuiPaneInfo().CentrePane().
313  Dockable(False).BestSize((-1,-1)).Name('3d').
314  CloseButton(False).DestroyOnClose(True).
315  Layer(0))
316 
317  self.MapWindow3D.Show()
318  self.MapWindow3D.ResetViewHistory()
319  self.MapWindow3D.UpdateView(None)
320  else:
321  self.MapWindow = self.MapWindow3D
322  os.environ['GRASS_REGION'] = self.Map.SetRegion(windres = True)
323  self.MapWindow3D.GetDisplay().Init()
324  del os.environ['GRASS_REGION']
325 
326  # switch from MapWindow to MapWindowGL
327  self._mgr.GetPane('2d').Hide()
328  self._mgr.GetPane('3d').Show()
329 
330  # add Nviz notebookpage
331  self._layerManager.AddNvizTools()
332  self.MapWindow3D.ResetViewHistory()
333  for page in ('view', 'light', 'fringe', 'constant', 'cplane', 'animation'):
334  self._layerManager.nviz.UpdatePage(page)
335 
336  self.MapWindow3D.overlays = self.MapWindow2D.overlays
337  self.MapWindow3D.textdict = self.MapWindow2D.textdict
338  # update overlays needs to be called after because getClientSize
339  # is called during update and it must give reasonable values
340  wx.CallAfter(self.MapWindow3D.UpdateOverlays)
341 
342  self.SetStatusText("", 0)
343  self._mgr.Update()
344 
345  def RemoveNviz(self):
346  """!Restore 2D view"""
347  self.toolbars['map'].RemoveTool(self.toolbars['map'].rotate)
348  self.toolbars['map'].RemoveTool(self.toolbars['map'].flyThrough)
349  # update status bar
350  self.statusbarManager.ShowStatusbarChoiceItemsByClass(self.statusbarItemsHiddenInNviz)
351  self.statusbarManager.SetMode(UserSettings.Get(group = 'display',
352  key = 'statusbarMode',
353  subkey = 'selection'))
354  self.SetStatusText(_("Please wait, unloading data..."), 0)
355  self._layerManager.goutput.WriteCmdLog(_("Switching back to 2D view mode..."),
356  switchPage = False)
357  self.MapWindow3D.OnClose(event = None)
358  # switch from MapWindowGL to MapWindow
359  self._mgr.GetPane('2d').Show()
360  self._mgr.GetPane('3d').Hide()
361 
362  self.MapWindow = self.MapWindow2D
363  # remove nviz notebook page
364  self._layerManager.RemoveNvizTools()
365 
366  self.MapWindow2D.overlays = self.MapWindow3D.overlays
367  self.MapWindow2D.textdict = self.MapWindow3D.textdict
368  self.MapWindow.UpdateMap()
369  self._mgr.Update()
370 
371  def AddToolbar(self, name):
372  """!Add defined toolbar to the window
373 
374  Currently known toolbars are:
375  - 'map' - basic map toolbar
376  - 'vdigit' - vector digitizer
377  - 'gcpdisp' - GCP Manager Display
378  """
379  # default toolbar
380  if name == "map":
381  self.toolbars['map'] = MapToolbar(self, self.Map)
382 
383  self._mgr.AddPane(self.toolbars['map'],
384  wx.aui.AuiPaneInfo().
385  Name("maptoolbar").Caption(_("Map Toolbar")).
386  ToolbarPane().Top().Name('mapToolbar').
387  LeftDockable(False).RightDockable(False).
388  BottomDockable(False).TopDockable(True).
389  CloseButton(False).Layer(2).
390  BestSize((self.toolbars['map'].GetBestSize())))
391 
392  # vector digitizer
393  elif name == "vdigit":
394  self._addToolbarVDigit()
395 
396  self._mgr.Update()
397 
398  def RemoveToolbar (self, name):
399  """!Removes defined toolbar from the window
400 
401  @todo Only hide, activate by calling AddToolbar()
402  """
403  # cannot hide main toolbar
404  if name == "map":
405  return
406 
407  self._mgr.DetachPane(self.toolbars[name])
408  self.toolbars[name].Destroy()
409  self.toolbars.pop(name)
410 
411  if name == 'vdigit':
412  self._mgr.GetPane('vdigit').Hide()
413  self._mgr.GetPane('2d').Show()
414  self.MapWindow = self.MapWindow2D
415 
416  self.toolbars['map'].combo.SetValue(_("2D view"))
417  self.toolbars['map'].Enable2D(True)
418 
419  self._mgr.Update()
420 
421  def IsPaneShown(self, name):
422  """!Check if pane (toolbar, mapWindow ...) of given name is currently shown"""
423  if self._mgr.GetPane(name).IsOk():
424  return self._mgr.GetPane(name).IsShown()
425  return False
426 
427  def OnUpdateProgress(self, event):
428  """!Update progress bar info
429  """
430  self.GetProgressBar().SetValue(event.value)
431 
432  event.Skip()
433 
434  def OnFocus(self, event):
435  """!Change choicebook page to match display.
436  """
437  # change bookcontrol page to page associated with display
438  if self.page:
439  pgnum = self.layerbook.GetPageIndex(self.page)
440  if pgnum > -1:
441  self.layerbook.SetSelection(pgnum)
442  self._layerManager.curr_page = self.layerbook.GetCurrentPage()
443 
444  event.Skip()
445 
446  def RemoveQueryLayer(self):
447  """!Removes temporary map layers (queries)"""
448  qlayer = self.GetMap().GetListOfLayers(l_name = globalvar.QUERYLAYER)
449  for layer in qlayer:
450  self.GetMap().DeleteLayer(layer)
451 
452  def OnRender(self, event):
453  """!Re-render map composition (each map layer)
454  """
455  self.RemoveQueryLayer()
456 
457  # delete tmp lines
458  if self.MapWindow.mouse["use"] in ("measure",
459  "profile"):
460  self.MapWindow.polycoords = []
461  self.MapWindow.ClearLines()
462 
463  # deselect features in vdigit
464  if self.GetToolbar('vdigit'):
465  if self.MapWindow.digit:
466  self.MapWindow.digit.GetDisplay().SetSelected([])
467  self.MapWindow.UpdateMap(render = True, renderVector = True)
468  else:
469  self.MapWindow.UpdateMap(render = True)
470 
471  # update statusbar
472  self.StatusbarUpdate()
473 
474  def OnPointer(self, event):
475  """!Pointer button clicked
476  """
477  if self.GetMapToolbar():
478  if event:
479  self.toolbars['map'].OnTool(event)
480  self.toolbars['map'].action['desc'] = ''
481 
482  self.MapWindow.mouse['use'] = "pointer"
483  self.MapWindow.mouse['box'] = "point"
484 
485  # change the cursor
486  if self.GetToolbar('vdigit'):
487  # digitization tool activated
488  self.MapWindow.SetCursor(self.cursors["cross"])
489 
490  # reset mouse['box'] if needed
491  if self.toolbars['vdigit'].GetAction() in ['addLine']:
492  if self.toolbars['vdigit'].GetAction('type') in ['point', 'centroid']:
493  self.MapWindow.mouse['box'] = 'point'
494  else: # line, boundary
495  self.MapWindow.mouse['box'] = 'line'
496  elif self.toolbars['vdigit'].GetAction() in ['addVertex', 'removeVertex', 'splitLine',
497  'editLine', 'displayCats', 'queryMap',
498  'copyCats']:
499  self.MapWindow.mouse['box'] = 'point'
500  else: # moveLine, deleteLine
501  self.MapWindow.mouse['box'] = 'box'
502 
503  else:
504  self.MapWindow.SetCursor(self.cursors["default"])
505 
506  def OnRotate(self, event):
507  """!Rotate 3D view
508  """
509  if self.GetMapToolbar():
510  self.toolbars['map'].OnTool(event)
511  self.toolbars['map'].action['desc'] = ''
512 
513  self.MapWindow.mouse['use'] = "rotate"
514 
515  # change the cursor
516  self.MapWindow.SetCursor(self.cursors["hand"])
517 
518  def OnFlyThrough(self, event):
519  """!Fly-through mode
520  """
521  if self.toolbars['map']:
522  self.toolbars['map'].OnTool(event)
523  self.toolbars['map'].action['desc'] = ''
524 
525  self.MapWindow.mouse['use'] = "fly"
526 
527  # change the cursor
528  self.MapWindow.SetCursor(self.cursors["hand"])
529  self.MapWindow.SetFocus()
530 
531  def OnZoomRegion(self, event):
532  """
533  Zoom to region
534  """
535  self.Map.getRegion()
536  self.Map.getResolution()
537  self.UpdateMap()
538  # event.Skip()
539 
540  def OnAlignRegion(self, event):
541  """
542  Align region
543  """
544  if not self.Map.alignRegion:
545  self.Map.alignRegion = True
546  else:
547  self.Map.alignRegion = False
548  # event.Skip()
549 
550  def SaveToFile(self, event):
551  """!Save map to image
552  """
553  if self.IsPaneShown('3d'):
554  filetype = "TIF file (*.tif)|*.tif|PPM file (*.ppm)|*.ppm"
555  ltype = [{ 'ext' : 'tif', 'type' : 'tif' },
556  { 'ext' : 'ppm', 'type' : 'ppm' }]
557  else:
558  img = self.MapWindow.img
559  if not img:
560  GMessage(parent = self,
561  message = _("Nothing to render (empty map). Operation canceled."))
562  return
563  filetype, ltype = GetImageHandlers(img)
564 
565  # get size
566  dlg = ImageSizeDialog(self)
567  dlg.CentreOnParent()
568  if dlg.ShowModal() != wx.ID_OK:
569  dlg.Destroy()
570  return
571  width, height = dlg.GetValues()
572  dlg.Destroy()
573 
574  # get filename
575  dlg = wx.FileDialog(parent = self,
576  message = _("Choose a file name to save the image "
577  "(no need to add extension)"),
578  wildcard = filetype,
579  style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
580 
581  if dlg.ShowModal() == wx.ID_OK:
582  path = dlg.GetPath()
583  if not path:
584  dlg.Destroy()
585  return
586 
587  base, ext = os.path.splitext(path)
588  fileType = ltype[dlg.GetFilterIndex()]['type']
589  extType = ltype[dlg.GetFilterIndex()]['ext']
590  if ext != extType:
591  path = base + '.' + extType
592 
593  self.MapWindow.SaveToFile(path, fileType,
594  width, height)
595 
596  dlg.Destroy()
597 
598  def PrintMenu(self, event):
599  """
600  Print options and output menu for map display
601  """
602  point = wx.GetMousePosition()
603  printmenu = wx.Menu()
604  # Add items to the menu
605  setup = wx.MenuItem(printmenu, wx.ID_ANY, _('Page setup'))
606  printmenu.AppendItem(setup)
607  self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup)
608 
609  preview = wx.MenuItem(printmenu, wx.ID_ANY, _('Print preview'))
610  printmenu.AppendItem(preview)
611  self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview)
612 
613  doprint = wx.MenuItem(printmenu, wx.ID_ANY, _('Print display'))
614  printmenu.AppendItem(doprint)
615  self.Bind(wx.EVT_MENU, self.printopt.OnDoPrint, doprint)
616 
617  # Popup the menu. If an item is selected then its handler
618  # will be called before PopupMenu returns.
619  self.PopupMenu(printmenu)
620  printmenu.Destroy()
621 
622  def OnCloseWindow(self, event):
623  """!Window closed.
624  Also close associated layer tree page
625  """
626  pgnum = None
627  self.Map.Clean()
628 
629  # close edited map and 3D tools properly
630  if self.GetToolbar('vdigit'):
631  maplayer = self.toolbars['vdigit'].GetLayer()
632  if maplayer:
633  self.toolbars['vdigit'].OnExit()
634  if self.IsPaneShown('3d'):
635  self.RemoveNviz()
636 
637  if not self._layerManager:
638  self.Destroy()
639  elif self.page:
640  pgnum = self.layerbook.GetPageIndex(self.page)
641  if pgnum > -1:
642  self.layerbook.DeletePage(pgnum)
643 
644  def Query(self, x, y, layers):
645  """!Query selected layers.
646 
647  Calls QueryMap in case of raster or more vectors,
648  or QueryVector in case of one vector with db connection.
649 
650  @param x,y coordinates
651  @param layers selected tree item layers
652  """
653  num = 0
654  filteredLayers = []
655  for layer in layers:
656  ltype = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
657  if ltype in ('raster', 'rgb', 'his',
658  'vector', 'thememap', 'themechart'):
659  filteredLayers.append(layer)
660 
661  if not filteredLayers:
662  GMessage(parent = self,
663  message = _('No raster or vector map layer selected for querying.'))
664  return
665 
666  layers = filteredLayers
667  # set query snap distance for v.what at map unit equivalent of 10 pixels
668  qdist = 10.0 * ((self.Map.region['e'] - self.Map.region['w']) / self.Map.width)
669  east, north = self.MapWindow.Pixel2Cell((x, y))
670 
671  posWindow = self.ClientToScreen((x + self.MapWindow.dialogOffset,
672  y + self.MapWindow.dialogOffset))
673 
674  isRaster = False
675  nVectors = 0
676  isDbConnection = False
677  allLayersConnected = None
678  for l in layers:
679  maplayer = self.tree.GetPyData(l)[0]['maplayer']
680  if maplayer.GetType() == 'raster':
681  isRaster = True
682  break
683  if maplayer.GetType() == 'vector':
684  nVectors += 1
685  isDbConnection = grass.vector_db(maplayer.GetName())
686  if isDbConnection:
687  # check if all layers are connected to db
688  # otherwise show output in command console instead of poping up attribute dialog
689  # which is missing features from layers not connected to db
690  allLayersConnected = True
691  vLayersDb = sorted(isDbConnection.keys())
692  vLayersAll = sorted(map(int, GetAllVectorLayers(maplayer.GetName())))
693  if vLayersAll != vLayersDb:
694  allLayersConnected = False
695 
696  if not self.IsPaneShown('3d'):
697  if isRaster or nVectors > 1 or not allLayersConnected:
698  self.QueryMap(east, north, qdist, layers)
699  else:
700  self.QueryVector(east, north, qdist, posWindow, layers[0])
701  else:
702  if isRaster:
703  self.MapWindow.QuerySurface(x, y)
704  if nVectors > 1 or not isDbConnection:
705  self.QueryMap(east, north, qdist, layers)
706  elif nVectors == 1:
707  self.QueryVector(east, north, qdist, posWindow, layers[0])
708 
709  def QueryMap(self, east, north, qdist, layers):
710  """!Query raster or vector map layers by r/v.what
711 
712  @param east,north coordinates
713  @param qdist query distance
714  @param layers selected tree items
715  """
716  rast = list()
717  vect = list()
718  rcmd = ['r.what', '--v']
719  vcmd = ['v.what', '--v']
720 
721  for layer in layers:
722  ltype = self.tree.GetPyData(layer)[0]['maplayer'].GetType()
723  dcmd = self.tree.GetPyData(layer)[0]['cmd']
724  name, found = GetLayerNameFromCmd(dcmd)
725 
726  if not found:
727  continue
728  if ltype == 'raster':
729  rast.append(name)
730  elif ltype in ('rgb', 'his'):
731  for iname in name.split('\n'):
732  rast.append(iname)
733  elif ltype in ('vector', 'thememap', 'themechart'):
734  vect.append(name)
735 
736  # use display region settings instead of computation region settings
737  self.tmpreg = os.getenv("GRASS_REGION")
738  os.environ["GRASS_REGION"] = self.Map.SetRegion(windres = False)
739 
740  # build query commands for any selected rasters and vectors
741  if rast:
742  rcmd.append('-f')
743  rcmd.append('-n')
744  rcmd.append('input=%s' % ','.join(rast))
745  rcmd.append('east_north=%f,%f' % (float(east), float(north)))
746 
747  if vect:
748  # check for vector maps open to be edited
749  digitToolbar = self.GetToolbar('vdigit')
750  if digitToolbar:
751  lmap = digitToolbar.GetLayer().GetName()
752  for name in vect:
753  if lmap == name:
754  self._layerManager.goutput.WriteWarning(_("Vector map <%s> "
755  "opened for editing - skipped.") % map)
756  vect.remove(name)
757 
758  if len(vect) < 1:
759  self._layerManager.goutput.WriteCmdLog(_("Nothing to query."))
760  return
761 
762  vcmd.append('-a')
763  vcmd.append('map=%s' % ','.join(vect))
764  vcmd.append('east_north=%f,%f' % (float(east), float(north)))
765  vcmd.append('distance=%f' % float(qdist))
766 
767  Debug.msg(1, "QueryMap(): raster=%s vector=%s" % (','.join(rast),
768  ','.join(vect)))
769  # parse query command(s)
770 
771  if rast and not self.IsPaneShown('3d'):
772  self._layerManager.goutput.RunCmd(rcmd,
773  compReg = False,
774  onDone = self._QueryMapDone)
775  if vect:
776  self._layerManager.goutput.RunCmd(vcmd,
777  onDone = self._QueryMapDone)
778 
779  def _QueryMapDone(self, cmd, returncode):
780  """!Restore settings after querying (restore GRASS_REGION)
781 
782  @param returncode command return code
783  """
784  if hasattr(self, "tmpreg"):
785  if self.tmpreg:
786  os.environ["GRASS_REGION"] = self.tmpreg
787  elif 'GRASS_REGION' in os.environ:
788  del os.environ["GRASS_REGION"]
789  elif 'GRASS_REGION' in os.environ:
790  del os.environ["GRASS_REGION"]
791 
792  if hasattr(self, "tmpreg"):
793  del self.tmpreg
794 
795  def QueryVector(self, east, north, qdist, posWindow, layer):
796  """!Query vector map layer features
797 
798  Attribute data of selected vector object are displayed in GUI dialog.
799  Data can be modified (On Submit)
800  """
801  mapName = self.tree.GetPyData(layer)[0]['maplayer'].name
802 
803  if self.tree.GetPyData(layer)[0]['maplayer'].GetMapset() != \
804  grass.gisenv()['MAPSET']:
805  mode = 'display'
806  else:
807  mode = 'update'
808 
809  if self.dialogs['attributes'] is None:
810  dlg = DisplayAttributesDialog(parent = self.MapWindow,
811  map = mapName,
812  query = ((east, north), qdist),
813  pos = posWindow,
814  action = mode)
815  self.dialogs['attributes'] = dlg
816 
817  else:
818  # selection changed?
819  if not self.dialogs['attributes'].mapDBInfo or \
820  self.dialogs['attributes'].mapDBInfo.map != mapName:
821  self.dialogs['attributes'].UpdateDialog(map = mapName, query = ((east, north), qdist),
822  action = mode)
823  else:
824  self.dialogs['attributes'].UpdateDialog(query = ((east, north), qdist),
825  action = mode)
826  if not self.dialogs['attributes'].IsFound():
827  self._layerManager.goutput.WriteLog(_('Nothing found.'))
828 
829  cats = self.dialogs['attributes'].GetCats()
830 
831  qlayer = None
832  if not self.IsPaneShown('3d') and self.IsAutoRendered():
833  try:
834  qlayer = self.Map.GetListOfLayers(l_name = globalvar.QUERYLAYER)[0]
835  except IndexError:
836  pass
837 
838  if self.dialogs['attributes'].mapDBInfo and cats:
839  if not self.IsPaneShown('3d') and self.IsAutoRendered():
840  # highlight feature & re-draw map
841  if qlayer:
842  qlayer.SetCmd(self.AddTmpVectorMapLayer(mapName, cats,
843  useId = False,
844  addLayer = False))
845  else:
846  qlayer = self.AddTmpVectorMapLayer(mapName, cats, useId = False)
847 
848  # set opacity based on queried layer
849  opacity = self.tree.GetPyData(layer)[0]['maplayer'].GetOpacity(float = True)
850  qlayer.SetOpacity(opacity)
851 
852  self.MapWindow.UpdateMap(render = False, renderVector = False)
853  if not self.dialogs['attributes'].IsShown():
854  self.dialogs['attributes'].Show()
855  else:
856  if qlayer:
857  self.Map.DeleteLayer(qlayer)
858  self.MapWindow.UpdateMap(render = False, renderVector = False)
859  if self.dialogs['attributes'].IsShown():
860  self.dialogs['attributes'].Hide()
861 
862  def OnQuery(self, event):
863  """!Query tools menu"""
864  if self.GetMapToolbar():
865  self.toolbars['map'].OnTool(event)
866  action = self.toolbars['map'].GetAction()
867 
868  self.toolbars['map'].action['desc'] = 'queryMap'
869  self.MapWindow.mouse['use'] = "query"
870 
871  if not self.IsStandalone():
872  # switch to output console to show query results
873  self._layerManager.notebook.SetSelectionByName('output')
874 
875  self.MapWindow.mouse['box'] = "point"
876  self.MapWindow.zoomtype = 0
877 
878  # change the cursor
879  self.MapWindow.SetCursor(self.cursors["cross"])
880 
881  def AddTmpVectorMapLayer(self, name, cats, useId = False, addLayer = True):
882  """!Add temporal vector map layer to map composition
883 
884  @param name name of map layer
885  @param useId use feature id instead of category
886  """
887  # color settings from ATM
888  color = UserSettings.Get(group = 'atm', key = 'highlight', subkey = 'color')
889  colorStr = str(color[0]) + ":" + \
890  str(color[1]) + ":" + \
891  str(color[2])
892 
893  # icon used in vector display and its size
894  icon = ''
895  size = 0
896  vparam = self.tree.GetPyData(self.tree.layer_selected)[0]['cmd']
897  for p in vparam:
898  if '=' in p:
899  parg,pval = p.split('=', 1)
900  if parg == 'icon': icon = pval
901  elif parg == 'size': size = float(pval)
902 
903  pattern = ["d.vect",
904  "map=%s" % name,
905  "color=%s" % colorStr,
906  "fcolor=%s" % colorStr,
907  "width=%d" % UserSettings.Get(group = 'atm', key = 'highlight', subkey = 'width')]
908  if icon != '':
909  pattern.append('icon=%s' % icon)
910  if size > 0:
911  pattern.append('size=%i' % size)
912 
913  if useId:
914  cmd = pattern
915  cmd.append('-i')
916  cmd.append('cats=%s' % str(cats))
917  else:
918  cmd = []
919  for layer in cats.keys():
920  cmd.append(copy.copy(pattern))
921  lcats = cats[layer]
922  cmd[-1].append("layer=%d" % layer)
923  cmd[-1].append("cats=%s" % ListOfCatsToRange(lcats))
924 
925  if addLayer:
926  if useId:
927  return self.Map.AddLayer(type = 'vector', name = globalvar.QUERYLAYER, command = cmd,
928  l_active = True, l_hidden = True, l_opacity = 1.0)
929  else:
930  return self.Map.AddLayer(type = 'command', name = globalvar.QUERYLAYER, command = cmd,
931  l_active = True, l_hidden = True, l_opacity = 1.0)
932  else:
933  return cmd
934 
935  def OnMeasure(self, event):
936  """!Init measurement routine that calculates map distance
937  along transect drawn on map display
938  """
939  self.totaldist = 0.0 # total measured distance
940 
941  # switch Layer Manager to output console to show measure results
942  self._layerManager.notebook.SetSelectionByName('output')
943 
944  # change mouse to draw line for measurement
945  self.MapWindow.mouse['use'] = "measure"
946  self.MapWindow.mouse['box'] = "line"
947  self.MapWindow.zoomtype = 0
948  self.MapWindow.pen = wx.Pen(colour = 'red', width = 2, style = wx.SHORT_DASH)
949  self.MapWindow.polypen = wx.Pen(colour = 'green', width = 2, style = wx.SHORT_DASH)
950 
951  # change the cursor
952  self.MapWindow.SetCursor(self.cursors["pencil"])
953 
954  # initiating output
955  self._layerManager.goutput.WriteWarning(_('Click and drag with left mouse button '
956  'to measure.\n'
957  'Double click with left button to clear.'))
958 
959  if self.Map.projinfo['proj'] != 'xy':
960  units = self.Map.projinfo['units']
961  self._layerManager.goutput.WriteCmdLog(_('Measuring distance') + ' ('
962  + units + '):')
963  else:
964  self._layerManager.goutput.WriteCmdLog(_('Measuring distance:'))
965 
966  if self.Map.projinfo['proj'] == 'll':
967  try:
968  import grass.lib.gis as gislib
969  global haveCtypes
970  haveCtypes = True
971 
972  gislib.G_begin_distance_calculations()
973  except ImportError, e:
974  self._layerManager.goutput.WriteWarning(_('Geodesic distance is not yet '
975  'supported by this tool.\n'
976  'Reason: %s' % e))
977 
978  def MeasureDist(self, beginpt, endpt):
979  """!Calculate map distance from screen distance
980  and print to output window
981  """
982  self._layerManager.notebook.SetSelectionByName('output')
983 
984  dist, (north, east) = self.MapWindow.Distance(beginpt, endpt)
985 
986  dist = round(dist, 3)
987  d, dunits = self.FormatDist(dist)
988 
989  self.totaldist += dist
990  td, tdunits = self.FormatDist(self.totaldist)
991 
992  strdist = str(d)
993  strtotdist = str(td)
994 
995  if self.Map.projinfo['proj'] == 'xy' or 'degree' not in self.Map.projinfo['unit']:
996  angle = int(math.degrees(math.atan2(north,east)) + 0.5)
997  # uncomment below (or flip order of atan2(y,x) above) to use
998  # the mathematical theta convention (CCW from +x axis)
999  #angle = 90 - angle
1000  if angle < 0:
1001  angle = 360 + angle
1002 
1003  mstring = '%s = %s %s\n%s = %s %s\n%s = %d %s\n%s' \
1004  % (_('segment'), strdist, dunits,
1005  _('total distance'), strtotdist, tdunits,
1006  _('bearing'), angle, _('degrees (clockwise from grid-north)'),
1007  '-' * 60)
1008  else:
1009  mstring = '%s = %s %s\n%s = %s %s\n%s' \
1010  % (_('segment'), strdist, dunits,
1011  _('total distance'), strtotdist, tdunits,
1012  '-' * 60)
1013 
1014  self._layerManager.goutput.WriteLog(mstring)
1015 
1016  return dist
1017 
1018  def OnProfile(self, event):
1019  """!Launch profile tool
1020  """
1021  raster = []
1022  if self.tree.layer_selected and \
1023  self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
1024  raster.append(self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
1025 
1026  win = ProfileFrame(parent = self, rasterList = raster)
1027 
1028  win.CentreOnParent()
1029  win.Show()
1030  # Open raster select dialog to make sure that a raster (and
1031  # the desired raster) is selected to be profiled
1032  win.OnSelectRaster(None)
1033 
1034  def FormatDist(self, dist):
1035  """!Format length numbers and units in a nice way,
1036  as a function of length. From code by Hamish Bowman
1037  Grass Development Team 2006"""
1038 
1039  mapunits = self.Map.projinfo['units']
1040  if mapunits == 'metres':
1041  mapunits = 'meters'
1042  outunits = mapunits
1043  dist = float(dist)
1044  divisor = 1.0
1045 
1046  # figure out which units to use
1047  if mapunits == 'meters':
1048  if dist > 2500.0:
1049  outunits = 'km'
1050  divisor = 1000.0
1051  else: outunits = 'm'
1052  elif mapunits == 'feet':
1053  # nano-bug: we match any "feet", but US Survey feet is really
1054  # 5279.9894 per statute mile, or 10.6' per 1000 miles. As >1000
1055  # miles the tick markers are rounded to the nearest 10th of a
1056  # mile (528'), the difference in foot flavours is ignored.
1057  if dist > 5280.0:
1058  outunits = 'miles'
1059  divisor = 5280.0
1060  else:
1061  outunits = 'ft'
1062  elif 'degree' in mapunits and \
1063  not haveCtypes:
1064  if dist < 1:
1065  outunits = 'min'
1066  divisor = (1/60.0)
1067  else:
1068  outunits = 'deg'
1069  else:
1070  outunits = 'meters'
1071 
1072  # format numbers in a nice way
1073  if (dist/divisor) >= 2500.0:
1074  outdist = round(dist/divisor)
1075  elif (dist/divisor) >= 1000.0:
1076  outdist = round(dist/divisor,1)
1077  elif (dist/divisor) > 0.0:
1078  outdist = round(dist/divisor,int(math.ceil(3-math.log10(dist/divisor))))
1079  else:
1080  outdist = float(dist/divisor)
1081 
1082  return (outdist, outunits)
1083 
1084  def OnHistogram(self, event):
1085  """!Init histogram display canvas and tools
1086  """
1087  win = HistogramFrame(self)
1088 
1089  win.CentreOnParent()
1090  win.Show()
1091  win.Refresh()
1092  win.Update()
1093 
1094  def AddBarscale(self, cmd = None, showDialog = True):
1095  """!Handler for scale/arrow map decoration menu selection.
1096  """
1097  if cmd:
1098  self.barscale.cmd = cmd
1099 
1100  if not showDialog:
1101  self.barscale.Show()
1102  self.MapWindow.UpdateMap()
1103  return
1104 
1105  # Decoration overlay control dialog
1106  if self.dialogs['barscale']:
1107  if self.dialogs['barscale'].IsShown():
1108  self.dialogs['barscale'].SetFocus()
1109  else:
1110  self.dialogs['barscale'].Show()
1111  else:
1112  # If location is latlon, only display north arrow (scale won't work)
1113  # proj = self.Map.projinfo['proj']
1114  # if proj == 'll':
1115  # barcmd = 'd.barscale -n'
1116  # else:
1117  # barcmd = 'd.barscale'
1118 
1119  # decoration overlay control dialog
1120  self.dialogs['barscale'] = \
1121  DecorationDialog(parent = self, title = _('Scale and North arrow'),
1122  overlayController = self.barscale,
1123  ddstyle = DECOR_DIALOG_BARSCALE,
1124  size = (350, 200),
1125  style = wx.DEFAULT_DIALOG_STYLE | wx.CENTRE)
1126 
1127  self.dialogs['barscale'].CentreOnParent()
1128  ### dialog cannot be show as modal - in the result d.barscale is not selectable
1129  ### self.dialogs['barscale'].ShowModal()
1130  self.dialogs['barscale'].Show()
1131  self.MapWindow.mouse['use'] = 'pointer'
1132 
1133  def AddLegend(self, cmd = None, showDialog = True):
1134  """!Handler for legend map decoration menu selection.
1135  """
1136  if cmd:
1137  self.legend.cmd = cmd
1138  else:
1139  if self.tree.layer_selected and \
1140  self.tree.GetPyData(self.tree.layer_selected)[0]['type'] == 'raster':
1141  self.legend.cmd.append('map=%s' % self.tree.GetPyData(self.tree.layer_selected)[0]['maplayer'].name)
1142 
1143  if not showDialog:
1144  self.legend.Show()
1145  self.MapWindow.UpdateMap()
1146  return
1147 
1148  # Decoration overlay control dialog
1149  if self.dialogs['legend']:
1150  if self.dialogs['legend'].IsShown():
1151  self.dialogs['legend'].SetFocus()
1152  else:
1153  self.dialogs['legend'].Show()
1154  else:
1155  # Decoration overlay control dialog
1156  self.dialogs['legend'] = \
1157  DecorationDialog(parent = self, title = ('Legend'),
1158  overlayController = self.legend,
1159  ddstyle = DECOR_DIALOG_LEGEND,
1160  size = (350, 200),
1161  style = wx.DEFAULT_DIALOG_STYLE | wx.CENTRE)
1162 
1163  self.dialogs['legend'].CentreOnParent()
1164  ### dialog cannot be show as modal - in the result d.legend is not selectable
1165  ### self.dialogs['legend'].ShowModal()
1166  self.dialogs['legend'].Show()
1167  self.MapWindow.mouse['use'] = 'pointer'
1168 
1169  def OnAddText(self, event):
1170  """!Handler for text decoration menu selection.
1171  """
1172  if self.MapWindow.dragid > -1:
1173  id = self.MapWindow.dragid
1174  self.MapWindow.dragid = -1
1175  else:
1176  # index for overlay layer in render
1177  if len(self.MapWindow.textdict.keys()) > 0:
1178  id = max(self.MapWindow.textdict.keys()) + 1
1179  else:
1180  id = 101
1181 
1182  self.dialogs['text'] = TextLayerDialog(parent = self, ovlId = id,
1183  title = _('Add text layer'),
1184  size = (400, 200))
1185  self.dialogs['text'].CenterOnParent()
1186 
1187  # If OK button pressed in decoration control dialog
1188  if self.dialogs['text'].ShowModal() == wx.ID_OK:
1189  text = self.dialogs['text'].GetValues()['text']
1190  active = self.dialogs['text'].GetValues()['active']
1191 
1192  # delete object if it has no text or is not active
1193  if text == '' or active == False:
1194  try:
1195  self.MapWindow2D.pdc.ClearId(id)
1196  self.MapWindow2D.pdc.RemoveId(id)
1197  del self.MapWindow.textdict[id]
1198  if self.IsPaneShown('3d'):
1199  self.MapWindow3D.UpdateOverlays()
1200  self.MapWindow.UpdateMap()
1201  else:
1202  self.MapWindow2D.UpdateMap(render = False, renderVector = False)
1203  except:
1204  pass
1205  return
1206 
1207 
1208  self.MapWindow.textdict[id] = self.dialogs['text'].GetValues()
1209 
1210  if self.IsPaneShown('3d'):
1211  self.MapWindow3D.UpdateOverlays()
1212  self.MapWindow3D.UpdateMap()
1213  else:
1214  self.MapWindow2D.pdc.ClearId(id)
1215  self.MapWindow2D.pdc.SetId(id)
1216  self.MapWindow2D.UpdateMap(render = False, renderVector = False)
1217 
1218  self.MapWindow.mouse['use'] = 'pointer'
1219 
1220  def OnAddArrow(self, event):
1221  """!Handler for north arrow menu selection.
1222  Opens Appearance page of nviz notebook.
1223  """
1224 
1225  self._layerManager.nviz.SetPage('decoration')
1226  self.MapWindow3D.SetDrawArrow((70, 70))
1227 
1228  def GetOptData(self, dcmd, type, params, propwin):
1229  """!Callback method for decoration overlay command generated by
1230  dialog created in menuform.py
1231  """
1232  # Reset comand and rendering options in render.Map. Always render decoration.
1233  # Showing/hiding handled by PseudoDC
1234  self.Map.ChangeOverlay(ovltype = type, type = 'overlay', name = '', command = dcmd,
1235  l_active = True, l_render = False)
1236  self.params[type] = params
1237  self.propwin[type] = propwin
1238 
1239  def OnZoomToMap(self, event):
1240  """!Set display extents to match selected raster (including
1241  NULLs) or vector map.
1242  """
1243  self.MapWindow.ZoomToMap()
1244 
1245  def OnZoomToRaster(self, event):
1246  """!Set display extents to match selected raster map (ignore NULLs)
1247  """
1248  self.MapWindow.ZoomToMap(ignoreNulls = True)
1249 
1250  def OnZoomToSaved(self, event):
1251  """!Set display geometry to match extents in
1252  saved region file
1253  """
1254  self.MapWindow.ZoomToSaved()
1255 
1256  def OnDisplayToWind(self, event):
1257  """!Set computational region (WIND file) to match display
1258  extents
1259  """
1260  self.MapWindow.DisplayToWind()
1261 
1262  def SaveDisplayRegion(self, event):
1263  """!Save display extents to named region file.
1264  """
1265  self.MapWindow.SaveDisplayRegion()
1266 
1267  def OnZoomMenu(self, event):
1268  """!Popup Zoom menu
1269  """
1270  point = wx.GetMousePosition()
1271  zoommenu = wx.Menu()
1272  # Add items to the menu
1273 
1274  zoomwind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to computational region (set with g.region)'))
1275  zoommenu.AppendItem(zoomwind)
1276  self.Bind(wx.EVT_MENU, self.OnZoomToWind, zoomwind)
1277 
1278  zoomdefault = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to default region'))
1279  zoommenu.AppendItem(zoomdefault)
1280  self.Bind(wx.EVT_MENU, self.OnZoomToDefault, zoomdefault)
1281 
1282  zoomsaved = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to saved region'))
1283  zoommenu.AppendItem(zoomsaved)
1284  self.Bind(wx.EVT_MENU, self.OnZoomToSaved, zoomsaved)
1285 
1286  savewind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Set computational region from display extent'))
1287  zoommenu.AppendItem(savewind)
1288  self.Bind(wx.EVT_MENU, self.OnDisplayToWind, savewind)
1289 
1290  savezoom = wx.MenuItem(zoommenu, wx.ID_ANY, _('Save display geometry to named region'))
1291  zoommenu.AppendItem(savezoom)
1292  self.Bind(wx.EVT_MENU, self.SaveDisplayRegion, savezoom)
1293 
1294  # Popup the menu. If an item is selected then its handler
1295  # will be called before PopupMenu returns.
1296  self.PopupMenu(zoommenu)
1297  zoommenu.Destroy()
1298 
1299  def SetProperties(self, render = False, mode = 0, showCompExtent = False,
1300  constrainRes = False, projection = False, alignExtent = True):
1301  """!Set properies of map display window"""
1302  self.SetProperty('render', render)
1303  self.statusbarManager.SetMode(mode)
1304  self.StatusbarUpdate()
1305  self.SetProperty('region', showCompExtent)
1306  self.SetProperty('alignExtent', alignExtent)
1307  self.SetProperty('resolution', constrainRes)
1308  self.SetProperty('projection', projection)
1309 
1310  def IsStandalone(self):
1311  """!Check if Map display is standalone"""
1312  if self._layerManager:
1313  return False
1314 
1315  return True
1316 
1317  def GetLayerManager(self):
1318  """!Get reference to Layer Manager
1319 
1320  @return window reference
1321  @return None (if standalone)
1322  """
1323  return self._layerManager
1324 
1325  def GetMapToolbar(self):
1326  """!Returns toolbar with zooming tools"""
1327  return self.toolbars['map']
def SaveToFile(self, event)
Save map to image.
def OnDisplayToWind(self, event)
Set computational region (WIND file) to match display extents.
def OnFlyThrough(self, event)
Fly-through mode.
def SaveDisplayRegion(self, event)
Save display extents to named region file.
def OnFocus(self, event)
Change choicebook page to match display.
def PrintMenu(self, event)
def IsPaneShown(self, name)
Check if pane (toolbar, mapWindow ...) of given name is currently shown.
def OnProfile(self, event)
Launch profile tool.
def OnUpdateProgress(self, event)
Update progress bar info.
wxGUI command interface
def AddToolbar(self, name)
Add defined toolbar to the window.
def _addToolbarVDigit(self)
Add vector digitizer toolbar.
wxGUI debugging
def SetValue(self, value)
Definition: widgets.py:115
def OnAlignRegion(self, event)
def MeasureDist(self, beginpt, endpt)
Calculate map distance from screen distance and print to output window.
wxGUI vector digitizer
def GetImageHandlers(image)
Get list of supported image handlers.
def GetMapWindow(self)
def SetProperties
Set properies of map display window.
def RemoveNviz(self)
Restore 2D view.
#define max(x, y)
Definition: draw2.c:69
def OnZoomToMap(self, event)
Set display extents to match selected raster (including NULLs) or vector map.
def __init__(self, parent=None, title=_("GRASS GIS - Map display"), toolbars=["map"], tree=None, notebook=None, lmgr=None, page=None, Map=None, auimgr=None, name='MapWindow', kwargs)
Main map display window with toolbars, statusbar and BufferedWindow (map canvas)
def AddNviz(self)
Add 3D view mode window.
def AddLegend
Handler for legend map decoration menu selection.
Nviz (3D view) module.
Various dialogs used in wxGUI.
def _QueryMapDone(self, cmd, returncode)
Restore settings after querying (restore GRASS_REGION)
Print context and utility functions for printing contents of map display window.
Rendering map layers and overlays into map composition image.
def GetAllVectorLayers(vector)
Returns list of all vector layers as strings.
Definition: core/utils.py:332
Base classes for Map display window.
def OnCloseWindow(self, event)
Window closed.
def IsStandalone(self)
Check if Map display is standalone.
def RemoveQueryLayer(self)
Removes temporary map layers (queries)
def GetMapToolbar(self)
Returns toolbar with zooming tools.
def OnHistogram(self, event)
Init histogram display canvas and tools.
def GetLayerNameFromCmd
Get map name from GRASS command.
Definition: core/utils.py:73
Plotting histogram based on d.histogram.
def GetLayerManager(self)
Get reference to Layer Manager.
def QueryMap(self, east, north, qdist, layers)
Query raster or vector map layers by r/v.what.
DBM-related dialogs.
def AddTmpVectorMapLayer
Add temporal vector map layer to map composition.
def RemoveToolbar(self, name)
Removes defined toolbar from the window.
def FormatDist(self, dist)
Format length numbers and units in a nice way, as a function of length.
def OnZoomToRaster(self, event)
Set display extents to match selected raster map (ignore NULLs)
def OnMeasure(self, event)
Init measurement routine that calculates map distance along transect drawn on map display...
def OnAddArrow(self, event)
Handler for north arrow menu selection.
Main frame for map display window.
def ListOfCatsToRange(cats)
Convert list of category number to range(s)
Definition: core/utils.py:207
Misc utilities for wxGUI.
Profiling using PyPlot.
def OnPointer(self, event)
Pointer button clicked.
def OnAddText(self, event)
Handler for text decoration menu selection.
Map display canvas for wxGUI vector digitizer.
def QueryVector(self, east, north, qdist, posWindow, layer)
Query vector map layer features.
def AddBarscale
Handler for scale/arrow map decoration menu selection.
Map display canvas - buffered window.
wxGUI vector digitizer toolbars
def GetOptData(self, dcmd, type, params, propwin)
Callback method for decoration overlay command generated by dialog created in menuform.py.
def UpdateDialog(parent, event, eventId, task)
Definition: forms.py:293
#define round(x)
Definition: draw2.c:71
Default GUI settings.
def Query(self, x, y, layers)
Query selected layers.
def OnZoomMenu(self, event)
Popup Zoom menu.
def OnRotate(self, event)
Rotate 3D view.
tuple range
Definition: tools.py:1406
def OnZoomToSaved(self, event)
Set display geometry to match extents in saved region file.
def OnQuery(self, event)
Query tools menu.
Map display overlays - barscale and legend.
def OnZoomRegion(self, event)
GLWindow
Definition: nviz/main.py:34
def OnRender(self, event)
Re-render map composition (each map layer)
Map display frame - toolbars.