GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
nviz/mapwindow.py
Go to the documentation of this file.
1 """!
2 @package nviz.mapwindow
3 
4 @brief wxGUI 3D view mode (map canvas)
5 
6 This module implements 3D visualization mode for map display.
7 
8 List of classes:
9  - mapwindow::NvizThread
10  - mapwindow::GLWindow
11 
12 (C) 2008-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 Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
18 @author Anna Kratochvilova <kratochanna gmail.com> (Google SoC 2011)
19 """
20 
21 import os
22 import sys
23 import time
24 import copy
25 import math
26 import types
27 import tempfile
28 
29 from threading import Thread
30 
31 import wx
32 from wx.lib.newevent import NewEvent
33 from wx import glcanvas
34 from wx.glcanvas import WX_GL_DEPTH_SIZE
35 
36 import grass.script as grass
37 
38 from core.gcmd import GMessage, GException, GError
39 from core.debug import Debug
40 from gui_core.mapwindow import MapWindow
41 from gui_core.goutput import wxCmdOutput
42 from nviz.workspace import NvizSettings
43 from core.settings import UserSettings
44 from nviz.animation import Animation
45 from nviz import wxnviz
46 from core.globalvar import CheckWxVersion
47 
48 wxUpdateProperties, EVT_UPDATE_PROP = NewEvent()
49 wxUpdateView, EVT_UPDATE_VIEW = NewEvent()
50 wxUpdateLight, EVT_UPDATE_LIGHT = NewEvent()
51 wxUpdateCPlane, EVT_UPDATE_CPLANE = NewEvent()
52 
53 class NvizThread(Thread):
54  def __init__(self, log, progressbar, window):
55  Thread.__init__(self)
56  Debug.msg(5, "NvizThread.__init__():")
57  self.log = log
58  self.progressbar = progressbar
59  self.window = window
60 
61  self._display = None
62 
63  self.setDaemon(True)
64 
65  def run(self):
66  self._display = wxnviz.Nviz(self.log, self.progressbar)
67 
68  def GetDisplay(self):
69  """!Get display instance"""
70  return self._display
71 
72 class GLWindow(MapWindow, glcanvas.GLCanvas):
73  """!OpenGL canvas for Map Display Window"""
74  def __init__(self, parent, id = wx.ID_ANY,
75  Map = None, tree = None, lmgr = None):
76  self.parent = parent # MapFrame
77 
78  # for wxGTK we need to set WX_GL_DEPTH_SIZE to draw vectors correctly
79  # but we don't know the right value
80  # in wxpython 2.9, there is IsDisplaySupported
81  if CheckWxVersion(version=[2, 8, 11]) and \
82  sys.platform not in ('win32', 'darwin'):
83  depthBuffer = int(UserSettings.Get(group='display', key='nvizDepthBuffer', subkey='value'))
84  attribs=[WX_GL_DEPTH_SIZE, depthBuffer, 0]
85  glcanvas.GLCanvas.__init__(self, parent, id, attribList=attribs)
86  else:
87  glcanvas.GLCanvas.__init__(self, parent, id)
88 
89 
90  MapWindow.__init__(self, parent, id,
91  Map, tree, lmgr)
92  self.Hide()
93 
94  self.init = False
95  self.initView = False
96  self.context = None
97  if CheckWxVersion(version=[2, 9]):
98  self.context = glcanvas.GLContext(self)
99 
100  # render mode
101  self.render = { 'quick' : False,
102  # do not render vector lines in quick mode
103  'vlines' : False,
104  'vpoints' : False,
105  'overlays': False }
106  self.mouse = {
107  'use': 'pointer'
108  }
109  self.cursors = {
110  'default' : wx.StockCursor(wx.CURSOR_ARROW),
111  'cross' : wx.StockCursor(wx.CURSOR_CROSS),
112  }
113  # list of loaded map layers (layer tree items)
114  self.layers = list()
115  # list of constant surfaces
116  self.constants = list()
117  # id of base surface (when vector is loaded and no surface exist)
118  self.baseId = -1
119  # list of cutting planes
120  self.cplanes = list()
121  # list of query points
122  self.qpoints = list()
123  # list of past views
124  self.viewhistory = []
125  self.saveHistory = False
126  # offset for dialog (e.g. DisplayAttributesDialog)
127  self.dialogOffset = 5
128  # overlays
129  self.overlays = {}
130  self.imagelist = []
131  self.overlay = wx.Overlay()
132  #self.pdc = wx.PseudoDC()
133  self.textdict = {}
134  self.dragid = -1
135  self.hitradius = 5
136  # layer manager toolwindow
137  self.toolWin = None
138 
139  if self.lmgr:
140  self.log = self.lmgr.goutput
141  logerr = self.lmgr.goutput.GetLog(err = True)
142  logmsg = self.lmgr.goutput.GetLog()
143  else:
144  self.log = logmsg = sys.stdout
145  logerr = sys.stderr
146 
147  # create nviz instance - use display region instead of computational
148  os.environ['GRASS_REGION'] = self.Map.SetRegion(windres = True)
149 
150  self.nvizThread = NvizThread(logerr,
151  self.parent.GetProgressBar(),
152  logmsg)
153  self.nvizThread.start()
154  time.sleep(.1)
155  self._display = self.nvizThread.GetDisplay()
156 
157  # GRASS_REGION needed only for initialization
158  del os.environ['GRASS_REGION']
159 
160  self.img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
161 
162  # size of MapWindow, to avoid resizing if size is the same
163  self.size = (0, 0)
164 
165  # default values
167  self.view = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'view')) # copy
168  self.iview = UserSettings.Get(group = 'nviz', key = 'view', internal = True)
169  self.light = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'light')) # copy
170  self.decoration = self.nvizDefault.SetDecorDefaultProp(type = 'arrow')
171  self.decoration['scalebar'] = []
172  self.decoration['arrow']['size'] = self._getDecorationSize()
173  self.fly = self.InitFly()
174 
175  # timer for flythrough
176  self.timerFly = wx.Timer(self, id = wx.NewId())
177  # timer for animations
178  self.timerAnim = wx.Timer(self, id = wx.NewId())
179  self.animation = Animation(mapWindow = self, timer = self.timerAnim)
180 
181  self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
182  self.Bind(wx.EVT_SIZE, self.OnSize)
183  self.Bind(wx.EVT_PAINT, self.OnPaint)
184  self._bindMouseEvents()
185 
186  self.Bind(EVT_UPDATE_PROP, self.UpdateMapObjProperties)
187  self.Bind(EVT_UPDATE_VIEW, self.OnUpdateView)
188  self.Bind(EVT_UPDATE_LIGHT, self.UpdateLight)
189  self.Bind(EVT_UPDATE_CPLANE, self.OnUpdateCPlane)
190 
191  self.Bind(wx.EVT_TIMER, self.OnTimerAnim, self.timerAnim)
192  self.Bind(wx.EVT_TIMER, self.OnTimerFly, self.timerFly)
193  self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
194  self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
195 
196  self.Bind(wx.EVT_CLOSE, self.OnClose)
197 
198  if CheckWxVersion(version=[2, 8, 11]) and \
199  sys.platform not in ('win32', 'darwin'):
200  wx.CallLater(3000, self._warningDepthBuffer)
201 
202  # cplanes cannot be initialized now
203  wx.CallAfter(self.InitCPlanes)
204 
205  def _warningDepthBuffer(self):
206  if not self.initView:
207  message=_("Opening 3D view was not successful. "
208  "Please try to change the value of depth buffer "
209  "in GUI Settings dialog > tab Map Display > Advanced "
210  "and restart GUI.")
211  GMessage(message)
212 
213  def InitFly(self):
214  """!Initialize fly through dictionary"""
215  fly = {'interval' : 10, # interval for timerFly
216  'value': [0, 0, 0], # calculated values for navigation
217  'mode' : 0, # fly through mode (0, 1)
218  'exag' : { # sensitivity
219  'move' : UserSettings.Get(group = 'nviz', key = 'fly', subkey = ['exag', 'move']),
220  'turn' : UserSettings.Get(group = 'nviz', key = 'fly', subkey = ['exag', 'turn'])},
221  'exagMultiplier' : 3, # speed up by Shift
222  'flySpeed' : 4, # speed of flying
223  'mouseControl' : None, # if mouse or keys are used
224  'pos' : {'x' : 0, 'y' : 0}, # virtual mouse position when using arrows
225  'arrowStep' : 50, # step in pixels (when using arrows)
226  'flySpeedStep' : 2,
227  }
228 
229  return fly
230 
231  def OnTimerFly(self, event):
232  """!Fly event was emitted, move the scene"""
233  if self.mouse['use'] != 'fly':
234  return
235 
236  if self.fly['mouseControl']:
237  mx, my = self.ComputeMxMy(*self.mouse['tmp'])
238  else:
239  mx, my = self.ComputeMxMy(self.fly['pos']['x'], self.fly['pos']['y'])
240 
241  self.ComputeFlyValues(mx = mx, my = my)
242  self._display.FlyThrough(flyInfo = self.fly['value'], mode = self.fly['mode'],
243  exagInfo = self.fly['exag'])
244  self.ChangeInnerView()
245  self.render['quick'] = True
246  self.Refresh(False)
247 
248  def ComputeMxMy(self, x, y):
249  """!Compute values for flythrough navigation
250  (ComputeFlyValues should follow).
251 
252  Based on visualization/nviz/src/togl_flythrough.c.
253  @param x,y screen coordinates
254  """
255  sx, sy = self.GetClientSizeTuple()
256  dx = dy = 0.01
257 
258  mx = 2 * (float(x) / sx) - 1
259  my = 2 * (float(y) / sy) - 1
260 
261  if mx < - dx:
262  mx += dx
263  elif mx > dx:
264  mx -= dx
265  else:
266  mx = 0.0 # ?
267  if my < - dy:
268  my += dy
269  elif my > dy:
270  my -= dy
271  else:
272  my = 0.0
273 
274  mx = mx / (1.0 - dx)
275  my = my / (1.0 - dy)
276 
277  # Quadratic seems smoother
278  mx *= abs(mx)
279  my *= abs(my)
280 
281  return mx, my
282 
283  def ComputeFlyValues(self, mx, my):
284  """!Compute parameters for fly-through navigation
285 
286  @params mx,my results from ComputeMxMy method
287  """
288  self.fly['value'] = [0, 0, 0]
289 
290  if self.fly['mode'] == 0:
291  self.fly['value'][0] = self.fly['flySpeed'] * self.fly['interval'] / 1000. # forward */
292  self.fly['value'][1] = mx * 0.1 * self.fly['interval'] / 1000. # heading
293  self.fly['value'][2] = my * 0.1 * self.fly['interval'] / 1000. # pitch
294  else:
295  self.fly['value'][0] = mx * 100.0 * self.fly['interval'] /1000.
296  self.fly['value'][2] = - my * 100.0 * self.fly['interval'] /1000.
297 
298  def ChangeFlySpeed(self, increase):
299  """!Increase/decrease flight spped"""
300  if increase:
301  self.fly['flySpeed'] += self.fly['flySpeedStep']
302  else:
303  self.fly['flySpeed'] -= self.fly['flySpeedStep']
304 
305  def __del__(self):
306  """!Stop timers if running, unload data"""
307  self.StopTimer(self.timerAnim)
308  self.StopTimer(self.timerFly)
309  self.UnloadDataLayers(force = True)
310 
311  def StopTimer(self, timer):
312  """!Stop timer if running"""
313  if timer.IsRunning():
314  timer.Stop()
315 
316  def _bindMouseEvents(self):
317  self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseAction)
318  self.Bind(wx.EVT_MOTION, self.OnMotion)
319 
320  def InitCPlanes(self):
321  """!Initialize cutting planes list"""
322  for i in range(self._display.GetCPlanesCount()):
323  cplane = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'cplane'))
324  cplane['on'] = False
325  self.cplanes.append(cplane)
326 
327  def SetToolWin(self, toolWin):
328  """!Sets reference to nviz toolwindow in layer manager"""
329  self.toolWin = toolWin
330 
331  def GetToolWin(self):
332  """!Returns reference to nviz toolwindow in layer manager"""
333  return self.toolWin
334 
335  def OnClose(self, event):
336  self.StopTimer(self.timerAnim)
337  self.StopTimer(self.timerFly)
338  # cleanup when window actually closes (on quit) and not just is hidden
339  self.UnloadDataLayers(force = True)
340 
341  def OnEraseBackground(self, event):
342  pass # do nothing, to avoid flashing on MSW
343 
344  def OnSize(self, event):
345  size = self.GetClientSize()
346  if CheckWxVersion(version=[2, 9]):
347  context = self.context
348  else:
349  context = self.GetContext()
350  if self.size != size \
351  and context:
352  Debug.msg(3, "GLCanvas.OnSize(): w = %d, h = %d" % \
353  (size.width, size.height))
354  if CheckWxVersion(version=[2, 9]):
355  self.SetCurrent(self.context)
356  else:
357  self.SetCurrent()
358  self._display.ResizeWindow(size.width,
359  size.height)
360 
361  # reposition checkbox in statusbar
362  self.parent.StatusbarReposition()
363 
364  # update statusbar
365  self.parent.StatusbarUpdate()
366 
367  self.size = size
368 
369  event.Skip()
370 
371  def OnPaint(self, event):
372  Debug.msg(1, "GLCanvas.OnPaint()")
373 
374  self.render['overlays'] = True
375  dc = wx.PaintDC(self)
376  self.DoPaint()
377 
378 
379  def DoPaint(self):
380  if CheckWxVersion(version=[2, 9]):
381  self.SetCurrent(self.context)
382  else:
383  self.SetCurrent()
384 
385  if not self.initView:
386  self._display.InitView()
387  self.initView = True
388 
389  self.LoadDataLayers()
390  self.UnloadDataLayers()
391 
392  if not self.init:
393  self.ResetView()
394 
395  if hasattr(self.lmgr, "nviz"):
396  self.lmgr.nviz.UpdatePage('view')
397  self.lmgr.nviz.UpdatePage('light')
398  self.lmgr.nviz.UpdatePage('cplane')
399  self.lmgr.nviz.UpdatePage('decoration')
400  self.lmgr.nviz.UpdatePage('animation')
401  layer = self.GetSelectedLayer()
402  if layer:
403  if layer.type == 'raster':
404  self.lmgr.nviz.UpdatePage('surface')
405  self.lmgr.nviz.UpdatePage('fringe')
406  elif layer.type == 'vector':
407  self.lmgr.nviz.UpdatePage('vector')
408 
409  self.lmgr.nviz.UpdateSettings()
410 
411  # update widgets
412  win = self.lmgr.nviz.FindWindowById( \
413  self.lmgr.nviz.win['vector']['lines']['surface'])
414  win.SetItems(self.GetLayerNames('raster'))
415 
416  self.init = True
417 
418  self.UpdateMap()
419 
420  def DrawImages(self):
421  """!Draw overlay image"""
422  for texture in self.imagelist:
423  if texture.IsActive():
424  texture.Draw()
425 
426  def GetLegendRect(self):
427  """!Estimates legend size for dragging"""
428  size = None
429  if 1 in self.overlays:
430  for param in self.overlays[1]['cmd'][1:]:
431  if param.startswith("at="):
432  size = map(int, param.split("=")[-1].split(','))
433  break
434  if size:
435  wSize = self.GetClientSizeTuple()
436  x, y = size[2]/100. * wSize[0], wSize[1] - (size[1]/100. * wSize[1])
437  x += self.overlays[1]['coords'][0]
438  y += self.overlays[1]['coords'][1]
439  w = (size[3] - size[2])/100. * wSize[0]
440  h = (size[1] - size[0])/100. * wSize[1]
441 
442  rect = wx.Rect(x, y, w, h)
443  return rect
444 
445  return wx.Rect()
446 
447  def DrawTextImage(self, textDict, relCoords):
448  """!Draw overlay text"""
449  bmp = wx.EmptyBitmap(textDict['bbox'][2], textDict['bbox'][3])
450  memDC = wx.MemoryDC()
451  memDC.SelectObject(bmp)
452 
453  mask = self.view['background']['color']
454  if mask == textDict['color']:
455  mask = wx.WHITE
456  memDC.SetBackground(wx.Brush(mask))
457  memDC.Clear()
458  memDC.SetFont(textDict['font'])
459  memDC.SetTextForeground(textDict['color'])
460  if textDict['rotation'] == 0:
461  memDC.DrawText(textDict['text'], 0, 0)
462  else:
463  memDC.DrawRotatedText(textDict['text'], relCoords[0], relCoords[1],
464  textDict['rotation'])
465  bmp.SetMaskColour(mask)
466  memDC.DrawBitmap(bmp, 0, 0, 1)
467 
468  filename = tempfile.mktemp() + '.png'
469  bmp.SaveFile(filename, wx.BITMAP_TYPE_PNG)
470  memDC.SelectObject(wx.NullBitmap)
471 
472  return filename
473 
474  def UpdateOverlays(self):
475  """!Converts rendered overlay files and text labels to wx.Image
476  and then to textures so that they can be rendered by OpenGL.
477  Updates self.imagelist"""
478  self.Map.ChangeMapSize(self.GetClientSize())
479  self.Map.RenderOverlays(force = True)
480 
481  # delete textures
482  for texture in self.imagelist:
483  # inactive overlays, remove text labels
484  if texture.GetId() < 100:
485  if not self.overlays[texture.GetId()]['layer'].IsActive():
486  texture.SetActive(False)
487  else:
488  texture.SetActive(True)
489  else: # text label
490  if texture.GetId() not in self.textdict:
491  self.imagelist.remove(texture)
492 
493  # update images (only legend so far)
494  for oid, overlay in self.overlays.iteritems():
495  layer = overlay['layer']
496  if not layer.IsActive() or oid == 0: # 0 for barscale
497  continue
498  if oid not in [t.GetId() for t in self.imagelist]: # new
499  self.CreateTexture(overlay = layer)
500  else:
501  for t in self.imagelist:
502  if t.GetId() == oid: # check if it is the same
503  if not t.Corresponds(layer):
504  self.imagelist.remove(t)
505  t = self.CreateTexture(overlay = layer)
506  # always set coordinates, needed for synchr. 2D and 3D modes
507  t.SetCoords(overlay['coords'])
508 
509 
510  # update text labels
511  for textId in self.textdict.keys():
512  if textId not in [t.GetId() for t in self.imagelist]:# new
513  self.CreateTexture(textId = textId)
514  else:
515  for t in self.imagelist:
516  if t.GetId() == textId: # check if it is the same
517  self.textdict[textId]['bbox'] = t.textDict['bbox']
518  if not t.Corresponds(self.textdict[textId]):
519  self.imagelist.remove(t)
520  t = self.CreateTexture(textId = textId)
521  # always set coordinates, needed for synchr. 2D and 3D modes
522  t.SetCoords(self.textdict[textId]['coords'])
523 
524  def CreateTexture(self, overlay = None, textId = None):
525  """!Create texture from overlay image or from textdict"""
526  if overlay: # legend
527  texture = wxnviz.ImageTexture(filepath = overlay.mapfile, overlayId = overlay.id,
528  coords = list(self.overlays[overlay.id]['coords']),
529  cmd = overlay.GetCmd())
530  if overlay.id == 1: # legend
531  texture.SetBounds(self.GetLegendRect())
532  else: # text
533  coords, bbox, relCoords = self.TextBounds(self.textdict[textId])
534  self.textdict[textId]['coords'] = coords
535  self.textdict[textId]['bbox'] = bbox
536  file = self.DrawTextImage(self.textdict[textId], relCoords)
537  texture = wxnviz.TextTexture(filepath = file, overlayId = textId,
538  coords = coords, textDict = self.textdict[textId])
539  bbox.OffsetXY(*relCoords)
540  texture.SetBounds(bbox)
541 
542  if not texture.textureId: # texture too big
543  GMessage(parent = self, message =
544  _("Image is too large, your OpenGL implementation "
545  "supports maximum texture size %d px.") % texture.maxSize)
546  return texture
547 
548  self.imagelist.append(texture)
549 
550  return texture
551 
552  def FindObjects(self, mouseX, mouseY, radius):
553  """Find object which was clicked on"""
554  for texture in self.imagelist:
555  if texture.HitTest(mouseX, mouseY, radius):
556  return texture.id
557  return -1
558 
559  def OnTimerAnim(self, event):
560  self.animation.Update()
561 
562  def GetAnimation(self):
563  return self.animation
564 
565  def OnKeyDown(self, event):
566  """!Key was pressed.
567 
568  Used for fly-through mode.
569  """
570  if not self.mouse['use'] == 'fly':
571  return
572 
573  key = event.GetKeyCode()
574  if key == wx.WXK_CONTROL: # Mac ?
575  self.fly['mode'] = 1
576 
577  elif key == wx.WXK_SHIFT:
578  self.fly['exag']['move'] *= self.fly['exagMultiplier']
579  self.fly['exag']['turn'] *= self.fly['exagMultiplier']
580 
581  elif key == wx.WXK_ESCAPE and self.timerFly.IsRunning() and not self.fly['mouseControl']:
582  self.StopTimer(self.timerFly)
583  self.fly['mouseControl'] = None
584  self.render['quick'] = False
585  self.Refresh(False)
586 
587  elif key in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT):
588  if not self.fly['mouseControl']:
589  if not self.timerFly.IsRunning():
590  sx, sy = self.GetClientSizeTuple()
591  self.fly['pos']['x'] = sx / 2
592  self.fly['pos']['y'] = sy / 2
593  self.fly['mouseControl'] = False # controlled by keyboard
594  self.timerFly.Start(self.fly['interval'])
595 
596  self.ProcessFlyByArrows(keyCode = key)
597 
598  # change speed of flight when using mouse
599  else:
600  if key == wx.WXK_UP:
601  self.ChangeFlySpeed(increase = True)
602  elif key == wx.WXK_DOWN:
603  self.ChangeFlySpeed(increase = False)
604 
605  elif key in (wx.WXK_HOME, wx.WXK_PAGEUP) and self.timerFly.IsRunning():
606  self.ChangeFlySpeed(increase = True)
607  elif key in (wx.WXK_END, wx.WXK_PAGEDOWN) and self.timerFly.IsRunning():
608  self.ChangeFlySpeed(increase = False)
609 
610  event.Skip()
611 
612  def ProcessFlyByArrows(self, keyCode):
613  """!Process arrow key during fly-through"""
614  step = self.fly['arrowStep']
615  if keyCode == wx.WXK_UP:
616  self.fly['pos']['y'] -= step
617  elif keyCode == wx.WXK_DOWN:
618  self.fly['pos']['y'] += step
619  elif keyCode == wx.WXK_LEFT:
620  self.fly['pos']['x'] -= step
621  elif keyCode == wx.WXK_RIGHT:
622  self.fly['pos']['x'] += step
623 
624  def OnKeyUp(self, event):
625  """!Key was released.
626 
627  Used for fly-through mode.
628  """
629  if not self.mouse['use'] == 'fly':
630  return
631 
632  key = event.GetKeyCode()
633  if key == wx.WXK_CONTROL: # Mac ?
634  self.fly['mode'] = 0
635  elif key == wx.WXK_SHIFT:
636  self.fly['exag']['move'] = math.floor(self.fly['exag']['move'] / self.fly['exagMultiplier'])
637  self.fly['exag']['turn'] = math.floor(self.fly['exag']['turn'] / self.fly['exagMultiplier'])
638 
639  event.Skip()
640 
641  def OnMouseAction(self, event):
642  """!Handle mouse events"""
643  # zoom with mouse wheel
644  if event.GetWheelRotation() != 0:
645  self.OnMouseWheel(event)
646 
647  # left mouse button pressed
648  elif event.LeftDown():
649  self.OnLeftDown(event)
650 
651  # left mouse button released
652  elif event.LeftUp():
653  self.OnLeftUp(event)
654 
655  # dragging
656  elif event.Dragging():
657  self.OnDragging(event)
658 
659  # double click
660  elif event.ButtonDClick():
661  self.OnDClick(event)
662 
663  event.Skip()
664 
665  def OnMouseWheel(self, event):
666  """!Change perspective"""
667  if UserSettings.Get(group = 'display',
668  key = 'mouseWheelZoom',
669  subkey = 'selection') == 2:
670  event.Skip()
671  return
672 
673  wheel = event.GetWheelRotation()
674  Debug.msg (5, "GLWindow.OnMouseMotion(): wheel = %d" % wheel)
675  if self.timerFly.IsRunning() and self.fly['mouseControl']:
676  if wheel > 0:
677  self.ChangeFlySpeed(increase = True)
678  else:
679  self.ChangeFlySpeed(increase = False)
680  else:
681  if UserSettings.Get(group = 'display',
682  key = 'scrollDirection',
683  subkey = 'selection'):
684  wheel *= -1
685  self.DoZoom(zoomtype = wheel, pos = event.GetPositionTuple())
686 
687  # update statusbar
688  ### self.parent.StatusbarUpdate()
689 
690  def OnLeftDown(self, event):
691  """!On left mouse down"""
692  self.mouse['begin'] = event.GetPositionTuple()
693  self.mouse['tmp'] = event.GetPositionTuple()
694  if self.mouse['use'] == "lookHere":
695  size = self.GetClientSize()
696  self._display.LookHere(self.mouse['begin'][0], size[1] - self.mouse['begin'][1])
697  focus = self._display.GetFocus()
698  for i, coord in enumerate(('x', 'y', 'z')):
699  self.iview['focus'][coord] = focus[i]
700  self.saveHistory = True
701  self.Refresh(False)
702  toggle = self.lmgr.nviz.FindWindowByName('here')
703  toggle.SetValue(False)
704  self.mouse['use'] = 'pointer'
705  self.SetCursor(self.cursors['default'])
706 
707  if self.mouse['use'] == 'arrow':
708  pos = event.GetPosition()
709  size = self.GetClientSize()
710  self.SetDrawArrow((pos[0], size[1] - pos[1]))
711 
712  if self.mouse['use'] == 'scalebar':
713  pos = event.GetPosition()
714  size = self.GetClientSize()
715  self.SetDrawScalebar((pos[0], size[1] - pos[1]))
716 
717  if self.mouse['use'] == 'pointer':
718  # get decoration or text id
719  self.dragid = self.FindObjects(self.mouse['tmp'][0], self.mouse['tmp'][1],
720  self.hitradius)
721 
722  if self.mouse['use'] == 'fly':
723  if not self.timerFly.IsRunning():
724  self.timerFly.Start(self.fly['interval'])
725  self.fly['mouseControl'] = True
726 
727  event.Skip()
728 
729  def OnDragging(self, event):
730  if self.mouse['use'] == 'pointer':
731  if self.dragid > 0:
732 
733  self.DragItem(self.dragid, event)
734 
735  if self.mouse['use'] == 'rotate':
736  dx, dy = event.GetX() - self.mouse['tmp'][0], event.GetY() - self.mouse['tmp'][1]
737 
738  angle, x, y, z = self._display.GetRotationParameters(dx, dy)
739  self._display.Rotate(angle, x, y, z)
740 
741  self.render['quick'] = True
742  self.Refresh(False)
743 
744  if self.mouse['use'] == 'pan':
745  self.FocusPanning(event)
746 
747  self.mouse['tmp'] = event.GetPositionTuple()
748 
749  event.Skip()
750 
751  def Pixel2Cell(self, (x, y)):
752  """!Convert image coordinates to real word coordinates
753 
754  @param x, y image coordinates
755 
756  @return easting, northing
757  @return None on error
758  """
759  size = self.GetClientSize()
760  # UL -> LL
761  sid, x, y, z = self._display.GetPointOnSurface(x, size[1] - y)
762 
763  if not sid:
764  return None
765 
766  return (x, y)
767 
768  def DoZoom(self, zoomtype, pos):
769  """!Change perspective and focus"""
770 
771  prev_value = self.view['persp']['value']
772  if zoomtype > 0:
773  value = -1 * self.view['persp']['step']
774  else:
775  value = self.view['persp']['step']
776  self.view['persp']['value'] += value
777  if self.view['persp']['value'] < 1:
778  self.view['persp']['value'] = 1
779  elif self.view['persp']['value'] > 180:
780  self.view['persp']['value'] = 180
781 
782  if prev_value != self.view['persp']['value']:
783  if hasattr(self.lmgr, "nviz"):
784  self.lmgr.nviz.UpdateSettings()
785  x, y = pos[0], self.GetClientSize()[1] - pos[1]
786  result = self._display.GetPointOnSurface(x, y)
787  if result[0]:
788  self._display.LookHere(x, y)
789  focus = self._display.GetFocus()
790  for i, coord in enumerate(('x', 'y', 'z')):
791  self.iview['focus'][coord] = focus[i]
792  self._display.SetView(self.view['position']['x'], self.view['position']['y'],
793  self.iview['height']['value'],
794  self.view['persp']['value'],
795  self.view['twist']['value'])
796  self.saveHistory = True
797  # redraw map
798  self.DoPaint()
799 
800  def OnLeftUp(self, event):
801  self.mouse['end'] = event.GetPositionTuple()
802  if self.mouse["use"] == "query":
803  # querying
804  if self.parent.IsStandalone():
805  GMessage(parent = self.parent,
806  message = _("Querying is not implemented in standalone mode of Map Display"))
807  return
808 
809  layers = self.GetSelectedLayer(type = 'item', multi = True)
810 
811  self.parent.Query(self.mouse['begin'][0],self.mouse['begin'][1], layers)
812 
813  elif self.mouse["use"] in ('arrow', 'scalebar'):
814  self.lmgr.nviz.FindWindowById(
815  self.lmgr.nviz.win['decoration'][self.mouse["use"]]['place']).SetValue(False)
816  self.mouse['use'] = 'pointer'
817  self.SetCursor(self.cursors['default'])
818  elif self.mouse['use'] == 'pointer':
819  if self.dragid > 0:
820  dx = self.mouse['end'][0] - self.mouse['begin'][0]
821  dy = self.mouse['end'][1] - self.mouse['begin'][1]
822  if self.dragid < 99:
823  coords = self.overlays[self.dragid]['coords']
824  self.overlays[self.dragid]['coords'] = [coords[0] + dx, coords[1] + dy]
825  else: # text
826  coords = self.textdict[self.dragid]['coords']
827  self.textdict[self.dragid]['coords'] = [coords[0] + dx, coords[1] + dy]
828  self.dragid = -1
829  self.render['quick'] = False
830  self.Refresh(False)
831 
832  elif self.mouse['use'] == 'rotate':
833  self._display.UnsetRotation()
834  self.iview['rotation'] = self._display.GetRotationMatrix()
835  self.saveHistory = True
836  self.render['quick'] = False
837  self.Refresh(False)
838 
839  elif self.mouse['use'] == 'pan':
840  self.saveHistory = True
841  self.render['quick'] = False
842  self.Refresh(False)
843 
844  elif self.mouse['use'] == 'fly':
845  if self.fly['mouseControl']:
846  self.StopTimer(self.timerFly)
847  self.fly['mouseControl'] = None
848  #for key in self.iview['dir'].keys():
849  #self.iview[''][key] = -1
850  # this causes sudden change, but it should be there
851  #if hasattr(self.lmgr, "nviz"):
852  #self.lmgr.nviz.UpdateSettings()
853 
854  self.render['quick'] = False
855  self.Refresh(False)
856 
857  elif self.mouse['use'] == 'zoom':
858  self.DoZoom(zoomtype = self.zoomtype, pos = self.mouse['end'])
859  event.Skip()
860 
861  def OnDClick(self, event):
862  """!On mouse double click"""
863  if self.mouse['use'] != 'pointer': return
864  pos = event.GetPositionTuple()
865  self.dragid = self.FindObjects(pos[0], pos[1], self.hitradius)
866 
867  if self.dragid == 1:
868  self.parent.OnAddLegend(None)
869  elif self.dragid > 100:
870  self.parent.OnAddText(None)
871  else:
872  return
873 
874  def FocusPanning(self, event):
875  """!Simulation of panning using focus"""
876  size = self.GetClientSizeTuple()
877  id1, x1, y1, z1 = self._display.GetPointOnSurface(
878  self.mouse['tmp'][0], size[1] - self.mouse['tmp'][1])
879  id2, x2, y2, z2 = self._display.GetPointOnSurface(
880  event.GetX(), size[1] - event.GetY())
881  if id1 and id1 == id2:
882  dx, dy, dz = x2 - x1, y2 - y1, z2 - z1
883  focus = self.iview['focus']
884  focus['x'], focus['y'], focus['z'] = self._display.GetFocus()
885  focus['x'] -= dx
886  focus['y'] -= dy
887  focus['z'] -= dz
888 
889  #update properties
890  self.PostViewEvent()
891 
892  self.mouse['tmp'] = event.GetPositionTuple()
893  self.render['quick'] = True
894  self.Refresh(False)
895 
896  def HorizontalPanning(self, event):
897  """!Move all layers in horizontal (x, y) direction.
898  Currently not used.
899  """
900  size = self.GetClientSizeTuple()
901  id1, x1, y1, z1 = self._display.GetPointOnSurface(
902  self.mouse['tmp'][0], size[1] - self.mouse['tmp'][1])
903  id2, x2, y2, z2 = self._display.GetPointOnSurface(
904  event.GetX(), size[1] - event.GetY())
905 
906  if id1 and id1 == id2:
907  dx, dy = x2 - x1, y2 - y1
908  # find raster and volume
909  for item in self.layers:
910  mapLayer = self.tree.GetPyData(item)[0]['maplayer']
911 
912  data = self.tree.GetPyData(item)[0]['nviz']
913  if mapLayer.GetType() == 'raster':
914  data['surface']['position']['x'] += dx
915  data['surface']['position']['y'] += dy
916  data['surface']['position']['update'] = None
917 
918  #update properties
919  evt = wxUpdateProperties(data = data)
920  wx.PostEvent(self, evt)
921 
922  if event.CmdDown() and id1 == data['surface']['object']['id']:
923  break
924 
925  elif mapLayer.GetType() == '3d-raster':
926  if 'x' not in data['volume']['position']:
927  data['volume']['position']['x'] = 0
928  data['volume']['position']['y'] = 0
929  data['volume']['position']['z'] = 0
930  data['volume']['position']['x'] += dx
931  data['volume']['position']['y'] += dy
932  data['volume']['position']['update'] = None
933 
934  #update properties
935  evt = wxUpdateProperties(data = data)
936  wx.PostEvent(self, evt)
937 
938  self.mouse['tmp'] = event.GetPositionTuple()
939  self.render['quick'] = True
940  self.Refresh(False)
941 
942  def DragItem(self, id, event):
943  """!Drag an overlay decoration item
944  """
945  if not id: return
946  Debug.msg (5, "GLWindow.DragItem(): id=%d" % id)
947  x, y = self.mouse['tmp']
948  dx = event.GetX() - x
949  dy = event.GetY() - y
950  for texture in self.imagelist:
951  if texture.id == id:
952  texture.MoveTexture(dx, dy)
953 
954 
955  self.render['quick'] = True
956  self.Refresh(False)
957 
958  self.mouse['tmp'] = (event.GetX(), event.GetY())
959 
960  def ZoomBack(self):
961  """!Set previous view in history list
962  """
963  view = {}
964  if len(self.viewhistory) > 1:
965  self.viewhistory.pop()
966  view = copy.deepcopy(self.viewhistory[-1])
967 
968  # disable tool if stack is empty
969  if len(self.viewhistory) < 2: # disable tool
970  toolbar = self.parent.GetMapToolbar()
971  toolbar.Enable('zoomback', enable = False)
972 
973  # set view and update nviz view page
974  self.lmgr.nviz.UpdateState(view = view[0], iview = view[1])
975  self.lmgr.nviz.UpdatePage('view')
976  # update map
977  self.Refresh(False)
978 
979  def ViewHistory(self, view, iview):
980  """!Manages a list of last 10 views
981 
982  @param view view dictionary
983  @param iview view dictionary (internal)
984 
985  @return removed history item if exists (or None)
986  """
987  removed = None
988  hview = copy.deepcopy(view)
989  hiview = copy.deepcopy(iview)
990 
991  if not (self.viewhistory and self.viewhistory[-1] == (hview, hiview)):
992  self.viewhistory.append((hview, hiview))
993 
994  if len(self.viewhistory) > 10:
995  removed = self.viewhistory.pop(0)
996 
997  if removed:
998  Debug.msg(4, "GLWindow.ViewHistory(): hist=%s, removed=%s" %
999  (self.viewhistory, removed))
1000  else:
1001  Debug.msg(4, "GLWindow.ViewHistory(): hist=%s" %
1002  (self.viewhistory))
1003 
1004  # update toolbar
1005  if len(self.viewhistory) > 1:
1006  enable = True
1007  else:
1008  enable = False
1009 
1010  toolbar = self.parent.GetMapToolbar()
1011  toolbar.Enable('zoomback', enable)
1012 
1013  return removed
1014 
1015  def ResetViewHistory(self):
1016  """!Reset view history"""
1017  self.viewhistory = list()
1018 
1019  def GoTo(self, e, n):
1020  """!Focus on given point"""
1021  w = self.Map.region['w']
1022  s = self.Map.region['s']
1023  e -= w
1024  n -= s
1025  focus = self.iview['focus']
1026  focus['x'], focus['y'] = e, n
1027  self.saveHistory = True
1028  #update properties
1029  self.PostViewEvent()
1030 
1031  self.render['quick'] = False
1032  self.Refresh(False)
1033 
1034  def QuerySurface(self, x, y):
1035  """!Query surface on given position"""
1036  size = self.GetClientSizeTuple()
1037  result = self._display.QueryMap(x, size[1] - y)
1038  if result:
1039  self.qpoints.append((result['x'], result['y'], result['z']))
1040  self.log.WriteLog("%-30s: %.3f" % (_("Easting"), result['x']))
1041  self.log.WriteLog("%-30s: %.3f" % (_("Northing"), result['y']))
1042  self.log.WriteLog("%-30s: %.3f" % (_("Elevation"), result['z']))
1043  name = ''
1044  for item in self.layers:
1045  self.tree.GetPyData(item)[0]['nviz']
1046  if self.tree.GetPyData(item)[0]['maplayer'].type == 'raster' and\
1047  self.tree.GetPyData(item)[0]['nviz']['surface']['object']['id'] == result['id']:
1048  name = self.tree.GetPyData(item)[0]['maplayer'].name
1049  self.log.WriteLog("%-30s: %s" % (_("Surface map name"), name))
1050  self.log.WriteLog("%-30s: %s" % (_("Surface map elevation"), result['elevation']))
1051  self.log.WriteLog("%-30s: %s" % (_("Surface map color"), result['color']))
1052  if len(self.qpoints) > 1:
1053  prev = self.qpoints[-2]
1054  curr = self.qpoints[-1]
1055  dxy = math.sqrt(pow(prev[0]-curr[0], 2) +
1056  pow(prev[1]-curr[1], 2))
1057  dxyz = math.sqrt(pow(prev[0]-curr[0], 2) +
1058  pow(prev[1]-curr[1], 2) +
1059  pow(prev[2]-curr[2], 2))
1060  self.log.WriteLog("%-30s: %.3f" % (_("XY distance from previous"), dxy))
1061  self.log.WriteLog("%-30s: %.3f" % (_("XYZ distance from previous"), dxyz))
1062  self.log.WriteLog("%-30s: %.3f" % (_("Distance along surface"),
1063  self._display.GetDistanceAlongSurface(result['id'],
1064  (curr[0], curr[1]),
1065  (prev[0], prev[1]),
1066  useExag = False)))
1067  self.log.WriteLog("%-30s: %.3f" % (_("Distance along exag. surface"),
1068  self._display.GetDistanceAlongSurface(result['id'],
1069  (curr[0], curr[1]),
1070  (prev[0], prev[1]),
1071  useExag = True)))
1072  self.log.WriteCmdLog('-' * 80)
1073  else:
1074  self.log.WriteLog(_("No point on surface"))
1075  self.log.WriteCmdLog('-' * 80)
1076 
1077  def PostViewEvent(self, zExag = False):
1078  """!Change view settings"""
1079  event = wxUpdateView(zExag = zExag)
1080  wx.PostEvent(self, event)
1081 
1082  def OnQueryVector(self, event):
1083  """!Query vector on given position"""
1084  self.parent.QueryVector(*event.GetPosition())
1085 
1086  def ChangeInnerView(self):
1087  """!Get current viewdir and viewpoint and set view"""
1088  view = self.view
1089  iview = self.iview
1090  (view['position']['x'], view['position']['y'],
1091  iview['height']['value']) = self._display.GetViewpointPosition()
1092  for key, val in zip(('x', 'y', 'z'), self._display.GetViewdir()):
1093  iview['dir'][key] = val
1094 
1095  iview['dir']['use'] = True
1096 
1097  def OnUpdateView(self, event):
1098  """!Change view settings"""
1099  if event:
1100  self.UpdateView(zexag = event.zExag)
1101 
1102  self.saveHistory = True
1103  if event:
1104  event.Skip()
1105 
1106 
1107  def UpdateView(self, zexag = False):
1108  """!Change view settings"""
1109  view = self.view
1110  iview = self.iview
1111  if zexag and 'value' in view['z-exag']:
1112  self._display.SetZExag(view['z-exag']['value'] / iview['z-exag']['llRatio'])
1113 
1114  self._display.SetView(view['position']['x'], view['position']['y'],
1115  iview['height']['value'],
1116  view['persp']['value'],
1117  view['twist']['value'])
1118 
1119  if iview['dir']['use']:
1120  self._display.SetViewdir(iview['dir']['x'], iview['dir']['y'], iview['dir']['z'])
1121 
1122  elif iview['focus']['x'] != -1:
1123  self._display.SetFocus(self.iview['focus']['x'], self.iview['focus']['y'],
1124  self.iview['focus']['z'])
1125 
1126  if 'rotation' in iview:
1127  if iview['rotation']:
1128  self._display.SetRotationMatrix(iview['rotation'])
1129  else:
1130  self._display.ResetRotation()
1131 
1132  def UpdateLight(self, event):
1133  """!Change light settings"""
1134  data = self.light
1135  self._display.SetLight(x = data['position']['x'], y = data['position']['y'],
1136  z = data['position']['z'] / 100., color = data['color'],
1137  bright = data['bright'] / 100.,
1138  ambient = data['ambient'] / 100.)
1139  self._display.DrawLightingModel()
1140  if event.refresh:
1141  self.Refresh(False)
1142 
1143  def UpdateMap(self, render = True):
1144  """!Updates the canvas anytime there is a change to the
1145  underlaying images or to the geometry of the canvas.
1146 
1147  @param render re-render map composition
1148  """
1149  start = time.clock()
1150 
1151  self.resize = False
1152 
1153  if self.render['quick'] is False:
1154  self.parent.GetProgressBar().Show()
1155  self.parent.GetProgressBar().SetRange(2)
1156  self.parent.GetProgressBar().SetValue(0)
1157 
1158  if self.render['quick'] is False:
1159  self.parent.GetProgressBar().SetValue(1)
1160  self._display.Draw(False, -1)
1161  if self.saveHistory:
1162  self.ViewHistory(view = self.view, iview = self.iview)
1163  self.saveHistory = False
1164  elif self.render['quick'] is True:
1165  # quick
1166  mode = wxnviz.DRAW_QUICK_SURFACE | wxnviz.DRAW_QUICK_VOLUME
1167  if self.render['vlines']:
1168  mode |= wxnviz.DRAW_QUICK_VLINES
1169  if self.render['vpoints']:
1170  mode |= wxnviz.DRAW_QUICK_VPOINTS
1171  self._display.Draw(True, mode)
1172  else: # None -> reuse last rendered image
1173  pass # TODO
1174 
1175  self.SwapBuffers()
1176  # draw fringe after SwapBuffers, otherwise it don't have to be visible
1177  # on some computers
1178  if self.render['quick'] is False:
1179  self._display.DrawFringe()
1180  if self.decoration['arrow']['show']:
1181  self._display.DrawArrow()
1182  if self.decoration['scalebar']:
1183  self._display.DrawScalebar()
1184  if self.imagelist:
1185  if ((self.render['quick'] and self.dragid > -1) or # during dragging
1186  (not self.render['quick'] and self.dragid < 0)): # redraw
1187  self._display.Start2D()
1188  self.DrawImages()
1189 
1190 
1191 
1192  stop = time.clock()
1193 
1194  if self.render['quick'] is False:
1195  self.parent.GetProgressBar().SetValue(2)
1196  # hide process bar
1197  self.parent.GetProgressBar().Hide()
1198 
1199  Debug.msg(3, "GLWindow.UpdateMap(): quick = %d, -> time = %g" % \
1200  (self.render['quick'], (stop-start)))
1201 
1202  def EraseMap(self):
1203  """!Erase the canvas
1204  """
1205  self._display.EraseMap()
1206  self.SwapBuffers()
1207 
1208  def _getDecorationSize(self):
1209  """!Get initial size of north arrow/scalebar"""
1210  size = self._display.GetLongDim() / 8.
1211  coef = 0.01
1212  if size < 1:
1213  coef = 100.
1214  return int(size * coef)/coef
1215 
1216  def SetDrawArrow(self, pos):
1217 
1218  if self._display.SetArrow(pos[0], pos[1],
1219  self.decoration['arrow']['size'],
1220  self.decoration['arrow']['color']):
1221  self._display.DrawArrow()
1222  # update
1223  self.decoration['arrow']['show'] = True
1224  self.decoration['arrow']['position']['x'] = pos[0]
1225  self.decoration['arrow']['position']['y'] = pos[1]
1226  self.Refresh(False)
1227 
1228  def SetDrawScalebar(self, pos):
1229  """!Add scale bar, sets properties and draw"""
1230  if len(self.decoration['scalebar']) == 0:
1231  self.decoration['scalebar'].append(
1232  self.nvizDefault.SetDecorDefaultProp(type = 'scalebar')['scalebar'])
1233  self.decoration['scalebar'][0]['size'] = self._getDecorationSize()
1234  else:
1235  self.decoration['scalebar'].append(copy.deepcopy(self.decoration['scalebar'][-1]))
1236  self.decoration['scalebar'][-1]['id'] += 1
1237 
1238  ret = self._display.SetScalebar(self.decoration['scalebar'][-1]['id'], pos[0], pos[1],
1239  self.decoration['scalebar'][-1]['size'],
1240  self.decoration['scalebar'][-1]['color'])
1241  if ret:
1242  self._display.DrawScalebar()
1243  # update
1244  self.decoration['scalebar'][-1]['position']['x'] = pos[0]
1245  self.decoration['scalebar'][-1]['position']['y'] = pos[1]
1246  self.Refresh(False)
1247 
1248  def IsLoaded(self, item):
1249  """!Check if layer (item) is already loaded
1250 
1251  @param item layer item
1252  """
1253  layer = self.tree.GetPyData(item)[0]['maplayer']
1254  data = self.tree.GetPyData(item)[0]['nviz']
1255 
1256  if not data:
1257  return 0
1258 
1259  if layer.type == 'raster':
1260  if 'object' not in data['surface']:
1261  return 0
1262  elif layer.type == 'vector':
1263  if 'object' not in data['vlines'] and \
1264  'object' not in data['points']:
1265  return 0
1266 
1267  return 1
1268 
1269  def _GetDataLayers(self, item, litems):
1270  """!Return get list of enabled map layers"""
1271  # load raster & vector maps
1272  while item and item.IsOk():
1273  type = self.tree.GetPyData(item)[0]['type']
1274  if type == 'group':
1275  subItem = self.tree.GetFirstChild(item)[0]
1276  self._GetDataLayers(subItem, litems)
1277  item = self.tree.GetNextSibling(item)
1278 
1279  if not item.IsChecked() or \
1280  type not in ('raster', 'vector', '3d-raster'):
1281  item = self.tree.GetNextSibling(item)
1282  continue
1283 
1284  litems.append(item)
1285 
1286  item = self.tree.GetNextSibling(item)
1287 
1288  def LoadDataLayers(self):
1289  """!Load raster/vector from current layer tree
1290 
1291  @todo volumes
1292  """
1293  if not self.tree:
1294  return
1295 
1296  listOfItems = []
1297  item = self.tree.GetFirstChild(self.tree.root)[0]
1298  self._GetDataLayers(item, listOfItems)
1299 
1300  start = time.time()
1301 
1302  while(len(listOfItems) > 0):
1303  item = listOfItems.pop()
1304  type = self.tree.GetPyData(item)[0]['type']
1305  if item in self.layers:
1306  continue
1307  # "raster (double click to set properties)" - tries to load this
1308  # layer - no idea how to fix it
1309  if ' ' in self.tree.GetPyData(item)[0]['maplayer'].name:
1310  return
1311  try:
1312  if type == 'raster':
1313  self.LoadRaster(item)
1314  elif type == '3d-raster':
1315  self.LoadRaster3d(item)
1316  elif type == 'vector':
1317  layer = self.tree.GetPyData(item)[0]['maplayer']
1318  vInfo = grass.vector_info_topo(layer.GetName())
1319  if (vInfo['points']) > 0:
1320  # include vInfo['centroids'] to initially load centroids
1321  self.LoadVector(item, points = True)
1322  if (vInfo['lines'] + vInfo['boundaries']) > 0:
1323  self.LoadVector(item, points = False)
1324  if vInfo['map3d'] and (vInfo['kernels'] + vInfo['faces']) > 0:
1325  self.LoadVector(item, points=None)
1326 
1327  except GException, e:
1328  GError(parent = self,
1329  message = e.value)
1330 
1331  stop = time.time()
1332 
1333  Debug.msg(1, "GLWindow.LoadDataLayers(): time = %f" % (stop-start))
1334 
1335  def UnloadDataLayers(self, force = False):
1336  """!Unload any layers that have been deleted from layer tree
1337 
1338  @param force True to unload all data layers
1339  """
1340  if not self.tree:
1341  return
1342 
1343  listOfItems = []
1344  if not force:
1345  item = self.tree.GetFirstChild(self.tree.root)[0]
1346  self._GetDataLayers(item, listOfItems)
1347 
1348  start = time.time()
1349 
1350  update = False
1351  layersTmp = self.layers[:]
1352  for layer in layersTmp:
1353  if layer in listOfItems:
1354  continue
1355  ltype = self.tree.GetPyData(layer)[0]['type']
1356  try:
1357  if ltype == 'raster':
1358  self.UnloadRaster(layer)
1359  elif ltype == '3d-raster':
1360  self.UnloadRaster3d(layer)
1361  elif ltype == 'vector':
1362  maplayer = self.tree.GetPyData(layer)[0]['maplayer']
1363  vInfo = grass.vector_info_topo(maplayer.GetName())
1364  if (vInfo['points'] + vInfo['centroids']) > 0:
1365  self.UnloadVector(layer, points = True)
1366  if (vInfo['lines'] + vInfo['boundaries']) > 0 or vInfo['map3d']:
1367  self.UnloadVector(layer, points = False)
1368 
1369  except GException, e:
1370  GError(parent = self,
1371  message = e.value)
1372 
1373  if force and self.baseId > 0: # unload base surface when quitting
1374  ret = self._display.UnloadSurface(self.baseId)
1375  self.baseId = -1
1376  if update:
1377  self.lmgr.nviz.UpdateSettings()
1378  self.UpdateView(None)
1379 
1380  stop = time.time()
1381 
1382  Debug.msg(1, "GLWindow.UnloadDataLayers(): time = %f" % (stop-start))
1383 
1384  def SetVectorSurface(self, data):
1385  """!Set reference surfaces of vector"""
1386  data['mode']['surface'] = {}
1387  data['mode']['surface']['value'] = list()
1388  data['mode']['surface']['show'] = list()
1389  for name in self.GetLayerNames('raster'):
1390  data['mode']['surface']['value'].append(name)
1391  data['mode']['surface']['show'].append(True)
1392 
1393  def SetVectorFromCmd(self, item, data):
1394  """!Set 3D view properties from cmd (d.vect)
1395 
1396  @param item Layer Tree item
1397  @param nviz data
1398  """
1399  cmd = self.tree.GetPyData(item)[0]['cmd']
1400  if cmd[0] != 'd.vect':
1401  return
1402  for opt in cmd[1:]:
1403  try:
1404  key, value = opt.split('=')
1405  except ValueError:
1406  continue
1407  if key == 'color':
1408  data['lines']['color']['value'] = value
1409  data['points']['color']['value'] = value
1410 
1411  def SetMapObjProperties(self, item, id, nvizType):
1412  """!Set map object properties
1413 
1414  Properties must be afterwards updated by
1415  UpdateMapObjProperties().
1416 
1417  @param item layer item
1418  @param id nviz layer id (or -1)
1419  @param nvizType nviz data type (surface, points, vector)
1420  """
1421  if nvizType != 'constant':
1422  mapType = self.tree.GetPyData(item)[0]['maplayer'].type
1423  # reference to original layer properties (can be None)
1424  data = self.tree.GetPyData(item)[0]['nviz']
1425  else:
1426  mapType = nvizType
1427  data = self.constants[item]
1428 
1429  if not data:
1430  # init data structure
1431  if nvizType != 'constant':
1432  self.tree.GetPyData(item)[0]['nviz'] = {}
1433  data = self.tree.GetPyData(item)[0]['nviz']
1434 
1435  if mapType == 'raster':
1436  # reset to default properties
1437  data[nvizType] = self.nvizDefault.SetSurfaceDefaultProp()
1438 
1439  elif mapType == 'vector':
1440  # reset to default properties (lines/points)
1441  data['vector'] = self.nvizDefault.SetVectorDefaultProp()
1442  self.SetVectorFromCmd(item, data['vector'])
1443  self.SetVectorSurface(data['vector']['points'])
1444  self.SetVectorSurface(data['vector']['lines'])
1445 
1446  elif mapType == '3d-raster':
1447  # reset to default properties
1448  data[nvizType] = self.nvizDefault.SetVolumeDefaultProp()
1449 
1450  elif mapType == 'constant':
1451  data['constant'] = self.nvizDefault.SetConstantDefaultProp()
1452 
1453  else:
1454  # complete data (use default values), not sure if this is necessary
1455  if mapType == 'raster':
1456  if not data['surface']:
1457  data['surface'] = self.nvizDefault.SetSurfaceDefaultProp()
1458  if mapType == 'vector':
1459  if not data['vector']['lines']:
1460  self.nvizDefault.SetVectorLinesDefaultProp(data['vector']['lines'])
1461  if not data['vector']['points']:
1462  self.nvizDefault.SetVectorPointsDefaultProp(data['vector']['points'])
1463  # set updates
1464  for sec in data.keys():
1465  for sec1 in data[sec].keys():
1466  if sec1 == 'position':
1467  data[sec][sec1]['update'] = None
1468  continue
1469  if type(data[sec][sec1]) == types.DictType:
1470  for sec2 in data[sec][sec1].keys():
1471  if sec2 not in ('all', 'init', 'id'):
1472  data[sec][sec1][sec2]['update'] = None
1473  elif type(data[sec][sec1]) == types.ListType:
1474  for i in range(len(data[sec][sec1])):
1475  for sec2 in data[sec][sec1][i].keys():
1476  data[sec][sec1][i][sec2]['update'] = None
1477  event = wxUpdateProperties(data = data)
1478  wx.PostEvent(self, event)
1479 
1480  # set id
1481  if id > 0:
1482  if mapType in ('raster', '3d-raster'):
1483  data[nvizType]['object'] = { 'id' : id,
1484  'init' : False }
1485  elif mapType == 'vector':
1486  data['vector'][nvizType]['object'] = { 'id' : id,
1487  'init' : False }
1488  elif mapType == 'constant':
1489  data[nvizType]['object'] = { 'id' : id,
1490  'init' : False }
1491 
1492  return data
1493 
1494  def LoadRaster(self, item):
1495  """!Load 2d raster map and set surface attributes
1496 
1497  @param layer item
1498  """
1499  return self._loadRaster(item)
1500 
1501  def LoadRaster3d(self, item):
1502  """!Load 3d raster map and set surface attributes
1503 
1504  @param layer item
1505  """
1506  return self._loadRaster(item)
1507 
1508  def _loadRaster(self, item):
1509  """!Load 2d/3d raster map and set its attributes
1510 
1511  @param layer item
1512  """
1513  layer = self.tree.GetPyData(item)[0]['maplayer']
1514 
1515  if layer.type not in ('raster', '3d-raster'):
1516  return
1517 
1518  if layer.type == 'raster':
1519  id = self._display.LoadSurface(str(layer.name), None, None)
1520  nvizType = 'surface'
1521  errorMsg = _("Loading raster map")
1522  elif layer.type == '3d-raster':
1523  id = self._display.LoadVolume(str(layer.name), None, None)
1524  nvizType = 'volume'
1525  errorMsg = _("Loading 3d raster map")
1526  else:
1527  id = -1
1528 
1529  if id < 0:
1530  if layer.type in ('raster', '3d-raster'):
1531  self.log.WriteError("%s <%s> %s" % (errorMsg, layer.name, _("failed")))
1532  else:
1533  self.log.WriteError(_("Unsupported layer type '%s'") % layer.type)
1534 
1535  self.layers.append(item)
1536 
1537  # set default/workspace layer properties
1538  data = self.SetMapObjProperties(item, id, nvizType)
1539 
1540  # update properties
1541  event = wxUpdateProperties(data = data)
1542  wx.PostEvent(self, event)
1543 
1544  # update tools window
1545  if hasattr(self.lmgr, "nviz") and \
1546  item == self.GetSelectedLayer(type = 'item'):
1547  toolWin = self.lmgr.nviz
1548  if layer.type == 'raster':
1549  win = toolWin.FindWindowById( \
1550  toolWin.win['vector']['lines']['surface'])
1551  win.SetItems(self.GetLayerNames(layer.type))
1552 
1553  #toolWin.UpdatePage(nvizType)
1554  #toolWin.SetPage(nvizType)
1555 
1556  return id
1557 
1558  def NewConstant(self):
1559  """!Create new constant"""
1560  index = len(self.constants)
1561  try:
1562  name = self.constants[-1]['constant']['object']['name'] + 1
1563  except IndexError:
1564  name = 1
1565  data = dict()
1566  self.constants.append(data)
1567  data = self.SetMapObjProperties(item = index, id = -1, nvizType = 'constant')
1568  self.AddConstant(data, name)
1569  return name
1570 
1571  def AddConstant(self, data, name):
1572  """!Add new constant"""
1573  id = self._display.AddConstant(value = data['constant']['value'], color = data['constant']['color'])
1574  self._display.SetSurfaceRes(id, data['constant']['resolution'], data['constant']['resolution'])
1575  data['constant']['object'] = { 'id' : id,
1576  'name': name,
1577  'init' : False }
1578 
1579  def DeleteConstant(self, index):
1580  """!Delete constant layer"""
1581  id = self.constants[index]['constant']['object']['id']
1582  self._display.UnloadSurface(id)
1583  del self.constants[index]
1584 
1585  def SelectCPlane(self, index):
1586  """!Select cutting plane"""
1587  for plane in range (self._display.GetCPlanesCount()):
1588  if plane == index:
1589  self._display.SelectCPlane(plane)
1590  self.cplanes[plane]['on'] = True
1591  self._display.SetFenceColor(self.cplanes[plane]['shading'])
1592  else:
1593  self._display.UnselectCPlane(plane)
1594  try:
1595  self.cplanes[plane]['on'] = False
1596  except IndexError:
1597  pass
1598 
1599  def OnUpdateCPlane(self, event):
1600  """!Change cutting plane settings"""
1601  self.UpdateCPlane(event.current, event.update)
1602 
1603  def UpdateCPlane(self, index, changes):
1604  """!Change cutting plane settings"""
1605  for each in changes:
1606  if each == 'rotation':
1607  self._display.SetCPlaneRotation(0, self.cplanes[index]['rotation']['tilt'],
1608  self.cplanes[index]['rotation']['rot'])
1609  if each == 'position':
1610  self._display.SetCPlaneTranslation(self.cplanes[index]['position']['x'],
1611  self.cplanes[index]['position']['y'],
1612  self.cplanes[index]['position']['z'])
1613  if each == 'shading':
1614  self._display.SetFenceColor(self.cplanes[index]['shading'])
1615 
1616  def UnloadRaster(self, item):
1617  """!Unload 2d raster map
1618 
1619  @param layer item
1620  """
1621  return self._unloadRaster(item)
1622 
1623  def UnloadRaster3d(self, item):
1624  """!Unload 3d raster map
1625 
1626  @param layer item
1627  """
1628  return self._unloadRaster(item)
1629 
1630  def _unloadRaster(self, item):
1631  """!Unload 2d/3d raster map
1632 
1633  @param item layer item
1634  """
1635  layer = self.tree.GetPyData(item)[0]['maplayer']
1636 
1637  if layer.type not in ('raster', '3d-raster'):
1638  return
1639 
1640  data = self.tree.GetPyData(item)[0]['nviz']
1641 
1642  if layer.type == 'raster':
1643  nvizType = 'surface'
1644  unloadFn = self._display.UnloadSurface
1645  errorMsg = _("Unable to unload raster map")
1646  successMsg = _("Raster map")
1647  else:
1648  nvizType = 'volume'
1649  unloadFn = self._display.UnloadVolume
1650  errorMsg = _("Unable to unload 3d raster map")
1651  successMsg = _("3d raster map")
1652 
1653  try:
1654  id = data[nvizType]['object']['id']
1655  except KeyError:
1656  return
1657 
1658  if unloadFn(id) == 0:
1659  self.log.WriteError("%s <%s>" % (errorMsg, layer.name))
1660  else:
1661  self.log.WriteLog("%s <%s> %s" % (successMsg, layer.name, _("unloaded successfully")))
1662 
1663  data[nvizType].pop('object')
1664 
1665  self.layers.remove(item)
1666 
1667  # update tools window
1668  if hasattr(self.lmgr, "nviz"):
1669  toolWin = self.lmgr.nviz
1670  if layer.type == 'raster':
1671  win = toolWin.FindWindowById(toolWin.win['vector']['lines']['surface'])
1672  win.SetItems(self.GetLayerNames(layer.type))
1673  win = toolWin.FindWindowById(toolWin.win['surface']['map'])
1674  win.SetValue('')
1675  if layer.type == '3d-raster':
1676  win = toolWin.FindWindowById(toolWin.win['volume']['map'])
1677  win.SetValue('')
1678  if layer.type == 'vector':
1679  win = toolWin.FindWindowById(toolWin.win['vector']['map'])
1680  win.SetValue('')
1681 
1682  def LoadVector(self, item, points = None, append = True):
1683  """!Load 2D or 3D vector map overlay
1684 
1685  @param item layer item
1686  @param points True to load points, False to load lines, None
1687  to load both
1688  @param append append vector to layer list
1689  """
1690  layer = self.tree.GetPyData(item)[0]['maplayer']
1691  if layer.type != 'vector':
1692  return
1693 
1694  # set default properties
1695  if points is None:
1696  self.SetMapObjProperties(item, -1, 'lines')
1697  self.SetMapObjProperties(item, -1, 'points')
1698  vecTypes = ('points', 'lines')
1699  elif points:
1700  self.SetMapObjProperties(item, -1, 'points')
1701  vecTypes = ('points', )
1702  else:
1703  self.SetMapObjProperties(item, -1, 'lines')
1704  vecTypes = ('lines', )
1705 
1706  id = -1
1707  for vecType in vecTypes:
1708  if vecType == 'lines':
1709  id, baseId = self._display.LoadVector(str(layer.GetName()), False)
1710  else:
1711  id, baseId = self._display.LoadVector(str(layer.GetName()), True)
1712  if id < 0:
1713  self.log.WriteError(_("Loading vector map <%(name)s> (%(type)s) failed") % \
1714  { 'name' : layer.name, 'type' : vecType })
1715  # update layer properties
1716  self.SetMapObjProperties(item, id, vecType)
1717  if baseId > 0:
1718  self.baseId = baseId # id of base surface (when no surface is loaded)
1719  if append:
1720  self.layers.append(item)
1721 
1722  # update properties
1723  data = self.tree.GetPyData(item)[0]['nviz']
1724  event = wxUpdateProperties(data = data)
1725  wx.PostEvent(self, event)
1726 
1727  # update tools window
1728  if hasattr(self.lmgr, "nviz") and \
1729  item == self.GetSelectedLayer(type = 'item'):
1730  toolWin = self.lmgr.nviz
1731 
1732  toolWin.UpdatePage('vector')
1733  ### toolWin.SetPage('vector')
1734 
1735  return id
1736 
1737  def UnloadVector(self, item, points = None, remove = True):
1738  """!Unload vector map overlay
1739 
1740  @param item layer item
1741  @param points,lines True to unload given feature type
1742  @param remove remove layer from list
1743  """
1744  layer = self.tree.GetPyData(item)[0]['maplayer']
1745  data = self.tree.GetPyData(item)[0]['nviz']['vector']
1746 
1747  # if vecType is None:
1748  # vecType = []
1749  # for v in ('lines', 'points'):
1750  # if UserSettings.Get(group = 'nviz', key = 'vector',
1751  # subkey = [v, 'show']):
1752  # vecType.append(v)
1753 
1754  if points is None:
1755  vecTypes = ('points', 'lines')
1756  elif points:
1757  vecTypes = ('points', )
1758  else:
1759  vecTypes = ('lines', )
1760 
1761  for vecType in vecTypes:
1762  if 'object' not in data[vecType]:
1763  continue
1764 
1765  id = data[vecType]['object']['id']
1766 
1767  if vecType == 'lines':
1768  ret = self._display.UnloadVector(id, False)
1769  else:
1770  ret = self._display.UnloadVector(id, True)
1771  if ret == 0:
1772  self.log.WriteError(_("Unable to unload vector map <%(name)s> (%(type)s)") % \
1773  { 'name': layer.name, 'type' : vecType })
1774  else:
1775  self.log.WriteLog(_("Vector map <%(name)s> (%(type)s) unloaded successfully") % \
1776  { 'name' : layer.name, 'type' : vecType })
1777 
1778  data[vecType].pop('object')
1779 
1780  if remove and item in self.layers:
1781  self.layers.remove(item)
1782 
1783  def ResetView(self):
1784  """!Reset to default view"""
1785  zexagOriginal, \
1786  self.iview['height']['value'], \
1787  self.iview['height']['min'], \
1788  self.iview['height']['max'] = self._display.SetViewDefault()
1789 
1790  ## hack for latlon projection
1791  ## TODO find more precise way or better rewrite it in OGSF
1792  self.iview['z-exag']['llRatio'] = 1
1793  if grass.locn_is_latlong():
1794  self.iview['z-exag']['llRatio'] = \
1795  math.pi / 180 * 6371000 * math.cos((grass.region()['n'] + grass.region()['s']) / 2)
1796 
1797  self.view['z-exag']['value'] = round(zexagOriginal * self.iview['z-exag']['llRatio'])
1798  self.view['z-exag']['min'] = UserSettings.Get(group = 'nviz', key = 'view',
1799  subkey = ('z-exag', 'min'))
1800  zexagMax = UserSettings.Get(group = 'nviz', key = 'view',
1801  subkey = ('z-exag', 'max'))
1802  if zexagMax <= self.view['z-exag']['value']:
1803  self.view['z-exag']['max'] = self.view['z-exag']['value'] * 2
1804  elif self.view['z-exag']['value'] < 1:
1805  if self.view['z-exag']['value'] == 0:
1806  self.view['z-exag']['value'] = 1
1807  self.view['z-exag']['max'] = 10 * self.view['z-exag']['value']
1808  else:
1809  self.view['z-exag']['max'] = zexagMax
1810 
1811  self.view['position']['x'] = UserSettings.Get(group = 'nviz', key = 'view',
1812  subkey = ('position', 'x'))
1813  self.view['position']['y'] = UserSettings.Get(group = 'nviz', key = 'view',
1814  subkey = ('position', 'y'))
1815  self.view['persp']['value'] = UserSettings.Get(group = 'nviz', key = 'view',
1816  subkey = ('persp', 'value'))
1817 
1818  self.view['twist']['value'] = UserSettings.Get(group = 'nviz', key = 'view',
1819  subkey = ('twist', 'value'))
1820  self._display.ResetRotation()
1821  self.iview['rotation'] = None
1822  self._display.LookAtCenter()
1823  focus = self.iview['focus']
1824  focus['x'], focus['y'], focus['z'] = self._display.GetFocus()
1825 
1826  self.PostViewEvent()
1827 
1828  def UpdateMapObjProperties(self, event):
1829  """!Generic method to update data layer properties"""
1830  data = event.data
1831 
1832  if 'surface' in data:
1833  try:
1834  id = data['surface']['object']['id']
1835  except KeyError:
1836  return
1837  self.UpdateSurfaceProperties(id, data['surface'])
1838  # -> initialized
1839  data['surface']['object']['init'] = True
1840 
1841  elif 'constant' in data:
1842  id = data['constant']['object']['id']
1843  self.UpdateConstantProperties(id, data['constant'])
1844  # -> initialized
1845  data['constant']['object']['init'] = True
1846 
1847  elif 'volume' in data:
1848  id = data['volume']['object']['id']
1849  self.UpdateVolumeProperties(id, data['volume'])
1850  # -> initialized
1851  data['volume']['object']['init'] = True
1852 
1853  elif 'vector' in data:
1854  for type in ('lines', 'points'):
1855  if 'object' in data['vector'][type]:
1856  id = data['vector'][type]['object']['id']
1857  self.UpdateVectorProperties(id, data['vector'], type)
1858  # -> initialized
1859  data['vector'][type]['object']['init'] = True
1860 
1861  def UpdateConstantProperties(self, id, data):
1862  """!Update surface map object properties"""
1863  self._display.SetSurfaceColor(id = id, map = False, value = data['color'])
1864  self._display.SetSurfaceTopo(id = id, map = False, value = data['value'])
1865  self._display.SetSurfaceRes(id, data['resolution'], data['resolution'])
1866  if data['transp'] == 0:
1867  self._display.UnsetSurfaceTransp(id)
1868  else:
1869  self._display.SetSurfaceTransp(id, map = False, value = data['transp'])
1870 
1871  def UpdateSurfaceProperties(self, id, data):
1872  """!Update surface map object properties"""
1873  # surface attributes
1874  for attrb in ('color', 'mask',
1875  'transp', 'shine'):
1876  if attrb not in data['attribute'] or \
1877  'update' not in data['attribute'][attrb]:
1878  continue
1879 
1880  map = data['attribute'][attrb]['map']
1881  value = data['attribute'][attrb]['value']
1882 
1883  if map is None: # unset
1884  # only optional attributes
1885  if attrb == 'mask':
1886  # TODO: invert mask
1887  # TODO: broken in NVIZ
1888  self._display.UnsetSurfaceMask(id)
1889  elif attrb == 'transp':
1890  self._display.UnsetSurfaceTransp(id)
1891  else:
1892  if type(value) == types.StringType and \
1893  len(value) <= 0: # ignore empty values (TODO: warning)
1894  continue
1895  if attrb == 'color':
1896  self._display.SetSurfaceColor(id, map, str(value))
1897  elif attrb == 'mask':
1898  # TODO: invert mask
1899  # TODO: broken in NVIZ
1900  self._display.SetSurfaceMask(id, False, str(value))
1901  elif attrb == 'transp':
1902  self._display.SetSurfaceTransp(id, map, str(value))
1903  elif attrb == 'shine':
1904  self._display.SetSurfaceShine(id, map, str(value))
1905  data['attribute'][attrb].pop('update')
1906 
1907  # draw res
1908  if 'update' in data['draw']['resolution']:
1909  coarse = data['draw']['resolution']['coarse']
1910  fine = data['draw']['resolution']['fine']
1911 
1912  if data['draw']['all']:
1913  self._display.SetSurfaceRes(-1, fine, coarse)
1914  else:
1915  self._display.SetSurfaceRes(id, fine, coarse)
1916  data['draw']['resolution'].pop('update')
1917 
1918  # draw style
1919  if 'update' in data['draw']['mode']:
1920  if data['draw']['mode']['value'] < 0: # need to calculate
1921  data['draw']['mode']['value'] = \
1922  self.nvizDefault.GetDrawMode(mode = data['draw']['mode']['desc']['mode'],
1923  style = data['draw']['mode']['desc']['style'],
1924  shade = data['draw']['mode']['desc']['shading'],
1925  string = True)
1926  style = data['draw']['mode']['value']
1927  if data['draw']['all']:
1928  self._display.SetSurfaceStyle(-1, style)
1929  else:
1930  self._display.SetSurfaceStyle(id, style)
1931  data['draw']['mode'].pop('update')
1932 
1933  # wire color
1934  if 'update' in data['draw']['wire-color']:
1935  color = data['draw']['wire-color']['value']
1936  if data['draw']['all']:
1937  self._display.SetWireColor(-1, str(color))
1938  else:
1939  self._display.SetWireColor(id, str(color))
1940  data['draw']['wire-color'].pop('update')
1941 
1942  # position
1943  if 'update' in data['position']:
1944  x = data['position']['x']
1945  y = data['position']['y']
1946  z = data['position']['z']
1947  self._display.SetSurfacePosition(id, x, y, z)
1948  data['position'].pop('update')
1949  data['draw']['all'] = False
1950 
1951  def UpdateVolumeProperties(self, id, data, isosurfId = None):
1952  """!Update volume (isosurface/slice) map object properties"""
1953  if 'update' in data['draw']['resolution']:
1954  if data['draw']['mode']['value'] == 0:
1955  self._display.SetIsosurfaceRes(id, data['draw']['resolution']['isosurface']['value'])
1956  else:
1957  self._display.SetSliceRes(id, data['draw']['resolution']['slice']['value'])
1958  data['draw']['resolution'].pop('update')
1959 
1960  if 'update' in data['draw']['shading']:
1961  if data['draw']['mode']['value'] == 0:
1962  if data['draw']['shading']['isosurface']['value'] < 0: # need to calculate
1963  mode = data['draw']['shading']['isosurface']['value'] = \
1964  self.nvizDefault.GetDrawMode(shade = data['draw']['shading']['isosurface'],
1965  string = False)
1966  self._display.SetIsosurfaceMode(id, mode)
1967  else:
1968  if data['draw']['shading']['slice']['value'] < 0: # need to calculate
1969  mode = data['draw']['shading']['slice']['value'] = \
1970  self.nvizDefault.GetDrawMode(shade = data['draw']['shading']['slice'],
1971  string = False)
1972  self._display.SetSliceMode(id, mode)
1973  data['draw']['shading'].pop('update')
1974 
1975  #
1976  # isosurface attributes
1977  #
1978  isosurfId = 0
1979  for isosurf in data['isosurface']:
1980  self._display.AddIsosurface(id, 0, isosurf_id = isosurfId)
1981  for attrb in ('topo', 'color', 'mask',
1982  'transp', 'shine'):
1983  if attrb not in isosurf or \
1984  'update' not in isosurf[attrb]:
1985  continue
1986  map = isosurf[attrb]['map']
1987  value = isosurf[attrb]['value']
1988 
1989  if map is None: # unset
1990  # only optional attributes
1991  if attrb == 'topo' :
1992  self._display.SetIsosurfaceTopo(id, isosurfId, map, str(value))
1993  elif attrb == 'mask':
1994  # TODO: invert mask
1995  # TODO: broken in NVIZ
1996  self._display.UnsetIsosurfaceMask(id, isosurfId)
1997  elif attrb == 'transp':
1998  self._display.UnsetIsosurfaceTransp(id, isosurfId)
1999  else:
2000  if type(value) == types.StringType and \
2001  len(value) <= 0: # ignore empty values (TODO: warning)
2002  continue
2003  elif attrb == 'color':
2004  self._display.SetIsosurfaceColor(id, isosurfId, map, str(value))
2005  elif attrb == 'mask':
2006  # TODO: invert mask
2007  # TODO: broken in NVIZ
2008  self._display.SetIsosurfaceMask(id, isosurfId, False, str(value))
2009  elif attrb == 'transp':
2010  self._display.SetIsosurfaceTransp(id, isosurfId, map, str(value))
2011  elif attrb == 'shine':
2012  self._display.SetIsosurfaceShine(id, isosurfId, map, str(value))
2013  isosurf[attrb].pop('update')
2014  isosurfId += 1
2015  #
2016  # slice attributes
2017  #
2018  sliceId = 0
2019  for slice in data['slice']:
2020  ret = self._display.AddSlice(id, slice_id = sliceId)
2021  if 'update' in slice['position']:
2022  pos = slice['position']
2023  ret = self._display.SetSlicePosition(id, sliceId, pos['x1'], pos['x2'],
2024  pos['y1'], pos['y2'], pos['z1'], pos['z2'], pos['axis'])
2025 
2026  slice['position'].pop('update')
2027  if 'update' in slice['transp']:
2028  tr = slice['transp']['value']
2029  self._display.SetSliceTransp(id, sliceId, tr)
2030  sliceId += 1
2031 
2032  # position
2033  if 'update' in data['position'] and 'x' in data['position']:
2034  x = data['position']['x']
2035  y = data['position']['y']
2036  z = data['position']['z']
2037  self._display.SetVolumePosition(id, x, y, z)
2038  data['position'].pop('update')
2039 
2040  def UpdateVectorProperties(self, id, data, type):
2041  """!Update vector layer properties
2042 
2043  @param id layer id
2044  @param data properties
2045  @param type lines/points
2046  """
2047  if type == 'points':
2048  self.UpdateVectorPointsProperties(id, data[type])
2049  else:
2050  self.UpdateVectorLinesProperties(id, data[type])
2051 
2052  def UpdateVectorLinesProperties(self, id, data):
2053  """!Update vector line map object properties"""
2054  # mode
2055  if 'update' in data['color'] or \
2056  'update' in data['width'] or \
2057  'update' in data['mode']:
2058  width = data['width']['value']
2059  color = data['color']['value']
2060  if data['mode']['type'] == 'flat':
2061  flat = True
2062  if 'surface' in data['mode']:
2063  data['mode'].pop('surface')
2064  else:
2065  flat = False
2066 
2067  self._display.SetVectorLineMode(id, color,
2068  width, flat)
2069 
2070  if 'update' in data['color']:
2071  data['color'].pop('update')
2072  if 'update' in data['width']:
2073  data['width'].pop('update')
2074 
2075  # height
2076  if 'update' in data['height']:
2077  self._display.SetVectorLineHeight(id,
2078  data['height']['value'])
2079  data['height'].pop('update')
2080 
2081  # surface
2082  if 'surface' in data['mode'] and 'update' in data['mode']:
2083  for item in range(len(data['mode']['surface']['value'])):
2084  for type in ('raster', 'constant'):
2085  sid = self.GetLayerId(type = type,
2086  name = data['mode']['surface']['value'][item])
2087  if sid > -1:
2088  if data['mode']['surface']['show'][item]:
2089  self._display.SetVectorLineSurface(id, sid)
2090  else:
2091  self._display.UnsetVectorLineSurface(id, sid)
2092  break
2093 
2094  if 'update' in data['mode']:
2095  data['mode'].pop('update')
2096 
2097  def UpdateVectorPointsProperties(self, id, data):
2098  """!Update vector point map object properties"""
2099  if 'update' in data['size'] or \
2100  'update' in data['width'] or \
2101  'update' in data['marker'] or \
2102  'update' in data['color']:
2103 
2104  ret = self._display.SetVectorPointMode(id, data['color']['value'],
2105  data['width']['value'], float(data['size']['value']),
2106  data['marker']['value'] + 1)
2107 
2108  error = None
2109  if ret == -1:
2110  error = _("Vector point layer not found (id = %d)") % id
2111  elif ret == -2:
2112  error = _("Unable to set data layer properties (id = %d)") % id
2113 
2114  if error:
2115  raise GException(_("Setting data layer properties failed.\n\n%s") % error)
2116 
2117  for prop in ('size', 'width', 'marker', 'color'):
2118  if 'update' in data[prop]:
2119  data[prop].pop('update')
2120 
2121  # height
2122  if 'update' in data['height']:
2123  self._display.SetVectorPointHeight(id,
2124  data['height']['value'])
2125  data['height'].pop('update')
2126 
2127  # surface
2128  if 'update' in data['mode']:
2129  if data['mode'].get('3d', False):
2130  self._display.SetVectorPointZMode(id, True)
2131  elif 'surface' in data['mode']:
2132  self._display.SetVectorPointZMode(id, False)
2133  for item in range(len(data['mode']['surface']['value'])):
2134  for type in ('raster', 'constant'):
2135  sid = self.GetLayerId(type=type,
2136  name=data['mode']['surface']['value'][item])
2137  if sid > -1:
2138  if data['mode']['surface']['show'][item]:
2139  self._display.SetVectorPointSurface(id, sid)
2140  else:
2141  self._display.UnsetVectorPointSurface(id, sid)
2142  break
2143  data['mode'].pop('update')
2144 
2145  def GetLayerNames(self, type):
2146  """!Return list of map layer names of given type"""
2147  layerName = []
2148 
2149  if type == 'constant':
2150  for item in self.constants:
2151  layerName.append(_("constant#") + str(item['constant']['object']['name']))
2152  else:
2153  for item in self.layers:
2154  mapLayer = self.tree.GetPyData(item)[0]['maplayer']
2155  if type != mapLayer.GetType():
2156  continue
2157 
2158  layerName.append(mapLayer.GetName())
2159 
2160  return layerName
2161 
2162  def GetLayerId(self, type, name, vsubtyp = None):
2163  """!Get layer object id or -1"""
2164  if len(name) < 1:
2165  return -1
2166 
2167  if type == 'constant':
2168  for item in self.constants:
2169  if _("constant#") + str(item['constant']['object']['name']) == name:
2170  return item['constant']['object']['id']
2171 
2172 
2173  for item in self.layers:
2174  mapLayer = self.tree.GetPyData(item)[0]['maplayer']
2175  if type != mapLayer.GetType() or \
2176  name != mapLayer.GetName():
2177  continue
2178 
2179  data = self.tree.GetPyData(item)[0]['nviz']
2180 
2181  try:
2182  if type == 'raster':
2183  return data['surface']['object']['id']
2184  elif type == 'vector':
2185  if vsubtyp == 'vpoint':
2186  return data['vector']['points']['object']['id']
2187  elif vsubtyp == 'vline':
2188  return data['vector']['lines']['object']['id']
2189  elif type == '3d-raster':
2190  return data['volume']['object']['id']
2191  except KeyError:
2192  return -1
2193  return -1
2194 
2195  def ReloadLayersData(self):
2196  """!Delete nviz data of all loaded layers and reload them from current settings"""
2197  for item in self.layers:
2198  type = self.tree.GetPyData(item)[0]['type']
2199  layer = self.tree.GetPyData(item)[0]['maplayer']
2200  data = self.tree.GetPyData(item)[0]['nviz']
2201 
2202  if type == 'raster':
2203  self.nvizDefault.SetSurfaceDefaultProp(data['surface'])
2204  if type == 'vector':
2205  vInfo = grass.vector_info_topo(layer.GetName())
2206  if (vInfo['points'] + vInfo['centroids']) > 0:
2207  self.nvizDefault.SetVectorPointsDefaultProp(data['vector']['points'])
2208  if (vInfo['lines'] + vInfo['boundaries']) > 0:
2209  self.nvizDefault.SetVectorLinesDefaultProp(data['vector']['lines'])
2210 
2211  def NvizCmdCommand(self):
2212  """!Generate command for m.nviz.image according to current state"""
2213  cmd = 'm.nviz.image '
2214 
2215  rasters = []
2216  vectors = []
2217  volumes = []
2218  for item in self.layers:
2219  if self.tree.GetPyData(item)[0]['type'] == 'raster':
2220  rasters.append(item)
2221  elif self.tree.GetPyData(item)[0]['type'] == '3d-raster':
2222  volumes.append(item)
2223  elif self.tree.GetPyData(item)[0]['type'] == 'vector':
2224  vectors.append(item)
2225  if not rasters and not self.constants:
2226  return _("At least one raster map required")
2227  # elevation_map/elevation_value
2228  if self.constants:
2229  subcmd = "elevation_value="
2230  for constant in self.constants:
2231  subcmd += "%d," % constant['constant']['value']
2232  subcmd = subcmd.strip(', ') + ' '
2233  cmd += subcmd
2234  if rasters:
2235  subcmd = "elevation_map="
2236  for item in rasters:
2237  subcmd += "%s," % self.tree.GetPyData(item)[0]['maplayer'].GetName()
2238  subcmd = subcmd.strip(', ') + ' '
2239  cmd += subcmd
2240  #
2241  # draw mode
2242  #
2243  cmdMode = "mode="
2244  cmdFine = "resolution_fine="
2245  cmdCoarse = "resolution_coarse="
2246  cmdShading = "shading="
2247  cmdStyle = "style="
2248  cmdWire = "wire_color="
2249  # test -a flag
2250  flag_a = "-a "
2251  nvizDataFirst = self.tree.GetPyData(rasters[0])[0]['nviz']['surface']['draw']
2252  for item in rasters:
2253  nvizData = self.tree.GetPyData(item)[0]['nviz']['surface']['draw']
2254  if nvizDataFirst != nvizData:
2255  flag_a = ""
2256  cmd += flag_a
2257  for item in rasters:
2258  nvizData = self.tree.GetPyData(item)[0]['nviz']['surface']['draw']
2259 
2260  cmdMode += "%s," % nvizData['mode']['desc']['mode']
2261  cmdFine += "%s," % nvizData['resolution']['fine']
2262  cmdCoarse += "%s," % nvizData['resolution']['coarse']
2263  cmdShading += "%s," % nvizData['mode']['desc']['shading']
2264  cmdStyle += "%s," % nvizData['mode']['desc']['style']
2265  cmdWire += "%s," % nvizData['wire-color']['value']
2266  for item in self.constants:
2267  cmdMode += "fine,"
2268  cmdFine += "%s," % item['constant']['resolution']
2269  cmdCoarse += "%s," % item['constant']['resolution']
2270  cmdShading += "gouraud,"
2271  cmdStyle += "surface,"
2272  cmdWire += "0:0:0,"
2273  mode = []
2274  for subcmd in (cmdMode, cmdFine, cmdCoarse, cmdShading, cmdStyle, cmdWire):
2275  if flag_a:
2276  mode.append(subcmd.split(',')[0] + ' ')
2277  else:
2278  subcmd = subcmd.strip(', ') + ' '
2279  cmd += subcmd
2280  if flag_a:# write only meaningful possibilities
2281  cmd += mode[0]
2282  if 'fine' in mode[0]:
2283  cmd += mode[1]
2284  elif 'coarse' in mode[0]:
2285  cmd += mode[2]
2286  elif 'both' in mode[0]:
2287  cmd += mode[2]
2288  cmd += mode[1]
2289  if 'flat' in mode[3]:
2290  cmd += mode[3]
2291  if 'wire' in mode[4]:
2292  cmd += mode[4]
2293  if 'coarse' in mode[0] or 'both' in mode[0] and 'wire' in mode[3]:
2294  cmd += mode[5]
2295  #
2296  # attributes
2297  #
2298  cmdColorMap = "color_map="
2299  cmdColorVal = "color="
2300  for item in rasters:
2301  nvizData = self.tree.GetPyData(item)[0]['nviz']['surface']['attribute']
2302  if 'color' not in nvizData:
2303  cmdColorMap += "%s," % self.tree.GetPyData(item)[0]['maplayer'].GetName()
2304  else:
2305  if nvizData['color']['map']:
2306  cmdColorMap += "%s," % nvizData['color']['value']
2307  else:
2308  cmdColorVal += "%s," % nvizData['color']['value']
2309  #TODO
2310  # transparency, shine, mask
2311  for item in self.constants:
2312  cmdColorVal += "%s," % item['constant']['color']
2313  if cmdColorMap.split("=")[1]:
2314  cmd += cmdColorMap.strip(', ') + ' '
2315  if cmdColorVal.split("=")[1]:
2316  cmd += cmdColorVal.strip(', ') + ' '
2317  cmd += "\\\n"
2318  #
2319  # vlines
2320  #
2321  if vectors:
2322  cmdLines = cmdLWidth = cmdLHeight = cmdLColor = cmdLMode = cmdLPos = \
2323  cmdPoints = cmdPWidth = cmdPSize = cmdPColor = cmdPMarker = cmdPPos = cmdPLayer = ""
2324  markers = ['x', 'box', 'sphere', 'cube', 'diamond',
2325  'dec_tree', 'con_tree', 'aster', 'gyro', 'histogram']
2326  for vector in vectors:
2327  layerName = self.tree.GetPyData(vector)[0]['maplayer'].GetName()
2328  vInfo = grass.vector_info_topo(layerName)
2329  nvizData = self.tree.GetPyData(vector)[0]['nviz']['vector']
2330  if (vInfo['lines'] + vInfo['boundaries']) > 0:
2331  cmdLines += "%s," % self.tree.GetPyData(vector)[0]['maplayer'].GetName()
2332  cmdLWidth += "%d," % nvizData['lines']['width']['value']
2333  cmdLHeight += "%d," % nvizData['lines']['height']['value']
2334  cmdLColor += "%s," % nvizData['lines']['color']['value']
2335  cmdLMode += "%s," % nvizData['lines']['mode']['type']
2336  cmdLPos += "0,0,%d," % nvizData['lines']['height']['value']
2337  if (vInfo['points'] + vInfo['centroids']) > 0:
2338  cmdPoints += "%s," % self.tree.GetPyData(vector)[0]['maplayer'].GetName()
2339  cmdPWidth += "%d," % nvizData['points']['width']['value']
2340  cmdPSize += "%d," % nvizData['points']['size']['value']
2341  cmdPColor += "%s," % nvizData['points']['color']['value']
2342  cmdPMarker += "%s," % markers[nvizData['points']['marker']['value']]
2343  cmdPPos += "0,0,%d," % nvizData['points']['height']['value']
2344  cmdPLayer += "1,1,"
2345  if cmdLines:
2346  cmd += "vline=" + cmdLines.strip(',') + ' '
2347  cmd += "vline_width=" + cmdLWidth.strip(',') + ' '
2348  cmd += "vline_color=" + cmdLColor.strip(',') + ' '
2349  cmd += "vline_height=" + cmdLHeight.strip(',') + ' '
2350  cmd += "vline_mode=" + cmdLMode.strip(',') + ' '
2351  cmd += "vline_position=" + cmdLPos.strip(',') + ' '
2352  if cmdPoints:
2353  cmd += "vpoint=" + cmdPoints.strip(',') + ' '
2354  cmd += "vpoint_width=" + cmdPWidth.strip(',') + ' '
2355  cmd += "vpoint_color=" + cmdPColor.strip(',') + ' '
2356  cmd += "vpoint_size=" + cmdPSize.strip(',') + ' '
2357  cmd += "vpoint_marker=" + cmdPMarker.strip(',') + ' '
2358  cmd += "vpoint_position=" + cmdPPos.strip(',') + ' '
2359  cmd += "\\\n"
2360 
2361  #
2362  # volumes
2363  #
2364  if volumes:
2365  cmdName = cmdShade = cmdRes = cmdPos = cmdIso = ""
2366  cmdIsoColorMap = cmdIsoColorVal = cmdIsoTrMap = cmdIsoTrVal = ""
2367  cmdSlice = cmdSliceTransp = cmdSlicePos = ""
2368  for i, volume in enumerate(volumes):
2369  nvizData = self.tree.GetPyData(volume)[0]['nviz']['volume']
2370  cmdName += "%s," % self.tree.GetPyData(volume)[0]['maplayer'].GetName()
2371  cmdShade += "%s," % nvizData['draw']['shading']['isosurface']['desc']
2372  cmdRes += "%d," % nvizData['draw']['resolution']['isosurface']['value']
2373  if nvizData['position']:
2374  cmdPos += "%d,%d,%d," % (nvizData['position']['x'], nvizData['position']['y'],
2375  nvizData['position']['z'])
2376  for iso in nvizData['isosurface']:
2377  level = iso['topo']['value']
2378  cmdIso += "%d:%s," % (i + 1, level)
2379  if iso['color']['map']:
2380  cmdIsoColorMap += "%s," % iso['color']['value']
2381  else:
2382  cmdIsoColorVal += "%s," % iso['color']['value']
2383  if 'transp' in iso:
2384  if iso['transp']['map']:
2385  cmdIsoTrMap += "%s," % iso['transp']['value']
2386  else:
2387  cmdIsoTrVal += "%s," % iso['transp']['value']
2388 
2389  for slice in nvizData['slice']:
2390  axis = ('x','y','z')[slice['position']['axis']]
2391  cmdSlice += "%d:%s," % (i + 1, axis)
2392  for coord in ('x1', 'x2', 'y1', 'y2', 'z1', 'z2'):
2393  cmdSlicePos += "%f," % slice['position'][coord]
2394  cmdSliceTransp += "%s," % slice['transp']['value']
2395 
2396  cmd += "volume=" + cmdName.strip(',') + ' '
2397  cmd += "volume_shading=" + cmdShade.strip(',') + ' '
2398  cmd += "volume_resolution=" + cmdRes.strip(',') + ' '
2399  if nvizData['position']:
2400  cmd += "volume_position=" + cmdPos.strip(',') + ' '
2401  if cmdIso:
2402  cmd += "isosurf_level=" + cmdIso.strip(',') + ' '
2403  if cmdIsoColorMap:
2404  cmd += "isosurf_color_map=" + cmdIsoColorMap.strip(',') + ' '
2405  if cmdIsoColorVal:
2406  cmd += "isosurf_color_value=" + cmdIsoColorVal.strip(',') + ' '
2407  if cmdIsoTrMap:
2408  cmd += "isosurf_transparency_map=" + cmdIsoTrMap.strip(',') + ' '
2409  if cmdIsoTrVal:
2410  cmd += "isosurf_transparency_value=" + cmdIsoTrVal.strip(',') + ' '
2411  if cmdSlice:
2412  cmd += "slice=" + cmdSlice.strip(',') + ' '
2413  cmd += "slice_position=" + cmdSlicePos.strip(',') + ' '
2414  cmd += "slice_transparency=" + cmdSliceTransp.strip(',') + ' '
2415 
2416  #
2417  # cutting planes
2418  #
2419  cplane = self.lmgr.nviz.FindWindowById(self.lmgr.nviz.win['cplane']['planes']).GetStringSelection()
2420  try:
2421  planeIndex = int(cplane.split()[-1]) - 1
2422  except (IndexError, ValueError):
2423  planeIndex = None
2424  if planeIndex is not None:
2425  shading = ['clear', 'top', 'bottom', 'blend', 'shaded']
2426  cmd += "cplane=%d " % planeIndex
2427  cmd += "cplane_rotation=%d " % self.cplanes[planeIndex]['rotation']['rot']
2428  cmd += "cplane_tilt=%d " % self.cplanes[planeIndex]['rotation']['tilt']
2429  cmd += "cplane_position=%d,%d,%d " % (self.cplanes[planeIndex]['position']['x'],
2430  self.cplanes[planeIndex]['position']['y'],
2431  self.cplanes[planeIndex]['position']['z'])
2432  cmd += "cplane_shading=%s " % shading[self.cplanes[planeIndex]['shading']]
2433  cmd += "\\\n"
2434  #
2435  # viewpoint
2436  #
2437  subcmd = "position=%.2f,%.2f " % (self.view['position']['x'], self.view['position']['y'])
2438  subcmd += "height=%d " % (self.iview['height']['value'])
2439  subcmd += "perspective=%d " % (self.view['persp']['value'])
2440  subcmd += "twist=%d " % (self.view['twist']['value'])
2441  subcmd += "zexag=%f " % (self.view['z-exag']['value'] / self.iview['z-exag']['llRatio'])
2442  subcmd += "focus=%d,%d,%d " % (self.iview['focus']['x'],self.iview['focus']['y'],self.iview['focus']['z'])
2443  cmd += subcmd
2444 
2445  # background
2446  subcmd = "bgcolor=%d:%d:%d " % (self.view['background']['color'][:3])
2447  if self.view['background']['color'] != (255, 255, 255):
2448  cmd += subcmd
2449  cmd += "\\\n"
2450  # light
2451  subcmd = "light_position=%.2f,%.2f,%.2f " % (self.light['position']['x'],
2452  self.light['position']['y'],
2453  self.light['position']['z']/100.)
2454  subcmd += "light_brightness=%d " % (self.light['bright'])
2455  subcmd += "light_ambient=%d " % (self.light['ambient'])
2456  subcmd += "light_color=%d:%d:%d " % (self.light['color'][:3])
2457  cmd += subcmd
2458  cmd += "\\\n"
2459  # fringe
2460  toolWindow = self.lmgr.nviz
2461  direction = ''
2462  for dir in ('nw', 'ne', 'sw', 'se'):
2463  if toolWindow.FindWindowById(toolWindow.win['fringe'][dir]).IsChecked():
2464  direction += "%s," % dir
2465  if direction:
2466  subcmd = "fringe=%s " % (direction.strip(','))
2467  color = toolWindow.FindWindowById(toolWindow.win['fringe']['color']).GetValue()
2468  subcmd += "fringe_color=%d:%d:%d " % (color[0], color[1], color[2])
2469  subcmd += "fringe_elevation=%d " % (toolWindow.FindWindowById(toolWindow.win['fringe']['elev']).GetValue())
2470  cmd += subcmd
2471  cmd += "\\\n"
2472  # north arrow
2473  if self.decoration['arrow']['show']:
2474  subcmd = "arrow_position=%d,%d " % (self.decoration['arrow']['position']['x'],
2475  self.decoration['arrow']['position']['y'])
2476  subcmd += "arrow_color=%s " % self.decoration['arrow']['color']
2477  subcmd += "arrow_size=%d " % self.decoration['arrow']['size']
2478  cmd += subcmd
2479 
2480  # output
2481  subcmd = 'output=nviz_output '
2482  subcmd += 'format=ppm '
2483  subcmd += 'size=%d,%d ' % self.GetClientSizeTuple()
2484  cmd += subcmd
2485 
2486  return cmd
2487 
2488  def OnNvizCmd(self):
2489  """!Generate and write command to command output"""
2490  self.log.WriteLog(self.NvizCmdCommand(), switchPage = True)
2491 
2492  def SaveToFile(self, FileName, FileType, width, height):
2493  """!This draws the DC to a buffer that can be saved to a file.
2494 
2495  @todo fix BufferedPaintDC
2496 
2497  @param FileName file name
2498  @param FileType type of bitmap
2499  @param width image width
2500  @param height image height
2501  """
2502  self._display.SaveToFile(FileName, width, height, FileType)
2503 
2504  # pbuffer = wx.EmptyBitmap(max(1, self.Map.width), max(1, self.Map.height))
2505  # dc = wx.BufferedPaintDC(self, pbuffer)
2506  # dc.Clear()
2507  # self.SetCurrent()
2508  # self._display.Draw(False, -1)
2509  # pbuffer.SaveFile(FileName, FileType)
2510  # self.SwapBuffers()
2511 
2512  def GetDisplay(self):
2513  """!Get display instance"""
2514  return self._display
2515 
2516  def ZoomToMap(self):
2517  """!Reset view
2518  """
2519  self.lmgr.nviz.OnResetView(None)
2520 
2521  def TextBounds(self, textinfo):
2522  """!Return text boundary data
2523 
2524  @param textinfo text metadata (text, font, color, rotation)
2525  """
2526  return self.parent.MapWindow2D.TextBounds(textinfo, relcoords = True)
def UpdateSurfaceProperties
Update surface map object properties.
def _loadRaster
Load 2d/3d raster map and set its attributes.
def ChangeInnerView
Get current viewdir and viewpoint and set view.
def QuerySurface
Query surface on given position.
def ReloadLayersData
Delete nviz data of all loaded layers and reload them from current settings.
def NvizCmdCommand
Generate command for m.nviz.image according to current state.
def GetValue
Definition: widgets.py:118
Abstract map display window class.
wxNviz workspace settings
wxGUI command interface
def UpdateVectorLinesProperties
Update vector line map object properties.
def OnDClick
On mouse double click.
def CheckWxVersion
Check wx version.
Definition: globalvar.py:36
def LoadVector
Load 2D or 3D vector map overlay.
def ChangeFlySpeed
Increase/decrease flight spped.
def _unloadRaster
Unload 2d/3d raster map.
wxGUI debugging
def PostViewEvent
Change view settings.
def OnMouseWheel
Change perspective.
def GetSelectedLayer
Get selected layer from layer tree.
def OnMouseAction
Handle mouse events.
Map display canvas - base class for buffered window.
def DrawImages
Draw overlay image.
Class representing OpenGL texture as an overlay image.
Definition: wxnviz.py:2014
def OnQueryVector
Query vector on given position.
def OnMotion
Tracks mouse motion and update statusbar.
Class representing OpenGL texture as a text label.
Definition: wxnviz.py:2035
def UnloadRaster3d
Unload 3d raster map.
def OnUpdateView
Change view settings.
def HorizontalPanning
Move all layers in horizontal (x, y) direction.
def GetLayerNames
Return list of map layer names of given type.
def NewConstant
Create new constant.
def UpdateVolumeProperties
Update volume (isosurface/slice) map object properties.
def SetValue
Definition: widgets.py:115
def GetDisplay
Get display instance.
def GetLegendRect
Estimates legend size for dragging.
def SetToolWin
Sets reference to nviz toolwindow in layer manager.
NvizSettings
Definition: nviz/main.py:36
def GetToolWin
Returns reference to nviz toolwindow in layer manager.
def FocusPanning
Simulation of panning using focus.
def InitCPlanes
Initialize cutting planes list.
def split
Platform spefic shlex.split.
Definition: core/utils.py:37
def UpdateConstantProperties
Update surface map object properties.
def OnKeyDown
Key was pressed.
def CreateTexture
Create texture from overlay image or from textdict.
def TextBounds
Return text boundary data.
def UpdateLight
Change light settings.
def ProcessFlyByArrows
Process arrow key during fly-through.
def UnloadRaster
Unload 2d raster map.
def DeleteConstant
Delete constant layer.
def EraseMap
Erase the canvas.
def ResetView
Reset to default view.
def SetVectorFromCmd
Set 3D view properties from cmd (d.vect)
def UpdateOverlays
Converts rendered overlay files and text labels to wx.Image and then to textures so that they can be ...
def LoadRaster3d
Load 3d raster map and set surface attributes.
def StopTimer
Stop timer if running.
def SelectCPlane
Select cutting plane.
def SaveToFile
This draws the DC to a buffer that can be saved to a file.
def _GetDataLayers
Return get list of enabled map layers.
def ZoomBack
Set previous view in history list.
def __del__
Stop timers if running, unload data.
def ViewHistory
Manages a list of last 10 views.
def UnloadVector
Unload vector map overlay.
def IsLoaded
Check if layer (item) is already loaded.
def DrawTextImage
Draw overlay text.
def UpdateVectorProperties
Update vector layer properties.
def SetMapObjProperties
Set map object properties.
def InitFly
Initialize fly through dictionary.
def GetDisplay
Get display instance.
def LoadRaster
Load 2d raster map and set surface attributes.
def ResetViewHistory
Reset view history.
def SetRange
Definition: widgets.py:128
def UnloadDataLayers
Unload any layers that have been deleted from layer tree.
def UpdateVectorPointsProperties
Update vector point map object properties.
def _getDecorationSize
Get initial size of north arrow/scalebar.
Global variables used by wxGUI.
def SetVectorSurface
Set reference surfaces of vector.
def OnUpdateCPlane
Change cutting plane settings.
def SetDrawScalebar
Add scale bar, sets properties and draw.
#define round(x)
Definition: draw2.c:71
def ComputeMxMy
Compute values for flythrough navigation (ComputeFlyValues should follow).
def OnNvizCmd
Generate and write command to command output.
Default GUI settings.
def OnKeyUp
Key was released.
def UpdateView
Change view settings.
def UpdateMap
Updates the canvas anytime there is a change to the underlaying images or to the geometry of the canv...
tuple range
Definition: tools.py:1406
def Pixel2Cell
Convert image coordinates to real word coordinates.
def LoadDataLayers
Load raster/vector from current layer tree.
def OnTimerFly
Fly event was emitted, move the scene.
def GoTo
Focus on given point.
def GetLayerId
Get layer object id or -1.
Nviz (3D view) animation.
OpenGL canvas for Map Display Window.
def ComputeFlyValues
Compute parameters for fly-through navigation.
def UpdateCPlane
Change cutting plane settings.
def OnLeftDown
On left mouse down.
def DragItem
Drag an overlay decoration item.
Command output widgets.
def AddConstant
Add new constant.
def ZoomToMap
Reset view.
def UpdateMapObjProperties
Generic method to update data layer properties.
def DoZoom
Change perspective and focus.