nviz_mapdisp.py 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196
  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 preferences import globalSettings as UserSettings
  26. from mapdisp import MapWindow as MapWindow
  27. from goutput import wxCmdOutput as wxCmdOutput
  28. sys.path.append(os.path.join(globalvar.ETCWXDIR, "nviz"))
  29. import grass6_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. # render mode
  59. self.render = { 'quick' : False,
  60. # do not render vector lines in quick mode
  61. 'vlines' : False,
  62. 'vpoints' : False }
  63. # list of loaded map layers
  64. self.layers = {}
  65. for type in ('raster', 'vlines', 'vpoints', '3d-raster'):
  66. self.layers[type] = {}
  67. self.layers[type]['name'] = []
  68. self.layers[type]['id'] = []
  69. #
  70. # create nviz instance
  71. #
  72. self.nvizThread = NvizThread(self.gismgr.goutput.cmd_stderr,
  73. self.parent.onRenderGauge,
  74. self.gismgr.goutput.cmd_output)
  75. self.nvizThread.start()
  76. time.sleep(.1)
  77. self.nvizClass = self.nvizThread.nvizClass
  78. #
  79. # set current display
  80. #
  81. self.nvizClass.SetDisplay(self)
  82. #
  83. # initialize mouse position
  84. #
  85. self.lastX = self.x = 30
  86. self.lastY = self.y = 30
  87. #
  88. # default values
  89. #
  90. self.view = copy.deepcopy(UserSettings.Get(group='nviz', key='view')) # copy
  91. self.iview = UserSettings.Get(group='nviz', key='view', internal=True)
  92. self.size = None
  93. self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
  94. self.Bind(wx.EVT_SIZE, self.OnSize)
  95. self.Bind(wx.EVT_PAINT, self.OnPaint)
  96. self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
  97. self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
  98. self.Bind(wx.EVT_MOTION, self.OnMouseAction)
  99. self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseAction)
  100. self.Bind(EVT_UPDATE_PROP, self.UpdateMapObjProperties)
  101. self.Bind(EVT_UPDATE_VIEW, self.UpdateView)
  102. def OnEraseBackground(self, event):
  103. pass # do nothing, to avoid flashing on MSW
  104. def OnSize(self, event):
  105. self.size = self.parent.GetClientSize()
  106. if self.GetContext():
  107. Debug.msg(3, "GLCanvas.OnPaint(): w=%d, h=%d" % \
  108. (self.size.width, self.size.height))
  109. self.SetCurrent()
  110. self.nvizClass.ResizeWindow(self.size.width,
  111. self.size.height)
  112. event.Skip()
  113. def OnPaint(self, event):
  114. Debug.msg(3, "GLCanvas.OnPaint()")
  115. dc = wx.PaintDC(self)
  116. self.SetCurrent()
  117. if not self.init:
  118. self.nvizClass.InitView()
  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.layers['raster']['name'])
  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. wx.Yield()
  197. self.nvizClass.Draw(False, -1)
  198. elif self.render['quick'] is True:
  199. # quick
  200. mode = wxnviz.DRAW_QUICK_SURFACE | wxnviz.DRAW_QUICK_VOLUME
  201. if self.render['vlines']:
  202. mode |= wxnviz.DRAW_QUICK_VLINES
  203. if self.render['vpoints']:
  204. mode |= wxnviz.DRAW_QUICK_VPOINTS
  205. self.nvizClass.Draw(True, mode)
  206. else: # None -> reuse last rendered image
  207. pass # TODO
  208. self.SwapBuffers()
  209. stop = time.clock()
  210. if self.render['quick'] is False:
  211. self.parent.onRenderGauge.SetValue(2)
  212. # hide process bar
  213. self.parent.onRenderGauge.Hide()
  214. #
  215. # update statusbar
  216. #
  217. # self.parent.StatusbarUpdate()
  218. Debug.msg(3, "GLWindow.UpdateMap(): quick=%d, -> time=%g" % \
  219. (self.render['quick'], (stop-start)))
  220. # print stop-start
  221. def EraseMap(self):
  222. """
  223. Erase the canvas
  224. """
  225. self.nvizClass.EraseMap()
  226. self.SwapBuffers()
  227. def IsLoaded(self, item):
  228. """Check if layer (item) is already loaded
  229. @param item layer item
  230. """
  231. layer = self.tree.GetPyData(item)[0]['maplayer']
  232. data = self.tree.GetPyData(item)[0]['nviz']
  233. if not data:
  234. return 0
  235. if layer.type == 'raster':
  236. if not data['surface'].has_key('object'):
  237. return 0
  238. elif layer.type == 'vector':
  239. if not data['vlines'].has_key('object') and \
  240. not data['points'].has_key('object'):
  241. return 0
  242. return 1
  243. def LoadDataLayers(self):
  244. """Load raster/vector from current layer tree
  245. @todo volumes
  246. """
  247. listOfItems = []
  248. # load raster & vector maps
  249. item = self.tree.GetFirstChild(self.tree.root)[0]
  250. while item and item.IsOk():
  251. type = self.tree.GetPyData(item)[0]['type']
  252. if not item.IsChecked() or \
  253. type not in ('raster', 'vector', '3d-raster'):
  254. item = self.tree.GetNextSibling(item)
  255. continue
  256. listOfItems.append(item)
  257. item = self.tree.GetNextSibling(item)
  258. start = time.time()
  259. while(len(listOfItems) > 0):
  260. item = listOfItems.pop()
  261. type = self.tree.GetPyData(item)[0]['type']
  262. try:
  263. if type == 'raster':
  264. self.LoadRaster(item)
  265. elif type == '3d-raster':
  266. self.LoadRaster3d(item)
  267. except gcmd.NvizError, e:
  268. print >> sys.stderr, "Nviz:" + e.message
  269. try:
  270. if type == 'vector':
  271. data = self.tree.GetPyData(item)[0]['nviz']
  272. vecType = []
  273. if data and data.has_key('vector'):
  274. for v in ('lines', 'points'):
  275. if data['vector'][v]:
  276. vecType.append(v)
  277. self.LoadVector(item, vecType)
  278. except gcmd.NvizError, e:
  279. print >> sys.stderr, "Nviz:" + e.message
  280. stop = time.time()
  281. Debug.msg(3, "GLWindow.LoadDataLayers(): time=%f" % (stop-start))
  282. # print stop - start
  283. def SetMapObjProperties(self, item, id, nvizType):
  284. """Set map object properties
  285. Properties must be afterwards updated by
  286. UpdateMapObjProperties().
  287. @param item layer item
  288. @param id nviz layer id (or -1)
  289. @param nvizType nviz data type (surface, points, vector)
  290. """
  291. type = self.tree.GetPyData(item)[0]['maplayer'].type
  292. # reference to original layer properties (can be None)
  293. data = self.tree.GetPyData(item)[0]['nviz']
  294. if data is None:
  295. # init data structure
  296. self.tree.GetPyData(item)[0]['nviz'] = {}
  297. data = self.tree.GetPyData(item)[0]['nviz']
  298. if type == 'raster':
  299. data[nvizType] = {}
  300. for sec in ('attribute', 'draw', 'mask', 'position'):
  301. data[nvizType][sec] = {}
  302. # reset to default properties
  303. self.SetSurfaceDefaultProp(data[nvizType])
  304. elif type == 'vector':
  305. data['vector'] = {}
  306. for sec in ('lines', 'points'):
  307. data['vector'][sec] = {}
  308. # reset to default properties (lines/points)
  309. self.SetVectorDefaultProp(data['vector'])
  310. elif type == '3d-raster':
  311. data[nvizType] = {}
  312. for sec in ('attribute', 'draw', 'position'):
  313. data[nvizType][sec] = {}
  314. for sec in ('isosurface', 'slice'):
  315. data[nvizType][sec] = []
  316. # reset to default properties
  317. self.SetVolumeDefaultProp(data[nvizType])
  318. else:
  319. # check data
  320. if type == 'vector':
  321. if not data['vector']['lines']:
  322. self.SetVectorLinesDefaultProp(data['vector']['lines'])
  323. if not data['vector']['points']:
  324. self.SetVectorPointsDefaultProp(data['vector']['points'])
  325. # set updates
  326. for sec in data.keys():
  327. for sec1 in data[sec].keys():
  328. for sec2 in data[sec][sec1].keys():
  329. if sec2 not in ('object', 'all'):
  330. data[sec][sec1][sec2]['update'] = None
  331. event = wxUpdateProperties(data=data)
  332. wx.PostEvent(self, event)
  333. # set id
  334. if id > 0:
  335. if type in ('raster', '3d-raster'):
  336. data[nvizType]['object'] = { 'id' : id,
  337. 'init' : False }
  338. elif type == 'vector':
  339. data['vector'][nvizType]['object'] = { 'id' : id,
  340. 'init' : False }
  341. return data
  342. def LoadRaster(self, item):
  343. """Load 2d raster map and set surface attributes
  344. @param layer item
  345. """
  346. return self._loadRaster(item)
  347. def LoadRaster3d(self, item):
  348. """Load 3d raster map and set surface attributes
  349. @param layer item
  350. """
  351. return self._loadRaster(item)
  352. def _loadRaster(self, item):
  353. """Load 2d/3d raster map and set its attributes
  354. @param layer item
  355. """
  356. layer = self.tree.GetPyData(item)[0]['maplayer']
  357. if layer.type not in ('raster', '3d-raster'):
  358. return
  359. if layer.type == 'raster':
  360. id = self.nvizClass.LoadSurface(str(layer.name), None, None)
  361. nvizType = 'surface'
  362. errorMsg = _("Loading raster map")
  363. elif layer.type == '3d-raster':
  364. id = self.nvizClass.LoadVolume(str(layer.name), None, None)
  365. nvizType = 'volume'
  366. errorMsg = _("Loading 3d raster map")
  367. else:
  368. id = -1
  369. if id < 0:
  370. if layer.type in ('raster', '3d-raster'):
  371. print >> sys.stderr, "Nviz:" + "%s <%s> %s" % (errorMsg, layer.name, _("failed"))
  372. else:
  373. print >> sys.stderr, "Nviz:" + _("Unsupported layer type '%s'") % layer.type
  374. self.layers[layer.type]['name'].append(layer.name)
  375. self.layers[layer.type]['id'].append(id)
  376. # set default/workspace layer properties
  377. data = self.SetMapObjProperties(item, id, nvizType)
  378. # update properties
  379. event = wxUpdateProperties(data=data)
  380. wx.PostEvent(self, event)
  381. # update tools window
  382. if hasattr(self.parent, "nvizToolWin") and \
  383. item == self.GetSelectedLayer(type='item'):
  384. toolWin = self.parent.nvizToolWin
  385. if layer.type == 'raster':
  386. win = toolWin.FindWindowById( \
  387. toolWin.win['vector']['lines']['surface'])
  388. win.SetItems(self.layers[layer.type]['name'])
  389. toolWin.UpdatePage(nvizType)
  390. toolWin.SetPage(nvizType)
  391. return id
  392. def UnloadRaster(self, item):
  393. """Unload 2d raster map
  394. @param layer item
  395. """
  396. return self._unloadRaster(item)
  397. def UnloadRaster3d(self, item):
  398. """Unload 3d raster map
  399. @param layer item
  400. """
  401. return self._unloadRaster(item)
  402. def _unloadRaster(self, item):
  403. """Unload 2d/3d raster map
  404. @param item layer item
  405. """
  406. layer = self.tree.GetPyData(item)[0]['maplayer']
  407. if layer.type not in ('raster', '3d-raster'):
  408. return
  409. data = self.tree.GetPyData(item)[0]['nviz']
  410. if layer.type == 'raster':
  411. nvizType = 'surface'
  412. unloadFn = self.nvizClass.UnloadSurface
  413. errorMsg = _("Unable to unload raster map")
  414. successMsg = _("Raster map")
  415. else:
  416. nvizType = 'volume'
  417. unloadFn = self.nvizClass.UnloadVolume
  418. errorMsg = _("Unable to unload 3d raster map")
  419. successMsg = _("3d raster map")
  420. id = data[nvizType]['object']['id']
  421. if unloadFn(id) == 0:
  422. print >> sys.stderr, "Nviz:" + "%s <%s>" % (errorMsg, layer.name)
  423. else:
  424. print "Nviz:" + "%s <%s> %s" % (successMsg, layer.name, _("unloaded successfully"))
  425. data[nvizType].pop('object')
  426. idx = self.layers[layer.type]['id'].index(id)
  427. del self.layers[layer.type]['name'][idx]
  428. del self.layers[layer.type]['id'][idx]
  429. # update tools window
  430. if hasattr(self.parent, "nvizToolWin") and \
  431. layer.type == 'raster':
  432. toolWin = self.parent.nvizToolWin
  433. win = toolWin.FindWindowById( \
  434. toolWin.win['vector']['lines']['surface'])
  435. win.SetItems(self.layers[layer.type]['name'])
  436. # remove surface page
  437. if toolWin.notebook.GetSelection() == toolWin.page[nvizType]['id']:
  438. toolWin.notebook.RemovePage(toolWin.page[nvizType]['id'])
  439. toolWin.page[nvizType]['id'] = -1
  440. toolWin.page['settings']['id'] = 1
  441. def LoadVector(self, item, vecType=None):
  442. """Load 2D or 3D vector map overlay
  443. @param item layer item
  444. @param vecType vector type (lines / points)
  445. """
  446. layer = self.tree.GetPyData(item)[0]['maplayer']
  447. if layer.type != 'vector':
  448. return
  449. if vecType is None:
  450. # load data type by default
  451. vecType = []
  452. for v in ('lines', 'points'):
  453. if UserSettings.Get(group='nviz', key='vector',
  454. subkey=[v, 'show']):
  455. vecType.append(v)
  456. # set default properties
  457. self.SetMapObjProperties(item, -1, 'lines')
  458. self.SetMapObjProperties(item, -1, 'points')
  459. id = -1
  460. for type in vecType:
  461. if type == 'lines':
  462. id = self.nvizClass.LoadVector(str(layer.name), False)
  463. else:
  464. id = self.nvizClass.LoadVector(str(layer.name), True)
  465. if id < 0:
  466. print >> sys.stderr, "Nviz:" + _("Loading vector map <%(name)s> (%(type)s) failed") % \
  467. { 'name' : layer.name, 'type' : type }
  468. continue
  469. # update layer properties
  470. self.SetMapObjProperties(item, id, type)
  471. self.layers['v' + type]['name'].append(layer.name)
  472. self.layers['v' + type]['id'].append(id)
  473. # update properties
  474. data = self.tree.GetPyData(item)[0]['nviz']
  475. event = wxUpdateProperties(data=data)
  476. wx.PostEvent(self, event)
  477. # update tools window
  478. if hasattr(self.parent, "nvizToolWin") and \
  479. item == self.GetSelectedLayer(type='item'):
  480. toolWin = self.parent.nvizToolWin
  481. toolWin.UpdatePage('vector')
  482. toolWin.SetPage('vector')
  483. return id
  484. def UnloadVector(self, item, vecType=None):
  485. """Unload vector map overlay
  486. @param item layer item
  487. @param vecType vector type (lines, points)
  488. """
  489. layer = self.tree.GetPyData(item)[0]['maplayer']
  490. data = self.tree.GetPyData(item)[0]['nviz']['vector']
  491. if vecType is None:
  492. vecType = []
  493. for v in ('lines', 'points'):
  494. if UserSettings.Get(group='nviz', key='vector',
  495. subkey=[v, 'show']):
  496. vecType.append(v)
  497. for vtype in vecType:
  498. if not data[vtype].has_key('object'):
  499. continue
  500. id = data[vtype]['object']['id']
  501. if vtype == 'lines':
  502. ret = self.nvizClass.UnloadVector(id, False)
  503. else:
  504. ret = self.nvizClass.UnloadVector(id, True)
  505. if ret == 0:
  506. print >> sys.stderr, "Nviz:" + _("Unable to unload vector map <%(name)s> (%(type)s)") % \
  507. { 'name': layer.name, 'type' : vtype }
  508. else:
  509. print "Nviz:" + _("Vector map <%(name)s> (%(type)s) unloaded successfully") % \
  510. { 'name' : layer.name, 'type' : vtype }
  511. data[vtype].pop('object')
  512. idx = self.layers['v' + vtype]['id'].index(id)
  513. del self.layers['v' + vtype]['name'][idx]
  514. del self.layers['v' + vtype]['id'][idx]
  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. if len(self.layers['raster']['name']) > 0:
  668. type = 'surface'
  669. map = self.layers['raster']['name'][0]
  670. else:
  671. type = 'flat'
  672. map = None
  673. data['mode'] = {}
  674. data['mode']['type'] = type
  675. data['mode']['update'] = None
  676. if map:
  677. data['mode']['surface'] = map
  678. # height
  679. data['height'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  680. subkey=['lines', 'height']) }
  681. if data.has_key('object'):
  682. for attrb in ('color', 'width', 'mode', 'height'):
  683. data[attrb]['update'] = None
  684. def SetVectorPointsDefaultProp(self, data):
  685. """Set default vector properties -- points"""
  686. # size
  687. data['size'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  688. subkey=['points', 'size']) }
  689. # width
  690. data['width'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  691. subkey=['points', 'width']) }
  692. # marker
  693. data['marker'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  694. subkey=['points', 'marker']) }
  695. # color
  696. value = UserSettings.Get(group='nviz', key='vector',
  697. subkey=['points', 'color'])
  698. color = str(value[0]) + ':' + str(value[1]) + ':' + str(value[2])
  699. data['color'] = { 'value' : color }
  700. # mode
  701. data['mode'] = { 'type' : 'surface',
  702. 'surface' : '', }
  703. if len(self.layers['raster']['name']) > 0:
  704. data['mode']['surface'] = self.layers['raster']['name'][0]
  705. # height
  706. data['height'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  707. subkey=['points', 'height']) }
  708. if data.has_key('object'):
  709. for attrb in ('size', 'width', 'marker',
  710. 'color', 'surface', 'height'):
  711. data[attrb]['update'] = None
  712. def Reset(self):
  713. """Reset (unload data)"""
  714. self.nvizClass.Reset()
  715. self.init = False
  716. def OnZoomToMap(self, event):
  717. """
  718. Set display extents to match selected raster
  719. or vector map or volume.
  720. @todo vector, volume
  721. """
  722. layer = self.GetSelectedLayer()
  723. if layer is None:
  724. return
  725. Debug.msg (3, "GLWindow.OnZoomToMap(): layer=%s, type=%s" % \
  726. (layer.name, layer.type))
  727. self.nvizClass.SetViewportDefault()
  728. def ResetView(self):
  729. """Reset to default view"""
  730. self.view['z-exag']['value'], \
  731. self.iview['height']['value'], \
  732. self.iview['height']['min'], \
  733. self.iview['height']['max'] = self.nvizClass.SetViewDefault()
  734. self.view['pos']['x'] = UserSettings.Get(group='nviz', key='view',
  735. subkey=('pos', 'x'))
  736. self.view['pos']['y'] = UserSettings.Get(group='nviz', key='view',
  737. subkey=('pos', 'x'))
  738. self.view['persp']['value'] = UserSettings.Get(group='nviz', key='view',
  739. subkey=('persp', 'value'))
  740. self.view['twist']['value'] = UserSettings.Get(group='nviz', key='view',
  741. subkey=('twist', 'value'))
  742. event = wxUpdateView(zExag=False)
  743. wx.PostEvent(self, event)
  744. def UpdateMapObjProperties(self, event):
  745. """Generic method to update data layer properties"""
  746. data = event.data
  747. if data.has_key('surface'):
  748. id = data['surface']['object']['id']
  749. self.UpdateSurfaceProperties(id, data['surface'])
  750. # -> initialized
  751. data['surface']['object']['init'] = True
  752. elif data.has_key('volume'):
  753. id = data['volume']['object']['id']
  754. self.UpdateVolumeProperties(id, data['volume'])
  755. # -> initialized
  756. data['volume']['object']['init'] = True
  757. elif data.has_key('vector'):
  758. for type in ('lines', 'points'):
  759. if data['vector'][type].has_key('object'):
  760. id = data['vector'][type]['object']['id']
  761. self.UpdateVectorProperties(id, data['vector'], type)
  762. # -> initialized
  763. data['vector'][type]['object']['init'] = True
  764. def UpdateSurfaceProperties(self, id, data):
  765. """Update surface map object properties"""
  766. # surface attributes
  767. for attrb in ('topo', 'color', 'mask',
  768. 'transp', 'shine', 'emit'):
  769. if not data['attribute'].has_key(attrb) or \
  770. not data['attribute'][attrb].has_key('update'):
  771. continue
  772. map = data['attribute'][attrb]['map']
  773. value = data['attribute'][attrb]['value']
  774. if map is None: # unset
  775. # only optional attributes
  776. if attrb == 'mask':
  777. # TODO: invert mask
  778. # TODO: broken in NVIZ
  779. self.nvizClass.UnsetSurfaceMask(id)
  780. elif attrb == 'transp':
  781. self.nvizClass.UnsetSurfaceTransp(id)
  782. elif attrb == 'emit':
  783. self.nvizClass.UnsetSurfaceEmit(id)
  784. else:
  785. if type(value) == type('') and \
  786. len(value) <= 0: # ignore empty values (TODO: warning)
  787. continue
  788. if attrb == 'topo':
  789. self.nvizClass.SetSurfaceTopo(id, map, str(value))
  790. elif attrb == 'color':
  791. self.nvizClass.SetSurfaceColor(id, map, str(value))
  792. elif attrb == 'mask':
  793. # TODO: invert mask
  794. # TODO: broken in NVIZ
  795. self.nvizClass.SetSurfaceMask(id, False, str(value))
  796. elif attrb == 'transp':
  797. self.nvizClass.SetSurfaceTransp(id, map, str(value))
  798. elif attrb == 'shine':
  799. self.nvizClass.SetSurfaceShine(id, map, str(value))
  800. elif attrb == 'emit':
  801. self.nvizClass.SetSurfaceEmit(id, map, str(value))
  802. data['attribute'][attrb].pop('update')
  803. # draw res
  804. if data['draw']['resolution'].has_key('update'):
  805. coarse = data['draw']['resolution']['coarse']
  806. fine = data['draw']['resolution']['fine']
  807. if data['draw']['all']:
  808. self.nvizClass.SetSurfaceRes(-1, fine, coarse)
  809. else:
  810. self.nvizClass.SetSurfaceRes(id, fine, coarse)
  811. data['draw']['resolution'].pop('update')
  812. # draw style
  813. if data['draw']['mode'].has_key('update'):
  814. if data['draw']['mode']['value'] < 0: # need to calculate
  815. data['draw']['mode']['value'] = \
  816. self.GetDrawMode(mode=data['draw']['mode']['desc']['mode'],
  817. style=data['draw']['mode']['desc']['style'],
  818. shade=data['draw']['mode']['desc']['shading'],
  819. string=True)
  820. style = data['draw']['mode']['value']
  821. if data['draw']['all']:
  822. self.nvizClass.SetSurfaceStyle(-1, style)
  823. else:
  824. self.nvizClass.SetSurfaceStyle(id, style)
  825. data['draw']['mode'].pop('update')
  826. # wire color
  827. if data['draw']['wire-color'].has_key('update'):
  828. color = data['draw']['wire-color']['value']
  829. if data['draw']['all']:
  830. self.nvizClass.SetWireColor(-1, str(color))
  831. else:
  832. self.nvizClass.SetWireColor(id, str(color))
  833. data['draw']['wire-color'].pop('update')
  834. # position
  835. if data['position'].has_key('update'):
  836. x = data['position']['x']
  837. y = data['position']['y']
  838. z = data['position']['z']
  839. self.nvizClass.SetSurfacePosition(id, x, y, z)
  840. data['position'].pop('update')
  841. def UpdateVolumeProperties(self, id, data, isosurfId=None):
  842. """Update volume (isosurface/slice) map object properties"""
  843. #
  844. # draw
  845. #
  846. if data['draw']['resolution'].has_key('update'):
  847. self.nvizClass.SetIsosurfaceRes(id, data['draw']['resolution']['value'])
  848. data['draw']['resolution'].pop('update')
  849. if data['draw']['shading'].has_key('update'):
  850. if data['draw']['shading']['value'] < 0: # need to calculate
  851. data['draw']['shading']['value'] = \
  852. self.GetDrawMode(shade=data['draw']['shading'],
  853. string=False)
  854. data['draw']['shading'].pop('update')
  855. #
  856. # isosurface attributes
  857. #
  858. isosurfId = 0
  859. for isosurf in data['isosurface']:
  860. for attrb in ('color', 'mask',
  861. 'transp', 'shine', 'emit'):
  862. if not isosurf.has_key(attrb) or \
  863. not isosurf[attrb].has_key('update'):
  864. continue
  865. map = isosurf[attrb]['map']
  866. value = isosurf[attrb]['value']
  867. if map is None: # unset
  868. # only optional attributes
  869. if attrb == 'mask':
  870. # TODO: invert mask
  871. # TODO: broken in NVIZ
  872. self.nvizClass.UnsetIsosurfaceMask(id, isosurfId)
  873. elif attrb == 'transp':
  874. self.nvizClass.UnsetIsosurfaceTransp(id, isosurfId)
  875. elif attrb == 'emit':
  876. self.nvizClass.UnsetIsosurfaceEmit(id, isosurfId)
  877. else:
  878. if type(value) == type('') and \
  879. len(value) <= 0: # ignore empty values (TODO: warning)
  880. continue
  881. elif attrb == 'color':
  882. self.nvizClass.SetIsosurfaceColor(id, isosurfId, map, str(value))
  883. elif attrb == 'mask':
  884. # TODO: invert mask
  885. # TODO: broken in NVIZ
  886. self.nvizClass.SetIsosurfaceMask(id, isosurfId, False, str(value))
  887. elif attrb == 'transp':
  888. self.nvizClass.SetIsosurfaceTransp(id, isosurfId, map, str(value))
  889. elif attrb == 'shine':
  890. self.nvizClass.SetIsosurfaceShine(id, isosurfId, map, str(value))
  891. elif attrb == 'emit':
  892. self.nvizClass.SetIsosurfaceEmit(id, isosurfId, map, str(value))
  893. isosurf[attrb].pop('update')
  894. isosurfId += 1
  895. def UpdateVectorProperties(self, id, data, type):
  896. """Update vector layer properties
  897. @param id layer id
  898. @param data properties
  899. @param type lines/points
  900. """
  901. if type == 'points':
  902. self.UpdateVectorPointsProperties(id, data[type])
  903. else:
  904. self.UpdateVectorLinesProperties(id, data[type])
  905. def UpdateVectorLinesProperties(self, id, data):
  906. """Update vector line map object properties"""
  907. # mode
  908. if data['color'].has_key('update') or \
  909. data['width'].has_key('update') or \
  910. data['mode'].has_key('update'):
  911. width = data['width']
  912. color = data['color']
  913. if data['mode']['type'] == 'flat':
  914. flat = True
  915. if data.has_key('surface'):
  916. data.pop('surface')
  917. else:
  918. flat = False
  919. if not 'vector:lines:surface' in update:
  920. update.append('vector:lines:surface')
  921. self.nvizClass.SetVectorLineMode(id, color,
  922. width, flat)
  923. if data['color'].has_key('update'):
  924. data['color'].pop('update')
  925. if data['width'].has_key('update'):
  926. data['width'].pop('update')
  927. if data['mode'].has_key('update'):
  928. data['mode'].pop('update')
  929. # height
  930. if data['height'].has_key('update'):
  931. self.nvizClass.SetVectorLineHeight(id,
  932. data['height'])
  933. data['height'].pop('update')
  934. # surface
  935. if data['mode'].has_key('update'):
  936. idx = self.layers['raster']['name'].index(data['mode']['surface'])
  937. if idx > -1:
  938. self.nvizClass.SetVectorLineSurface(id,
  939. self.layers['raster']['id'][idx])
  940. data['mode'].pop('update')
  941. def UpdateVectorPointsProperties(self, id, data):
  942. """Update vector point map object properties"""
  943. if data['size'].has_key('update') or \
  944. data['width'].has_key('update') or \
  945. data['marker'].has_key('update') or \
  946. data['color'].has_key('update'):
  947. ret = self.nvizClass.SetVectorPointMode(id, data['color']['value'],
  948. data['width']['value'], float(data['size']['value']),
  949. data['marker']['value'] + 1)
  950. error = None
  951. if ret == -1:
  952. error = _("Vector point layer not found (id=%d)") % id
  953. elif ret == -2:
  954. error = _("Unable to set data layer properties (id=%d)") % id
  955. if error:
  956. raise gcmd.NvizError(parent=self.parent,
  957. message=_("Setting data layer properties failed.\n\n%s") % error)
  958. for prop in ('size', 'width', 'marker', 'color'):
  959. if data[prop].has_key('update'):
  960. data[prop].pop('update')
  961. # height
  962. if data['height'].has_key('update'):
  963. self.nvizClass.SetVectorPointHeight(id,
  964. data['height']['value'])
  965. data['height'].pop('update')
  966. # surface
  967. if data['mode'].has_key('update'):
  968. idx = self.layers['raster']['name'].index(data['mode']['surface'])
  969. if idx > -1:
  970. self.nvizClass.SetVectorPointSurface(id,
  971. self.layers['raster']['id'][idx])
  972. data['mode'].pop('update')