nviz_mapdisp.py 43 KB

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