nviz_mapdisp.py 45 KB

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