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