nviz_mapdisp.py 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248
  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 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. 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 _GetDataLayers(self, item, litems):
  244. """Return get list of enabled map layers"""
  245. # load raster & vector maps
  246. while item and item.IsOk():
  247. type = self.tree.GetPyData(item)[0]['type']
  248. if type == 'group':
  249. subItem = self.tree.GetFirstChild(item)[0]
  250. self._GetDataLayers(subItem, litems)
  251. item = self.tree.GetNextSibling(item)
  252. if not item.IsChecked() or \
  253. type not in ('raster', 'vector', '3d-raster'):
  254. item = self.tree.GetNextSibling(item)
  255. continue
  256. litems.append(item)
  257. item = self.tree.GetNextSibling(item)
  258. def LoadDataLayers(self):
  259. """Load raster/vector from current layer tree
  260. @todo volumes
  261. """
  262. listOfItems = []
  263. item = self.tree.GetFirstChild(self.tree.root)[0]
  264. self._GetDataLayers(item, listOfItems)
  265. start = time.time()
  266. while(len(listOfItems) > 0):
  267. item = listOfItems.pop()
  268. type = self.tree.GetPyData(item)[0]['type']
  269. try:
  270. if type == 'raster':
  271. self.LoadRaster(item)
  272. elif type == '3d-raster':
  273. self.LoadRaster3d(item)
  274. except gcmd.NvizError, e:
  275. print >> sys.stderr, "Nviz:" + e.message
  276. try:
  277. if type == 'vector':
  278. data = self.tree.GetPyData(item)[0]['nviz']
  279. vecType = []
  280. if data and data.has_key('vector'):
  281. for v in ('lines', 'points'):
  282. if data['vector'][v]:
  283. vecType.append(v)
  284. self.LoadVector(item, vecType)
  285. except gcmd.NvizError, e:
  286. print >> sys.stderr, "Nviz:" + e.message
  287. stop = time.time()
  288. Debug.msg(3, "GLWindow.LoadDataLayers(): time=%f" % (stop-start))
  289. # print stop - start
  290. def SetMapObjProperties(self, item, id, nvizType):
  291. """Set map object properties
  292. Properties must be afterwards updated by
  293. UpdateMapObjProperties().
  294. @param item layer item
  295. @param id nviz layer id (or -1)
  296. @param nvizType nviz data type (surface, points, vector)
  297. """
  298. type = self.tree.GetPyData(item)[0]['maplayer'].type
  299. # reference to original layer properties (can be None)
  300. data = self.tree.GetPyData(item)[0]['nviz']
  301. if data is None:
  302. # init data structure
  303. self.tree.GetPyData(item)[0]['nviz'] = {}
  304. data = self.tree.GetPyData(item)[0]['nviz']
  305. if type == 'raster':
  306. data[nvizType] = {}
  307. for sec in ('attribute', 'draw', 'mask', 'position'):
  308. data[nvizType][sec] = {}
  309. # reset to default properties
  310. self.SetSurfaceDefaultProp(data[nvizType])
  311. elif type == 'vector':
  312. data['vector'] = {}
  313. for sec in ('lines', 'points'):
  314. data['vector'][sec] = {}
  315. # reset to default properties (lines/points)
  316. self.SetVectorDefaultProp(data['vector'])
  317. elif type == '3d-raster':
  318. data[nvizType] = {}
  319. for sec in ('attribute', 'draw', 'position'):
  320. data[nvizType][sec] = {}
  321. for sec in ('isosurface', 'slice'):
  322. data[nvizType][sec] = []
  323. # reset to default properties
  324. self.SetVolumeDefaultProp(data[nvizType])
  325. else:
  326. # check data
  327. if type == 'vector':
  328. if not data['vector']['lines']:
  329. self.SetVectorLinesDefaultProp(data['vector']['lines'])
  330. if not data['vector']['points']:
  331. self.SetVectorPointsDefaultProp(data['vector']['points'])
  332. # set updates
  333. for sec in data.keys():
  334. for sec1 in data[sec].keys():
  335. for sec2 in data[sec][sec1].keys():
  336. if sec2 != 'all':
  337. data[sec][sec1][sec2]['update'] = None
  338. event = wxUpdateProperties(data=data)
  339. wx.PostEvent(self, event)
  340. # set id
  341. if id > 0:
  342. if type in ('raster', '3d-raster'):
  343. data[nvizType]['object'] = { 'id' : id,
  344. 'init' : False }
  345. elif type == 'vector':
  346. data['vector'][nvizType]['object'] = { 'id' : id,
  347. 'init' : False }
  348. return data
  349. def LoadRaster(self, item):
  350. """Load 2d raster map and set surface attributes
  351. @param layer item
  352. """
  353. return self._loadRaster(item)
  354. def LoadRaster3d(self, item):
  355. """Load 3d raster map and set surface attributes
  356. @param layer item
  357. """
  358. return self._loadRaster(item)
  359. def _loadRaster(self, item):
  360. """Load 2d/3d raster map and set its attributes
  361. @param layer item
  362. """
  363. layer = self.tree.GetPyData(item)[0]['maplayer']
  364. if layer.type not in ('raster', '3d-raster'):
  365. return
  366. if layer.type == 'raster':
  367. id = self.nvizClass.LoadSurface(str(layer.name), None, None)
  368. nvizType = 'surface'
  369. errorMsg = _("Loading raster map")
  370. elif layer.type == '3d-raster':
  371. id = self.nvizClass.LoadVolume(str(layer.name), None, None)
  372. nvizType = 'volume'
  373. errorMsg = _("Loading 3d raster map")
  374. else:
  375. id = -1
  376. if id < 0:
  377. if layer.type in ('raster', '3d-raster'):
  378. print >> sys.stderr, "Nviz:" + "%s <%s> %s" % (errorMsg, layer.name, _("failed"))
  379. else:
  380. print >> sys.stderr, "Nviz:" + _("Unsupported layer type '%s'") % layer.type
  381. self.layers.append(item)
  382. # set default/workspace layer properties
  383. data = self.SetMapObjProperties(item, id, nvizType)
  384. # update properties
  385. event = wxUpdateProperties(data=data)
  386. wx.PostEvent(self, event)
  387. # update tools window
  388. if hasattr(self.parent, "nvizToolWin") and \
  389. item == self.GetSelectedLayer(type='item'):
  390. toolWin = self.parent.nvizToolWin
  391. if layer.type == 'raster':
  392. win = toolWin.FindWindowById( \
  393. toolWin.win['vector']['lines']['surface'])
  394. win.SetItems(self.GetLayerNames(layer.type))
  395. toolWin.UpdatePage(nvizType)
  396. toolWin.SetPage(nvizType)
  397. return id
  398. def UnloadRaster(self, item):
  399. """Unload 2d raster map
  400. @param layer item
  401. """
  402. return self._unloadRaster(item)
  403. def UnloadRaster3d(self, item):
  404. """Unload 3d raster map
  405. @param layer item
  406. """
  407. return self._unloadRaster(item)
  408. def _unloadRaster(self, item):
  409. """Unload 2d/3d raster map
  410. @param item layer item
  411. """
  412. layer = self.tree.GetPyData(item)[0]['maplayer']
  413. if layer.type not in ('raster', '3d-raster'):
  414. return
  415. data = self.tree.GetPyData(item)[0]['nviz']
  416. if layer.type == 'raster':
  417. nvizType = 'surface'
  418. unloadFn = self.nvizClass.UnloadSurface
  419. errorMsg = _("Unable to unload raster map")
  420. successMsg = _("Raster map")
  421. else:
  422. nvizType = 'volume'
  423. unloadFn = self.nvizClass.UnloadVolume
  424. errorMsg = _("Unable to unload 3d raster map")
  425. successMsg = _("3d raster map")
  426. id = data[nvizType]['object']['id']
  427. if unloadFn(id) == 0:
  428. print >> sys.stderr, "Nviz:" + "%s <%s>" % (errorMsg, layer.name)
  429. else:
  430. print "Nviz:" + "%s <%s> %s" % (successMsg, layer.name, _("unloaded successfully"))
  431. data[nvizType].pop('object')
  432. self.layers.remove(item)
  433. # update tools window
  434. if hasattr(self.parent, "nvizToolWin") and \
  435. layer.type == 'raster':
  436. toolWin = self.parent.nvizToolWin
  437. win = toolWin.FindWindowById( \
  438. toolWin.win['vector']['lines']['surface'])
  439. win.SetItems(self.GetLayerNames(layer.type))
  440. # remove surface page
  441. if toolWin.notebook.GetSelection() == toolWin.page[nvizType]['id']:
  442. toolWin.notebook.RemovePage(toolWin.page[nvizType]['id'])
  443. toolWin.page[nvizType]['id'] = -1
  444. toolWin.page['settings']['id'] = 1
  445. def LoadVector(self, item, vecType=None):
  446. """Load 2D or 3D vector map overlay
  447. @param item layer item
  448. @param vecType vector type (lines / points)
  449. """
  450. layer = self.tree.GetPyData(item)[0]['maplayer']
  451. if layer.type != 'vector':
  452. return
  453. if vecType is None:
  454. # load data type by default
  455. vecType = []
  456. for v in ('lines', 'points'):
  457. if UserSettings.Get(group='nviz', key='vector',
  458. subkey=[v, 'show']):
  459. vecType.append(v)
  460. # set default properties
  461. self.SetMapObjProperties(item, -1, 'lines')
  462. self.SetMapObjProperties(item, -1, 'points')
  463. id = -1
  464. for type in vecType:
  465. if type == 'lines':
  466. id = self.nvizClass.LoadVector(str(layer.name), False)
  467. else:
  468. id = self.nvizClass.LoadVector(str(layer.name), True)
  469. if id < 0:
  470. print >> sys.stderr, "Nviz:" + _("Loading vector map <%(name)s> (%(type)s) failed") % \
  471. { 'name' : layer.name, 'type' : type }
  472. continue
  473. # update layer properties
  474. self.SetMapObjProperties(item, id, type)
  475. self.layers.append(item)
  476. # update properties
  477. data = self.tree.GetPyData(item)[0]['nviz']
  478. event = wxUpdateProperties(data=data)
  479. wx.PostEvent(self, event)
  480. # update tools window
  481. if hasattr(self.parent, "nvizToolWin") and \
  482. item == self.GetSelectedLayer(type='item'):
  483. toolWin = self.parent.nvizToolWin
  484. toolWin.UpdatePage('vector')
  485. toolWin.SetPage('vector')
  486. return id
  487. def UnloadVector(self, item, vecType=None):
  488. """Unload vector map overlay
  489. @param item layer item
  490. @param vecType vector type (lines, points)
  491. """
  492. layer = self.tree.GetPyData(item)[0]['maplayer']
  493. data = self.tree.GetPyData(item)[0]['nviz']['vector']
  494. if vecType is None:
  495. vecType = []
  496. for v in ('lines', 'points'):
  497. if UserSettings.Get(group='nviz', key='vector',
  498. subkey=[v, 'show']):
  499. vecType.append(v)
  500. for vtype in vecType:
  501. if not data[vtype].has_key('object'):
  502. continue
  503. id = data[vtype]['object']['id']
  504. if vtype == 'lines':
  505. ret = self.nvizClass.UnloadVector(id, False)
  506. else:
  507. ret = self.nvizClass.UnloadVector(id, True)
  508. if ret == 0:
  509. print >> sys.stderr, "Nviz:" + _("Unable to unload vector map <%(name)s> (%(type)s)") % \
  510. { 'name': layer.name, 'type' : vtype }
  511. else:
  512. print "Nviz:" + _("Vector map <%(name)s> (%(type)s) unloaded successfully") % \
  513. { 'name' : layer.name, 'type' : vtype }
  514. data[vtype].pop('object')
  515. self.layers.remove(id)
  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. rasters = self.GetLayerNames('raster')
  669. if len(rasters) > 0:
  670. type = 'surface'
  671. map = rasters[0]
  672. else:
  673. type = 'flat'
  674. map = None
  675. data['mode'] = {}
  676. data['mode']['type'] = type
  677. data['mode']['update'] = None
  678. if map:
  679. data['mode']['surface'] = map
  680. # height
  681. data['height'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  682. subkey=['lines', 'height']) }
  683. if data.has_key('object'):
  684. for attrb in ('color', 'width', 'mode', 'height'):
  685. data[attrb]['update'] = None
  686. def SetVectorPointsDefaultProp(self, data):
  687. """Set default vector properties -- points"""
  688. # size
  689. data['size'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  690. subkey=['points', 'size']) }
  691. # width
  692. data['width'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  693. subkey=['points', 'width']) }
  694. # marker
  695. data['marker'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  696. subkey=['points', 'marker']) }
  697. # color
  698. value = UserSettings.Get(group='nviz', key='vector',
  699. subkey=['points', 'color'])
  700. color = str(value[0]) + ':' + str(value[1]) + ':' + str(value[2])
  701. data['color'] = { 'value' : color }
  702. # mode
  703. data['mode'] = { 'type' : 'surface',
  704. 'surface' : '', }
  705. rasters = self.GetLayerNames('raster')
  706. if len(rasters) > 0:
  707. data['mode']['surface'] = rasters[0]
  708. # height
  709. data['height'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  710. subkey=['points', 'height']) }
  711. if data.has_key('object'):
  712. for attrb in ('size', 'width', 'marker',
  713. 'color', 'surface', 'height'):
  714. data[attrb]['update'] = None
  715. def Reset(self):
  716. """Reset (unload data)"""
  717. for item in self.layers:
  718. type = self.tree.GetPyData(item)[0]['maplayer'].type
  719. if type == 'raster':
  720. self.UnloadRaster(item)
  721. elif type == '3d-raster':
  722. self.UnloadRaster3d(item)
  723. elif type == 'vector':
  724. self.UnloadVector(item)
  725. self.init = False
  726. def OnZoomToMap(self, event):
  727. """
  728. Set display extents to match selected raster
  729. or vector map or volume.
  730. @todo vector, volume
  731. """
  732. layer = self.GetSelectedLayer()
  733. if layer is None:
  734. return
  735. Debug.msg (3, "GLWindow.OnZoomToMap(): layer=%s, type=%s" % \
  736. (layer.name, layer.type))
  737. self.nvizClass.SetViewportDefault()
  738. def ResetView(self):
  739. """Reset to default view"""
  740. self.view['z-exag']['value'], \
  741. self.iview['height']['value'], \
  742. self.iview['height']['min'], \
  743. self.iview['height']['max'] = self.nvizClass.SetViewDefault()
  744. self.view['pos']['x'] = UserSettings.Get(group='nviz', key='view',
  745. subkey=('pos', 'x'))
  746. self.view['pos']['y'] = UserSettings.Get(group='nviz', key='view',
  747. subkey=('pos', 'x'))
  748. self.view['persp']['value'] = UserSettings.Get(group='nviz', key='view',
  749. subkey=('persp', 'value'))
  750. self.view['twist']['value'] = UserSettings.Get(group='nviz', key='view',
  751. subkey=('twist', 'value'))
  752. event = wxUpdateView(zExag=False)
  753. wx.PostEvent(self, event)
  754. def UpdateMapObjProperties(self, event):
  755. """Generic method to update data layer properties"""
  756. data = event.data
  757. if data.has_key('surface'):
  758. id = data['surface']['object']['id']
  759. self.UpdateSurfaceProperties(id, data['surface'])
  760. # -> initialized
  761. data['surface']['object']['init'] = True
  762. elif data.has_key('volume'):
  763. id = data['volume']['object']['id']
  764. self.UpdateVolumeProperties(id, data['volume'])
  765. # -> initialized
  766. data['volume']['object']['init'] = True
  767. elif data.has_key('vector'):
  768. for type in ('lines', 'points'):
  769. if data['vector'][type].has_key('object'):
  770. id = data['vector'][type]['object']['id']
  771. self.UpdateVectorProperties(id, data['vector'], type)
  772. # -> initialized
  773. data['vector'][type]['object']['init'] = True
  774. def UpdateSurfaceProperties(self, id, data):
  775. """Update surface map object properties"""
  776. # surface attributes
  777. for attrb in ('topo', 'color', 'mask',
  778. 'transp', 'shine', 'emit'):
  779. if not data['attribute'].has_key(attrb) or \
  780. not data['attribute'][attrb].has_key('update'):
  781. continue
  782. map = data['attribute'][attrb]['map']
  783. value = data['attribute'][attrb]['value']
  784. if map is None: # unset
  785. # only optional attributes
  786. if attrb == 'mask':
  787. # TODO: invert mask
  788. # TODO: broken in NVIZ
  789. self.nvizClass.UnsetSurfaceMask(id)
  790. elif attrb == 'transp':
  791. self.nvizClass.UnsetSurfaceTransp(id)
  792. elif attrb == 'emit':
  793. self.nvizClass.UnsetSurfaceEmit(id)
  794. else:
  795. if type(value) == type('') and \
  796. len(value) <= 0: # ignore empty values (TODO: warning)
  797. continue
  798. if attrb == 'topo':
  799. self.nvizClass.SetSurfaceTopo(id, map, str(value))
  800. elif attrb == 'color':
  801. self.nvizClass.SetSurfaceColor(id, map, str(value))
  802. elif attrb == 'mask':
  803. # TODO: invert mask
  804. # TODO: broken in NVIZ
  805. self.nvizClass.SetSurfaceMask(id, False, str(value))
  806. elif attrb == 'transp':
  807. self.nvizClass.SetSurfaceTransp(id, map, str(value))
  808. elif attrb == 'shine':
  809. self.nvizClass.SetSurfaceShine(id, map, str(value))
  810. elif attrb == 'emit':
  811. self.nvizClass.SetSurfaceEmit(id, map, str(value))
  812. data['attribute'][attrb].pop('update')
  813. # draw res
  814. if data['draw']['resolution'].has_key('update'):
  815. coarse = data['draw']['resolution']['coarse']
  816. fine = data['draw']['resolution']['fine']
  817. if data['draw']['all']:
  818. self.nvizClass.SetSurfaceRes(-1, fine, coarse)
  819. else:
  820. self.nvizClass.SetSurfaceRes(id, fine, coarse)
  821. data['draw']['resolution'].pop('update')
  822. # draw style
  823. if data['draw']['mode'].has_key('update'):
  824. if data['draw']['mode']['value'] < 0: # need to calculate
  825. data['draw']['mode']['value'] = \
  826. self.GetDrawMode(mode=data['draw']['mode']['desc']['mode'],
  827. style=data['draw']['mode']['desc']['style'],
  828. shade=data['draw']['mode']['desc']['shading'],
  829. string=True)
  830. style = data['draw']['mode']['value']
  831. if data['draw']['all']:
  832. self.nvizClass.SetSurfaceStyle(-1, style)
  833. else:
  834. self.nvizClass.SetSurfaceStyle(id, style)
  835. data['draw']['mode'].pop('update')
  836. # wire color
  837. if data['draw']['wire-color'].has_key('update'):
  838. color = data['draw']['wire-color']['value']
  839. if data['draw']['all']:
  840. self.nvizClass.SetWireColor(-1, str(color))
  841. else:
  842. self.nvizClass.SetWireColor(id, str(color))
  843. data['draw']['wire-color'].pop('update')
  844. # position
  845. if data['position'].has_key('update'):
  846. x = data['position']['x']
  847. y = data['position']['y']
  848. z = data['position']['z']
  849. self.nvizClass.SetSurfacePosition(id, x, y, z)
  850. data['position'].pop('update')
  851. def UpdateVolumeProperties(self, id, data, isosurfId=None):
  852. """Update volume (isosurface/slice) map object properties"""
  853. #
  854. # draw
  855. #
  856. if data['draw']['resolution'].has_key('update'):
  857. self.nvizClass.SetIsosurfaceRes(id, data['draw']['resolution']['value'])
  858. data['draw']['resolution'].pop('update')
  859. if data['draw']['shading'].has_key('update'):
  860. if data['draw']['shading']['value'] < 0: # need to calculate
  861. data['draw']['shading']['value'] = \
  862. self.GetDrawMode(shade=data['draw']['shading'],
  863. string=False)
  864. data['draw']['shading'].pop('update')
  865. #
  866. # isosurface attributes
  867. #
  868. isosurfId = 0
  869. for isosurf in data['isosurface']:
  870. for attrb in ('color', 'mask',
  871. 'transp', 'shine', 'emit'):
  872. if not isosurf.has_key(attrb) or \
  873. not isosurf[attrb].has_key('update'):
  874. continue
  875. map = isosurf[attrb]['map']
  876. value = isosurf[attrb]['value']
  877. if map is None: # unset
  878. # only optional attributes
  879. if attrb == 'mask':
  880. # TODO: invert mask
  881. # TODO: broken in NVIZ
  882. self.nvizClass.UnsetIsosurfaceMask(id, isosurfId)
  883. elif attrb == 'transp':
  884. self.nvizClass.UnsetIsosurfaceTransp(id, isosurfId)
  885. elif attrb == 'emit':
  886. self.nvizClass.UnsetIsosurfaceEmit(id, isosurfId)
  887. else:
  888. if type(value) == type('') and \
  889. len(value) <= 0: # ignore empty values (TODO: warning)
  890. continue
  891. elif attrb == 'color':
  892. self.nvizClass.SetIsosurfaceColor(id, isosurfId, map, str(value))
  893. elif attrb == 'mask':
  894. # TODO: invert mask
  895. # TODO: broken in NVIZ
  896. self.nvizClass.SetIsosurfaceMask(id, isosurfId, False, str(value))
  897. elif attrb == 'transp':
  898. self.nvizClass.SetIsosurfaceTransp(id, isosurfId, map, str(value))
  899. elif attrb == 'shine':
  900. self.nvizClass.SetIsosurfaceShine(id, isosurfId, map, str(value))
  901. elif attrb == 'emit':
  902. self.nvizClass.SetIsosurfaceEmit(id, isosurfId, map, str(value))
  903. isosurf[attrb].pop('update')
  904. isosurfId += 1
  905. def UpdateVectorProperties(self, id, data, type):
  906. """Update vector layer properties
  907. @param id layer id
  908. @param data properties
  909. @param type lines/points
  910. """
  911. if type == 'points':
  912. self.UpdateVectorPointsProperties(id, data[type])
  913. else:
  914. self.UpdateVectorLinesProperties(id, data[type])
  915. def UpdateVectorLinesProperties(self, id, data):
  916. """Update vector line map object properties"""
  917. # mode
  918. if data['color'].has_key('update') or \
  919. data['width'].has_key('update') or \
  920. data['mode'].has_key('update'):
  921. width = data['width']['value']
  922. color = data['color']['value']
  923. if data['mode']['type'] == 'flat':
  924. flat = True
  925. if data.has_key('surface'):
  926. data.pop('surface')
  927. else:
  928. flat = False
  929. self.nvizClass.SetVectorLineMode(id, color,
  930. width, flat)
  931. if data['color'].has_key('update'):
  932. data['color'].pop('update')
  933. if data['width'].has_key('update'):
  934. data['width'].pop('update')
  935. if data['mode'].has_key('update'):
  936. data['mode'].pop('update')
  937. # height
  938. if data['height'].has_key('update'):
  939. self.nvizClass.SetVectorLineHeight(id,
  940. data['height']['value'])
  941. data['height'].pop('update')
  942. # surface
  943. if data['mode'].has_key('update'):
  944. sid = self.GetLayerId(type='raster', name=data['mode']['surface'])
  945. if sid > -1:
  946. self.nvizClass.SetVectorLineSurface(id, sid)
  947. data['mode'].pop('update')
  948. def UpdateVectorPointsProperties(self, id, data):
  949. """Update vector point map object properties"""
  950. if data['size'].has_key('update') or \
  951. data['width'].has_key('update') or \
  952. data['marker'].has_key('update') or \
  953. data['color'].has_key('update'):
  954. ret = self.nvizClass.SetVectorPointMode(id, data['color']['value'],
  955. data['width']['value'], float(data['size']['value']),
  956. data['marker']['value'] + 1)
  957. error = None
  958. if ret == -1:
  959. error = _("Vector point layer not found (id=%d)") % id
  960. elif ret == -2:
  961. error = _("Unable to set data layer properties (id=%d)") % id
  962. if error:
  963. raise gcmd.NvizError(parent=self.parent,
  964. message=_("Setting data layer properties failed.\n\n%s") % error)
  965. for prop in ('size', 'width', 'marker', 'color'):
  966. if data[prop].has_key('update'):
  967. data[prop].pop('update')
  968. # height
  969. if data['height'].has_key('update'):
  970. self.nvizClass.SetVectorPointHeight(id,
  971. data['height']['value'])
  972. data['height'].pop('update')
  973. # surface
  974. if data['mode'].has_key('update'):
  975. sid = self.GetLayerId(type='raster', name=data['mode']['surface'])
  976. if sid > -1:
  977. self.nvizClass.SetVectorPointSurface(id, sid)
  978. data['mode'].pop('update')
  979. def GetLayerNames(self, type):
  980. """Return list of map layer names of given type"""
  981. layerName = []
  982. for item in self.layers:
  983. mapLayer = self.tree.GetPyData(item)[0]['maplayer']
  984. if type != mapLayer.GetType():
  985. continue
  986. layerName.append(mapLayer.GetName())
  987. return layerName
  988. def GetLayerId(self, type, name):
  989. """Get layer object id or -1"""
  990. if len(name) < 1:
  991. return -1
  992. for item in self.layers:
  993. mapLayer = self.tree.GetPyData(item)[0]['maplayer']
  994. if type != mapLayer.GetType() or \
  995. name != mapLayer.GetName():
  996. continue
  997. data = self.tree.GetPyData(item)[0]['nviz']
  998. if type == 'raster':
  999. return data['surface']['object']['id']
  1000. elif type == 'vpoint':
  1001. return data['vector']['points']['object']['id']
  1002. elif type == 'vline':
  1003. return data['vector']['lines']['object']['id']
  1004. elif type == '3d-raster':
  1005. return data['volume']['object']['id']
  1006. return -1