nviz_mapdisp.py 45 KB

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