GRASS Programmer's Manual  6.4.2(2012)
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
nviz_mapdisp.py
Go to the documentation of this file.
1 """
2 @package nviz_mapdisp.py
3 
4 @brief Nviz extension for wxGUI
5 
6 This module implements 3D visualization mode of map display.
7 
8 List of classes:
9  - GLWindow
10 
11 (C) 2008-2009 by the GRASS Development Team
12 
13 This program is free software under the GNU General Public
14 License (>=v2). Read the file COPYING that comes with GRASS
15 for details.
16 
17 @author Martin Landa <landa.martin gmail.com> (Google SoC 2008)
18 """
19 
20 import os
21 import sys
22 import time
23 import copy
24 import math
25 
26 from threading import Thread
27 
28 import wx
29 import wx.lib.scrolledpanel as scrolled
30 from wx.lib.newevent import NewEvent
31 from wx import glcanvas
32 
33 import gcmd
34 import globalvar
35 from debug import Debug
36 from mapdisp_window import MapWindow
37 from goutput import wxCmdOutput
38 from preferences import globalSettings as UserSettings
39 from workspace import Nviz as NvizDefault
40 
41 try:
42  import wxnviz
43 except (ImportError, NameError):
44  pass
45 
46 wxUpdateProperties, EVT_UPDATE_PROP = NewEvent()
47 wxUpdateView, EVT_UPDATE_VIEW = NewEvent()
48 wxUpdateLight, EVT_UPDATE_LIGHT = NewEvent()
49 
50 class NvizThread(Thread):
51  def __init__(self, log, progressbar, window):
52  Thread.__init__(self)
53 
54  self.log = log
55  self.progressbar = progressbar
56  self.window = window
57 
58  self._display = None
59 
60  self.setDaemon(True)
61 
62  def run(self):
63  self._display = wxnviz.Nviz(self.log, self.progressbar)
64 
65  def GetDisplay(self):
66  """!Get display instance"""
67  return self._display
68 
69 class GLWindow(MapWindow, glcanvas.GLCanvas):
70  """!OpenGL canvas for Map Display Window"""
71  def __init__(self, parent, id = wx.ID_ANY,
72  Map = None, tree = None, lmgr = None):
73  self.parent = parent # MapFrame
74 
75  glcanvas.GLCanvas.__init__(self, parent, id)
76  MapWindow.__init__(self, parent, id,
77  Map, tree, lmgr)
78  self.Hide()
79 
80  self.init = False
81  self.initView = False
82 
83  # render mode
84  self.render = { 'quick' : False,
85  # do not render vector lines in quick mode
86  'vlines' : False,
87  'vpoints' : False }
88 
89  # list of loaded map layers (layer tree items)
90  self.layers = list()
91  # list of query points
92  self.qpoints = list()
93 
94  #
95  # use display region instead of computational
96  #
97  os.environ['GRASS_REGION'] = self.Map.SetRegion()
98 
99  #
100  # create nviz instance
101  #
102  if self.lmgr:
103  self.log = self.lmgr.goutput
104  logerr = self.lmgr.goutput.GetLog(err = True)
105  logmsg = self.lmgr.goutput.GetLog()
106  else:
107  self.log = logmsg = sys.stdout
108  logerr = sys.stderr
109 
110  self.nvizThread = NvizThread(logerr,
111  self.parent.statusbarWin['progress'],
112  logmsg)
113  self.nvizThread.start()
114  time.sleep(.1)
115  self._display = self.nvizThread.GetDisplay()
116 
117  # GRASS_REGION needed only for initialization
118  del os.environ['GRASS_REGION']
119 
120  self.img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
121 
122  # size of MapWindow, to avoid resizing if size is the same
123  self.size = (0,0)
124 
125  #
126  # default values
127  #
128  self.view = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'view')) # copy
129  self.iview = UserSettings.Get(group = 'nviz', key = 'view', internal = True)
130 
131  self.nvizDefault = NvizDefault()
132  self.light = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'light')) # copy
133 
134  self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
135  self.Bind(wx.EVT_SIZE, self.OnSize)
136  self.Bind(wx.EVT_PAINT, self.OnPaint)
137  self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
138  self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseAction)
139  self.Bind(wx.EVT_MOTION, self.OnMotion)
140 
141  self.Bind(EVT_UPDATE_PROP, self.UpdateMapObjProperties)
142  self.Bind(EVT_UPDATE_VIEW, self.UpdateView)
143  self.Bind(EVT_UPDATE_LIGHT, self.UpdateLight)
144 
145  self.Bind(wx.EVT_CLOSE, self.OnClose)
146 
147  def OnClose(self, event):
148  # cleanup when window actually closes (on quit) and not just is hidden
149  self.Reset()
150 
151  def OnEraseBackground(self, event):
152  pass # do nothing, to avoid flashing on MSW
153 
154  def OnSize(self, event):
155  size = self.GetClientSize()
156  if self.size != size \
157  and self.GetContext():
158  Debug.msg(3, "GLCanvas.OnSize(): w = %d, h = %d" % \
159  (size.width, size.height))
160  self.SetCurrent()
161  self._display.ResizeWindow(size.width,
162  size.height)
163  self.size = size
164  event.Skip()
165 
166  def OnPaint(self, event):
167  Debug.msg(1, "GLCanvas.OnPaint()")
168 
169  dc = wx.PaintDC(self)
170  self.SetCurrent()
171 
172  if not self.initView:
173  self._display.InitView()
174  self.initView = True
175 
176  self.LoadDataLayers()
177  self.UnloadDataLayers()
178 
179  if not self.init:
180  self.ResetView()
181 
182  if hasattr(self.lmgr, "nviz"):
183  self.lmgr.nviz.UpdatePage('view')
184  self.lmgr.nviz.UpdatePage('light')
185  layer = self.GetSelectedLayer()
186  if layer:
187  if layer.type == 'raster':
188  self.lmgr.nviz.UpdatePage('surface')
189  self.lmgr.nviz.UpdatePage('fringe')
190  elif layer.type == 'vector':
191  self.lmgr.nviz.UpdatePage('vector')
192 
193  ### self.lmgr.nviz.UpdateSettings()
194 
195  # update widgets
196  win = self.lmgr.nviz.FindWindowById( \
197  self.lmgr.nviz.win['vector']['lines']['surface'])
198  win.SetItems(self.GetLayerNames('raster'))
199 
200  self.init = True
201 
202  self.UpdateMap()
203 
204  def OnMouseAction(self, event):
205  # change perspective with mouse wheel
206  wheel = event.GetWheelRotation()
207 
208  if wheel != 0:
209  current = event.GetPositionTuple()[:]
210  Debug.msg (5, "GLWindow.OnMouseMotion(): wheel = %d" % wheel)
211  prev_value = self.view['persp']['value']
212  if wheel > 0:
213  value = -1 * self.view['persp']['step']
214  else:
215  value = self.view['persp']['step']
216  self.view['persp']['value'] += value
217  if self.view['persp']['value'] < 1:
218  self.view['persp']['value'] = 1
219  elif self.view['persp']['value'] > 100:
220  self.view['persp']['value'] = 100
221 
222  if prev_value != self.view['persp']['value']:
223  if hasattr(self.lmgr, "nviz"):
224  self.lmgr.nviz.UpdateSettings()
225 
226  self._display.SetView(self.view['position']['x'], self.view['position']['y'],
227  self.iview['height']['value'],
228  self.view['persp']['value'],
229  self.view['twist']['value'])
230 
231  # redraw map
232  self.OnPaint(None)
233 
234  # update statusbar
235  ### self.parent.StatusbarUpdate()
236 
237  event.Skip()
238 
239  def Pixel2Cell(self, (x, y)):
240  """!Convert image coordinates to real word coordinates
241 
242  @param x, y image coordinates
243 
244  @return easting, northing
245  @return None on error
246  """
247  size = self.GetClientSize()
248  # UL -> LL
249  sid, x, y, z = self._display.GetPointOnSurface(x, y)
250 
251  if not sid:
252  return None
253 
254  return (x, y)
255 
256  def OnLeftUp(self, event):
257  self.ReleaseMouse()
258  if self.mouse["use"] == "nvizQuerySurface":
259  self.OnQuerySurface(event)
260  elif self.mouse["use"] == "nvizQueryVector":
261  self.OnQueryVector(event)
262 
263  def OnQuerySurface(self, event):
264  """!Query surface on given position"""
265  result = self._display.QueryMap(event.GetX(), event.GetY())
266  if result:
267  self.qpoints.append((result['x'], result['y'], result['z']))
268  self.log.WriteLog("%-30s: %.3f" % (_("Easting"), result['x']))
269  self.log.WriteLog("%-30s: %.3f" % (_("Northing"), result['y']))
270  self.log.WriteLog("%-30s: %.3f" % (_("Elevation"), result['z']))
271  self.log.WriteLog("%-30s: %s" % (_("Surface map elevation"), result['elevation']))
272  self.log.WriteLog("%-30s: %s" % (_("Surface map color"), result['color']))
273  if len(self.qpoints) > 1:
274  prev = self.qpoints[-2]
275  curr = self.qpoints[-1]
276  dxy = math.sqrt(pow(prev[0]-curr[0], 2) +
277  pow(prev[1]-curr[1], 2))
278  dxyz = math.sqrt(pow(prev[0]-curr[0], 2) +
279  pow(prev[1]-curr[1], 2) +
280  pow(prev[2]-curr[2], 2))
281  self.log.WriteLog("%-30s: %.3f" % (_("XY distance from previous"), dxy))
282  self.log.WriteLog("%-30s: %.3f" % (_("XYZ distance from previous"), dxyz))
283  self.log.WriteLog("%-30s: %.3f" % (_("Distance along surface"),
284  self._display.GetDistanceAlongSurface(result['id'],
285  (curr[0], curr[1]),
286  (prev[0], prev[1]),
287  useExag = False)))
288  self.log.WriteLog("%-30s: %.3f" % (_("Distance along exag. surface"),
289  self._display.GetDistanceAlongSurface(result['id'],
290  (curr[0], curr[1]),
291  (prev[0], prev[1]),
292  useExag = True)))
293  self.log.WriteCmdLog('-' * 80)
294  else:
295  self.log.WriteLog(_("No point on surface"))
296  self.log.WriteCmdLog('-' * 80)
297 
298  def OnQueryVector(self, event):
299  """!Query vector on given position"""
300  self.log.WriteWarning(_("Function not implemented yet"))
301  self.log.WriteCmdLog('-' * 80)
302 
303  def UpdateView(self, event):
304  """!Change view settings"""
305  data = self.view
306  self._display.SetView(data['position']['x'], data['position']['y'],
307  self.iview['height']['value'],
308  data['persp']['value'],
309  data['twist']['value'])
310 
311  if event and event.zExag and 'value' in data['z-exag']:
312  self._display.SetZExag(data['z-exag']['value'])
313 
314  if event:
315  event.Skip()
316 
317  def UpdateLight(self, event):
318  """!Change light settings"""
319  data = self.light
320  self._display.SetLight(x = data['position']['x'], y = data['position']['y'],
321  z = data['position']['z'] / 100., color = data['color'],
322  bright = data['bright'] / 100.,
323  ambient = data['ambient'] / 100.)
324  self._display.DrawLightingModel()
325 
326  def UpdateMap(self, render = True):
327  """!Updates the canvas anytime there is a change to the
328  underlaying images or to the geometry of the canvas.
329 
330  @param render re-render map composition
331  """
332  start = time.clock()
333 
334  self.resize = False
335 
336  if self.render['quick'] is False:
337  self.parent.statusbarWin['progress'].Show()
338  self.parent.statusbarWin['progress'].SetRange(2)
339  self.parent.statusbarWin['progress'].SetValue(0)
340 
341  if self.render['quick'] is False:
342  self.parent.statusbarWin['progress'].SetValue(1)
343  self._display.Draw(False, -1)
344  elif self.render['quick'] is True:
345  # quick
346  mode = wxnviz.DRAW_QUICK_SURFACE | wxnviz.DRAW_QUICK_VOLUME
347  if self.render['vlines']:
348  mode |= wxnviz.DRAW_QUICK_VLINES
349  if self.render['vpoints']:
350  mode |= wxnviz.DRAW_QUICK_VPOINTS
351  self._display.Draw(True, mode)
352  else: # None -> reuse last rendered image
353  pass # TODO
354 
355  self.SwapBuffers()
356 
357  stop = time.clock()
358 
359  if self.render['quick'] is False:
360  self.parent.statusbarWin['progress'].SetValue(2)
361  # hide process bar
362  self.parent.statusbarWin['progress'].Hide()
363 
364  Debug.msg(3, "GLWindow.UpdateMap(): quick = %d, -> time = %g" % \
365  (self.render['quick'], (stop-start)))
366 
367  def EraseMap(self):
368  """!Erase the canvas
369  """
370  self._display.EraseMap()
371  self.SwapBuffers()
372 
373  def IsLoaded(self, item):
374  """!Check if layer (item) is already loaded
375 
376  @param item layer item
377  """
378  layer = self.tree.GetPyData(item)[0]['maplayer']
379  data = self.tree.GetPyData(item)[0]['nviz']
380 
381  if not data:
382  return 0
383 
384  if layer.type == 'raster':
385  if 'object' not in data['surface']:
386  return 0
387  elif layer.type == 'vector':
388  if 'object' not in data['vlines'] and \
389  'object' not in data['points']:
390  return 0
391 
392  return 1
393 
394  def _GetDataLayers(self, item, litems):
395  """!Return get list of enabled map layers"""
396  # load raster & vector maps
397  while item and item.IsOk():
398  type = self.tree.GetPyData(item)[0]['type']
399  if type == 'group':
400  subItem = self.tree.GetFirstChild(item)[0]
401  self._GetDataLayers(subItem, litems)
402  item = self.tree.GetNextSibling(item)
403 
404  if not item.IsChecked() or \
405  type not in ('raster', 'vector', '3d-raster'):
406  item = self.tree.GetNextSibling(item)
407  continue
408 
409  litems.append(item)
410 
411  item = self.tree.GetNextSibling(item)
412 
413  def LoadDataLayers(self):
414  """!Load raster/vector from current layer tree
415 
416  @todo volumes
417  """
418  if not self.tree:
419  return
420 
421  listOfItems = []
422  item = self.tree.GetFirstChild(self.tree.root)[0]
423  self._GetDataLayers(item, listOfItems)
424 
425  start = time.time()
426 
427  while(len(listOfItems) > 0):
428  item = listOfItems.pop()
429  type = self.tree.GetPyData(item)[0]['type']
430  if item in self.layers:
431  continue
432  try:
433  if type == 'raster':
434  self.LoadRaster(item)
435  elif type == '3d-raster':
436  self.LoadRaster3d(item)
437  elif type == 'vector':
438  # data = self.tree.GetPyData(item)[0]['nviz']
439  # vecType = []
440  # if data and 'vector' in data:
441  # for v in ('lines', 'points'):
442  # if data['vector'][v]:
443  # vecType.append(v)
444  layer = self.tree.GetPyData(item)[0]['maplayer']
445  npoints, nlines, nfeatures, mapIs3D = self.lmgr.nviz.VectorInfo(layer)
446  if npoints > 0:
447  self.LoadVector(item, points = True)
448  if nlines > 0:
449  self.LoadVector(item, points = False)
450  except gcmd.GException, e:
451  GError(parent = self,
452  message = e.value)
453  self.init = False
454 
455  stop = time.time()
456 
457  Debug.msg(3, "GLWindow.LoadDataLayers(): time = %f" % (stop-start))
458 
459  def UnloadDataLayers(self):
460  """!Unload any layers that have been deleted from layer tree"""
461  if not self.tree:
462  return
463 
464  listOfItems = []
465  item = self.tree.GetFirstChild(self.tree.root)[0]
466  self._GetDataLayers(item, listOfItems)
467 
468  start = time.time()
469 
470  for layer in self.layers:
471  if layer not in listOfItems:
472  ltype = self.tree.GetPyData(layer)[0]['type']
473  try:
474  if ltype == 'raster':
475  self.UnloadRaster(layer)
476  elif ltype == '3d-raster':
477  self.UnloadRaster3d(layer)
478  elif ltype == 'vector':
479  self.UnloadVector(layer, True)
480  self.UnloadVector(layer, False)
481 
482  self.UpdateView(None)
483  except gcmd.GException, e:
484  gcmd.GError(parent = self,
485  message = e.value)
486 
487  self.lmgr.nviz.UpdateSettings()
488 
489  stop = time.time()
490 
491  Debug.msg(3, "GLWindow.UnloadDataLayers(): time = %f" % (stop-start))
492 
493  def SetVectorFromCmd(self, item, data):
494  """!Set 3D view properties from cmd (d.vect)
495 
496  @param item Layer Tree item
497  @param nviz data
498  """
499  cmd = self.tree.GetPyData(item)[0]['cmd']
500  if cmd[0] != 'd.vect':
501  return
502  for opt in cmd[1:]:
503  try:
504  key, value = opt.split('=')
505  except ValueError:
506  continue
507  if key == 'color':
508  data['lines']['color']['value'] = value
509  data['points']['color']['value'] = value
510 
511  def SetMapObjProperties(self, item, id, nvizType):
512  """!Set map object properties
513 
514  Properties must be afterwards updated by
515  UpdateMapObjProperties().
516 
517  @param item layer item
518  @param id nviz layer id (or -1)
519  @param nvizType nviz data type (surface, points, vector)
520  """
521  type = self.tree.GetPyData(item)[0]['maplayer'].type
522  # reference to original layer properties (can be None)
523  data = self.tree.GetPyData(item)[0]['nviz']
524 
525  if not data:
526  # init data structure
527  self.tree.GetPyData(item)[0]['nviz'] = {}
528  data = self.tree.GetPyData(item)[0]['nviz']
529 
530  if type == 'raster':
531  # reset to default properties
532  data[nvizType] = self.nvizDefault.SetSurfaceDefaultProp()
533 
534  elif type == 'vector':
535  # reset to default properties (lines/points)
536  data['vector'] = self.nvizDefault.SetVectorDefaultProp()
537  self.SetVectorFromCmd(item, data['vector'])
538 
539  elif type == '3d-raster':
540  # reset to default properties
541  data[nvizType] = self.nvizDefault.SetVolumeDefaultProp()
542 
543  else:
544  # complete data (use default values)
545  if type == 'raster':
546  data['surface'] = self.nvizDefault.SetSurfaceDefaultProp()
547  if type == 'vector':
548  if not data['vector']['lines']:
549  self.nvizDefault.SetVectorLinesDefaultProp(data['vector']['lines'])
550  if not data['vector']['points']:
551  self.nvizDefault.SetVectorPointsDefaultProp(data['vector']['points'])
552 
553  # set updates
554  for sec in data.keys():
555  for sec1 in data[sec].keys():
556  for sec2 in data[sec][sec1].keys():
557  if sec2 != 'all':
558  data[sec][sec1][sec2]['update'] = None
559 
560  event = wxUpdateProperties(data = data)
561  wx.PostEvent(self, event)
562 
563  # set id
564  if id > 0:
565  if type in ('raster', '3d-raster'):
566  data[nvizType]['object'] = { 'id' : id,
567  'init' : False }
568  elif type == 'vector':
569  data['vector'][nvizType]['object'] = { 'id' : id,
570  'init' : False }
571 
572  return data
573 
574  def LoadRaster(self, item):
575  """!Load 2d raster map and set surface attributes
576 
577  @param layer item
578  """
579  return self._loadRaster(item)
580 
581  def LoadRaster3d(self, item):
582  """!Load 3d raster map and set surface attributes
583 
584  @param layer item
585  """
586  return self._loadRaster(item)
587 
588  def _loadRaster(self, item):
589  """!Load 2d/3d raster map and set its attributes
590 
591  @param layer item
592  """
593  layer = self.tree.GetPyData(item)[0]['maplayer']
594 
595  if layer.type not in ('raster', '3d-raster'):
596  return
597 
598  if layer.type == 'raster':
599  id = self._display.LoadSurface(str(layer.name), None, None)
600  nvizType = 'surface'
601  errorMsg = _("Loading raster map")
602  elif layer.type == '3d-raster':
603  id = self._display.LoadVolume(str(layer.name), None, None)
604  nvizType = 'volume'
605  errorMsg = _("Loading 3d raster map")
606  else:
607  id = -1
608 
609  if id < 0:
610  if layer.type in ('raster', '3d-raster'):
611  self.log.WriteError("%s <%s> %s" % (errorMsg, layer.name, _("failed")))
612  else:
613  self.log.WriteError(_("Unsupported layer type '%s'") % layer.type)
614 
615  self.layers.append(item)
616 
617  # set default/workspace layer properties
618  data = self.SetMapObjProperties(item, id, nvizType)
619 
620  # update properties
621  event = wxUpdateProperties(data = data)
622  wx.PostEvent(self, event)
623 
624  # update tools window
625  if hasattr(self.lmgr, "nviz") and \
626  item == self.GetSelectedLayer(type = 'item'):
627  toolWin = self.lmgr.nviz
628  if layer.type == 'raster':
629  win = toolWin.FindWindowById( \
630  toolWin.win['vector']['lines']['surface'])
631  win.SetItems(self.GetLayerNames(layer.type))
632 
633  #toolWin.UpdatePage(nvizType)
634  #toolWin.SetPage(nvizType)
635 
636  return id
637 
638  def UnloadRaster(self, item):
639  """!Unload 2d raster map
640 
641  @param layer item
642  """
643  return self._unloadRaster(item)
644 
645  def UnloadRaster3d(self, item):
646  """!Unload 3d raster map
647 
648  @param layer item
649  """
650  return self._unloadRaster(item)
651 
652  def _unloadRaster(self, item):
653  """!Unload 2d/3d raster map
654 
655  @param item layer item
656  """
657  layer = self.tree.GetPyData(item)[0]['maplayer']
658 
659  if layer.type not in ('raster', '3d-raster'):
660  return
661 
662  data = self.tree.GetPyData(item)[0]['nviz']
663 
664  if layer.type == 'raster':
665  nvizType = 'surface'
666  unloadFn = self._display.UnloadSurface
667  errorMsg = _("Unable to unload raster map")
668  successMsg = _("Raster map")
669  else:
670  nvizType = 'volume'
671  unloadFn = self._display.UnloadVolume
672  errorMsg = _("Unable to unload 3d raster map")
673  successMsg = _("3d raster map")
674 
675  id = data[nvizType]['object']['id']
676 
677  if unloadFn(id) == 0:
678  self.log.WriteError("%s <%s>" % (errorMsg, layer.name))
679  else:
680  self.log.WriteLog("%s <%s> %s" % (successMsg, layer.name, _("unloaded successfully")))
681 
682  data[nvizType].pop('object')
683 
684  self.layers.remove(item)
685 
686  # update tools window
687  if hasattr(self.lmgr, "nviz") and \
688  layer.type == 'raster':
689  toolWin = self.lmgr.nviz
690  win = toolWin.FindWindowById( \
691  toolWin.win['vector']['lines']['surface'])
692  win.SetItems(self.GetLayerNames(layer.type))
693 
694  def LoadVector(self, item, points = None):
695  """!Load 2D or 3D vector map overlay
696 
697  @param item layer item
698  @param points True to load points, False to load lines, None
699  to load both
700  """
701  layer = self.tree.GetPyData(item)[0]['maplayer']
702  if layer.type != 'vector':
703  return
704 
705  # set default properties
706  if points is None:
707  self.SetMapObjProperties(item, -1, 'lines')
708  self.SetMapObjProperties(item, -1, 'points')
709  vecTypes = ('points', 'lines')
710  elif points:
711  self.SetMapObjProperties(item, -1, 'points')
712  vecTypes = ('points', )
713  else:
714  self.SetMapObjProperties(item, -1, 'lines')
715  vecTypes = ('lines', )
716 
717  id = -1
718  for vecType in vecTypes:
719  if vecType == 'lines':
720  id = self._display.LoadVector(str(layer.GetName()), False)
721  else:
722  id = self._display.LoadVector(str(layer.GetName()), True)
723  if id < 0:
724  self.log.WriteError(_("Loading vector map <%(name)s> (%(type)s) failed") % \
725  { 'name' : layer.name, 'type' : vecType })
726  # update layer properties
727  self.SetMapObjProperties(item, id, vecType)
728 
729  self.layers.append(item)
730 
731  # update properties
732  data = self.tree.GetPyData(item)[0]['nviz']
733  event = wxUpdateProperties(data = data)
734  wx.PostEvent(self, event)
735 
736  # update tools window
737  if hasattr(self.lmgr, "nviz") and \
738  item == self.GetSelectedLayer(type = 'item'):
739  toolWin = self.lmgr.nviz
740 
741  toolWin.UpdatePage('vector')
742  ### toolWin.SetPage('vector')
743 
744  return id
745 
746  def UnloadVector(self, item, points = None):
747  """!Unload vector map overlay
748 
749  @param item layer item
750  @param points,lines True to unload given feature type
751  """
752  layer = self.tree.GetPyData(item)[0]['maplayer']
753  data = self.tree.GetPyData(item)[0]['nviz']['vector']
754 
755  # if vecType is None:
756  # vecType = []
757  # for v in ('lines', 'points'):
758  # if UserSettings.Get(group = 'nviz', key = 'vector',
759  # subkey = [v, 'show']):
760  # vecType.append(v)
761 
762  if points is None:
763  vecTypes = ('points', 'lines')
764  elif points:
765  vecTypes = ('points', )
766  else:
767  vecTypes = ('lines', )
768 
769  for vecType in vecTypes:
770  if 'object' not in data[vecType]:
771  continue
772 
773  id = data[vecType]['object']['id']
774 
775  if vecType == 'lines':
776  ret = self._display.UnloadVector(id, False)
777  else:
778  ret = self._display.UnloadVector(id, True)
779  if ret == 0:
780  self.log.WriteError(_("Unable to unload vector map <%(name)s> (%(type)s)") % \
781  { 'name': layer.name, 'type' : vecType })
782  else:
783  self.log.WriteLog(_("Vector map <%(name)s> (%(type)s) unloaded successfully") % \
784  { 'name' : layer.name, 'type' : vecType })
785 
786  data[vecType].pop('object')
787 
788  ### self.layers.remove(id)
789 
790  def Reset(self):
791  """!Reset (unload data)"""
792  for item in self.layers:
793  type = self.tree.GetPyData(item)[0]['maplayer'].type
794  if type == 'raster':
795  self.UnloadRaster(item)
796  elif type == '3d-raster':
797  self.UnloadRaster3d(item)
798  elif type == 'vector':
799  self.UnloadVector(item)
800 
801  self.init = False
802 
803  def OnZoomToMap(self, event):
804  """!Set display extents to match selected raster or vector
805  map or volume.
806 
807  @todo vector, volume
808  """
809  layer = self.GetSelectedLayer()
810 
811  if layer is None:
812  return
813 
814  Debug.msg (3, "GLWindow.OnZoomToMap(): layer = %s, type = %s" % \
815  (layer.name, layer.type))
816 
817  self._display.SetViewportDefault()
818 
819  def ResetView(self):
820  """!Reset to default view"""
821  self.view['z-exag']['value'], \
822  self.iview['height']['value'], \
823  self.iview['height']['min'], \
824  self.iview['height']['max'] = self._display.SetViewDefault()
825 
826  self.view['z-exag']['min'] = 0
827  self.view['z-exag']['max'] = self.view['z-exag']['value'] * 10
828 
829  self.view['position']['x'] = UserSettings.Get(group = 'nviz', key = 'view',
830  subkey = ('position', 'x'))
831  self.view['position']['y'] = UserSettings.Get(group = 'nviz', key = 'view',
832  subkey = ('position', 'y'))
833  self.view['persp']['value'] = UserSettings.Get(group = 'nviz', key = 'view',
834  subkey = ('persp', 'value'))
835 
836  self.view['twist']['value'] = UserSettings.Get(group = 'nviz', key = 'view',
837  subkey = ('twist', 'value'))
838 
839  event = wxUpdateView(zExag = False)
840  wx.PostEvent(self, event)
841 
842  def UpdateMapObjProperties(self, event):
843  """!Generic method to update data layer properties"""
844  data = event.data
845 
846  if 'surface' in data:
847  id = data['surface']['object']['id']
848  self.UpdateSurfaceProperties(id, data['surface'])
849  # -> initialized
850  data['surface']['object']['init'] = True
851 
852  elif 'volume' in data:
853  id = data['volume']['object']['id']
854  self.UpdateVolumeProperties(id, data['volume'])
855  # -> initialized
856  data['volume']['object']['init'] = True
857 
858  elif 'vector' in data:
859  for type in ('lines', 'points'):
860  if 'object' in data['vector'][type]:
861  id = data['vector'][type]['object']['id']
862  self.UpdateVectorProperties(id, data['vector'], type)
863  # -> initialized
864  data['vector'][type]['object']['init'] = True
865 
866  def UpdateSurfaceProperties(self, id, data):
867  """!Update surface map object properties"""
868  # surface attributes
869  for attrb in ('topo', 'color', 'mask',
870  'transp', 'shine', 'emit'):
871  if attrb not in data['attribute'] or \
872  'update' not in data['attribute'][attrb]:
873  continue
874 
875  map = data['attribute'][attrb]['map']
876  value = data['attribute'][attrb]['value']
877 
878  if map is None: # unset
879  # only optional attributes
880  if attrb == 'mask':
881  # TODO: invert mask
882  # TODO: broken in NVIZ
883  self._display.UnsetSurfaceMask(id)
884  elif attrb == 'transp':
885  self._display.UnsetSurfaceTransp(id)
886  elif attrb == 'emit':
887  self._display.UnsetSurfaceEmit(id)
888  else:
889  if type(value) == type('') and \
890  len(value) <= 0: # ignore empty values (TODO: warning)
891  continue
892  if attrb == 'topo':
893  self._display.SetSurfaceTopo(id, map, str(value))
894  elif attrb == 'color':
895  self._display.SetSurfaceColor(id, map, str(value))
896  elif attrb == 'mask':
897  # TODO: invert mask
898  # TODO: broken in NVIZ
899  self._display.SetSurfaceMask(id, False, str(value))
900  elif attrb == 'transp':
901  self._display.SetSurfaceTransp(id, map, str(value))
902  elif attrb == 'shine':
903  self._display.SetSurfaceShine(id, map, str(value))
904  elif attrb == 'emit':
905  self._display.SetSurfaceEmit(id, map, str(value))
906  data['attribute'][attrb].pop('update')
907 
908  # draw res
909  if 'update' in data['draw']['resolution']:
910  coarse = data['draw']['resolution']['coarse']
911  fine = data['draw']['resolution']['fine']
912 
913  if data['draw']['all']:
914  self._display.SetSurfaceRes(-1, fine, coarse)
915  else:
916  self._display.SetSurfaceRes(id, fine, coarse)
917  data['draw']['resolution'].pop('update')
918 
919  # draw style
920  if 'update' in data['draw']['mode']:
921  if data['draw']['mode']['value'] < 0: # need to calculate
922  data['draw']['mode']['value'] = \
923  self.nvizDefault.GetDrawMode(mode = data['draw']['mode']['desc']['mode'],
924  style = data['draw']['mode']['desc']['style'],
925  shade = data['draw']['mode']['desc']['shading'],
926  string = True)
927  style = data['draw']['mode']['value']
928  if data['draw']['all']:
929  self._display.SetSurfaceStyle(-1, style)
930  else:
931  self._display.SetSurfaceStyle(id, style)
932  data['draw']['mode'].pop('update')
933 
934  # wire color
935  if 'update' in data['draw']['wire-color']:
936  color = data['draw']['wire-color']['value']
937  if data['draw']['all']:
938  self._display.SetWireColor(-1, str(color))
939  else:
940  self._display.SetWireColor(id, str(color))
941  data['draw']['wire-color'].pop('update')
942 
943  # position
944  if 'update' in data['position']:
945  x = data['position']['x']
946  y = data['position']['y']
947  z = data['position']['z']
948  self._display.SetSurfacePosition(id, x, y, z)
949  data['position'].pop('update')
950  data['draw']['all'] = False
951 
952  def UpdateVolumeProperties(self, id, data, isosurfId = None):
953  """!Update volume (isosurface/slice) map object properties"""
954  if 'update' in data['draw']['resolution']:
955  self._display.SetIsosurfaceRes(id, data['draw']['resolution']['value'])
956  data['draw']['resolution'].pop('update')
957 
958  if 'update' in data['draw']['shading']:
959  if data['draw']['shading']['value'] < 0: # need to calculate
960  data['draw']['shading']['value'] = \
961  self.nvizDefault.GetDrawMode(shade = data['draw']['shading'],
962  string = False)
963  data['draw']['shading'].pop('update')
964 
965  #
966  # isosurface attributes
967  #
968  isosurfId = 0
969  for isosurf in data['isosurface']:
970  for attrb in ('color', 'mask',
971  'transp', 'shine', 'emit'):
972  if attrb not in isosurf or \
973  'update' not in isosurf[attrb]:
974  continue
975  map = isosurf[attrb]['map']
976  value = isosurf[attrb]['value']
977 
978  if map is None: # unset
979  # only optional attributes
980  if attrb == 'mask':
981  # TODO: invert mask
982  # TODO: broken in NVIZ
983  self._display.UnsetIsosurfaceMask(id, isosurfId)
984  elif attrb == 'transp':
985  self._display.UnsetIsosurfaceTransp(id, isosurfId)
986  elif attrb == 'emit':
987  self._display.UnsetIsosurfaceEmit(id, isosurfId)
988  else:
989  if type(value) == type('') and \
990  len(value) <= 0: # ignore empty values (TODO: warning)
991  continue
992  elif attrb == 'color':
993  self._display.SetIsosurfaceColor(id, isosurfId, map, str(value))
994  elif attrb == 'mask':
995  # TODO: invert mask
996  # TODO: broken in NVIZ
997  self._display.SetIsosurfaceMask(id, isosurfId, False, str(value))
998  elif attrb == 'transp':
999  self._display.SetIsosurfaceTransp(id, isosurfId, map, str(value))
1000  elif attrb == 'shine':
1001  self._display.SetIsosurfaceShine(id, isosurfId, map, str(value))
1002  elif attrb == 'emit':
1003  self._display.SetIsosurfaceEmit(id, isosurfId, map, str(value))
1004  isosurf[attrb].pop('update')
1005  isosurfId += 1
1006 
1007  def UpdateVectorProperties(self, id, data, type):
1008  """!Update vector layer properties
1009 
1010  @param id layer id
1011  @param data properties
1012  @param type lines/points
1013  """
1014  if type == 'points':
1015  self.UpdateVectorPointsProperties(id, data[type])
1016  else:
1017  self.UpdateVectorLinesProperties(id, data[type])
1018 
1019  def UpdateVectorLinesProperties(self, id, data):
1020  """!Update vector line map object properties"""
1021  # mode
1022  if 'update' in data['color'] or \
1023  'update' in data['width'] or \
1024  'update' in data['mode']:
1025  width = data['width']['value']
1026  color = data['color']['value']
1027  if data['mode']['type'] == 'flat':
1028  flat = True
1029  if 'surface' in data:
1030  data.pop('surface')
1031  else:
1032  flat = False
1033 
1034  self._display.SetVectorLineMode(id, color,
1035  width, flat)
1036 
1037  if 'update' in data['color']:
1038  data['color'].pop('update')
1039  if 'update' in data['width']:
1040  data['width'].pop('update')
1041  if 'update' in data['mode']:
1042  data['mode'].pop('update')
1043 
1044  # height
1045  if 'update' in data['height']:
1046  self._display.SetVectorLineHeight(id,
1047  data['height']['value'])
1048  data['height'].pop('update')
1049 
1050  # surface
1051  if 'update' in data['mode']:
1052  sid = self.GetLayerId(type = 'raster', name = data['mode']['surface'])
1053  if sid > -1:
1054  self._display.SetVectorLineSurface(id, sid)
1055 
1056  data['mode'].pop('update')
1057 
1058  def UpdateVectorPointsProperties(self, id, data):
1059  """!Update vector point map object properties"""
1060  if 'update' in data['size'] or \
1061  'update' in data['width'] or \
1062  'update' in data['marker'] or \
1063  'update' in data['color']:
1064  ret = self._display.SetVectorPointMode(id, data['color']['value'],
1065  data['width']['value'], float(data['size']['value']),
1066  data['marker']['value'] + 1)
1067 
1068  error = None
1069  if ret == -1:
1070  error = _("Vector point layer not found (id = %d)") % id
1071  elif ret == -2:
1072  error = _("Unable to set data layer properties (id = %d)") % id
1073 
1074  if error:
1075  raise gcmd.GException(_("Setting data layer properties failed.\n\n%s") % error)
1076 
1077  for prop in ('size', 'width', 'marker', 'color'):
1078  if 'update' in data[prop]:
1079  data[prop].pop('update')
1080 
1081  # height
1082  if 'update' in data['height']:
1083  self._display.SetVectorPointHeight(id,
1084  data['height']['value'])
1085  data['height'].pop('update')
1086 
1087  # surface
1088  if 'update' in data['mode']:
1089  sid = self.GetLayerId(type = 'raster', name = data['mode']['surface'])
1090  if sid > -1:
1091  self._display.SetVectorPointSurface(id, sid)
1092 
1093  data['mode'].pop('update')
1094 
1095  def GetLayerNames(self, type):
1096  """!Return list of map layer names of given type"""
1097  layerName = []
1098 
1099  for item in self.layers:
1100  mapLayer = self.tree.GetPyData(item)[0]['maplayer']
1101  if type != mapLayer.GetType():
1102  continue
1103 
1104  layerName.append(mapLayer.GetName())
1105 
1106  return layerName
1107 
1108  def GetLayerId(self, type, name):
1109  """!Get layer object id or -1"""
1110  if len(name) < 1:
1111  return -1
1112 
1113  for item in self.layers:
1114  mapLayer = self.tree.GetPyData(item)[0]['maplayer']
1115  if type != mapLayer.GetType() or \
1116  name != mapLayer.GetName():
1117  continue
1118 
1119  data = self.tree.GetPyData(item)[0]['nviz']
1120 
1121  if type == 'raster':
1122  return data['surface']['object']['id']
1123  elif type == 'vpoint':
1124  return data['vector']['points']['object']['id']
1125  elif type == 'vline':
1126  return data['vector']['lines']['object']['id']
1127  elif type == '3d-raster':
1128  return data['volume']['object']['id']
1129 
1130  return -1
1131 
1132  def SaveToFile(self, FileName, FileType, width, height):
1133  """!This draws the DC to a buffer that can be saved to a file.
1134 
1135  @todo fix BufferedPaintDC
1136 
1137  @param FileName file name
1138  @param FileType type of bitmap
1139  @param width image width
1140  @param height image height
1141  """
1142  self._display.SaveToFile(FileName, width, height)
1143 
1144  # pbuffer = wx.EmptyBitmap(max(1, self.Map.width), max(1, self.Map.height))
1145  # dc = wx.BufferedPaintDC(self, pbuffer)
1146  # dc.Clear()
1147  # self.SetCurrent()
1148  # self._display.Draw(False, -1)
1149  # pbuffer.SaveFile(FileName, FileType)
1150  # self.SwapBuffers()
1151 
1152  def GetDisplay(self):
1153  """!Get display instance"""
1154  return self._display
1155 
1156  def ZoomToMap(self):
1157  """!Reset view
1158  """
1159  self.lmgr.nviz.OnResetView(None)
1160