nviz_mapdisp.py 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227
  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. 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 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 != '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.append(item)
  375. # set default/workspace layer properties
  376. data = self.SetMapObjProperties(item, id, nvizType)
  377. # update properties
  378. event = wxUpdateProperties(data=data)
  379. wx.PostEvent(self, event)
  380. # update tools window
  381. if hasattr(self.parent, "nvizToolWin") and \
  382. item == self.GetSelectedLayer(type='item'):
  383. toolWin = self.parent.nvizToolWin
  384. if layer.type == 'raster':
  385. win = toolWin.FindWindowById( \
  386. toolWin.win['vector']['lines']['surface'])
  387. win.SetItems(self.GetLayerNames(layer.type))
  388. toolWin.UpdatePage(nvizType)
  389. toolWin.SetPage(nvizType)
  390. return id
  391. def UnloadRaster(self, item):
  392. """Unload 2d raster map
  393. @param layer item
  394. """
  395. return self._unloadRaster(item)
  396. def UnloadRaster3d(self, item):
  397. """Unload 3d raster map
  398. @param layer item
  399. """
  400. return self._unloadRaster(item)
  401. def _unloadRaster(self, item):
  402. """Unload 2d/3d raster map
  403. @param item layer item
  404. """
  405. layer = self.tree.GetPyData(item)[0]['maplayer']
  406. if layer.type not in ('raster', '3d-raster'):
  407. return
  408. data = self.tree.GetPyData(item)[0]['nviz']
  409. if layer.type == 'raster':
  410. nvizType = 'surface'
  411. unloadFn = self.nvizClass.UnloadSurface
  412. errorMsg = _("Unable to unload raster map")
  413. successMsg = _("Raster map")
  414. else:
  415. nvizType = 'volume'
  416. unloadFn = self.nvizClass.UnloadVolume
  417. errorMsg = _("Unable to unload 3d raster map")
  418. successMsg = _("3d raster map")
  419. id = data[nvizType]['object']['id']
  420. if unloadFn(id) == 0:
  421. print >> sys.stderr, "Nviz:" + "%s <%s>" % (errorMsg, layer.name)
  422. else:
  423. print "Nviz:" + "%s <%s> %s" % (successMsg, layer.name, _("unloaded successfully"))
  424. data[nvizType].pop('object')
  425. self.layers.remove(item)
  426. # update tools window
  427. if hasattr(self.parent, "nvizToolWin") and \
  428. layer.type == 'raster':
  429. toolWin = self.parent.nvizToolWin
  430. win = toolWin.FindWindowById( \
  431. toolWin.win['vector']['lines']['surface'])
  432. win.SetItems(self.GetLayerNames(layer.type))
  433. # remove surface page
  434. if toolWin.notebook.GetSelection() == toolWin.page[nvizType]['id']:
  435. toolWin.notebook.RemovePage(toolWin.page[nvizType]['id'])
  436. toolWin.page[nvizType]['id'] = -1
  437. toolWin.page['settings']['id'] = 1
  438. def LoadVector(self, item, vecType=None):
  439. """Load 2D or 3D vector map overlay
  440. @param item layer item
  441. @param vecType vector type (lines / points)
  442. """
  443. layer = self.tree.GetPyData(item)[0]['maplayer']
  444. if layer.type != 'vector':
  445. return
  446. if vecType is None:
  447. # load data type by default
  448. vecType = []
  449. for v in ('lines', 'points'):
  450. if UserSettings.Get(group='nviz', key='vector',
  451. subkey=[v, 'show']):
  452. vecType.append(v)
  453. # set default properties
  454. self.SetMapObjProperties(item, -1, 'lines')
  455. self.SetMapObjProperties(item, -1, 'points')
  456. id = -1
  457. for type in vecType:
  458. if type == 'lines':
  459. id = self.nvizClass.LoadVector(str(layer.name), False)
  460. else:
  461. id = self.nvizClass.LoadVector(str(layer.name), True)
  462. if id < 0:
  463. print >> sys.stderr, "Nviz:" + _("Loading vector map <%(name)s> (%(type)s) failed") % \
  464. { 'name' : layer.name, 'type' : type }
  465. continue
  466. # update layer properties
  467. self.SetMapObjProperties(item, id, type)
  468. self.layers.append(item)
  469. # update properties
  470. data = self.tree.GetPyData(item)[0]['nviz']
  471. event = wxUpdateProperties(data=data)
  472. wx.PostEvent(self, event)
  473. # update tools window
  474. if hasattr(self.parent, "nvizToolWin") and \
  475. item == self.GetSelectedLayer(type='item'):
  476. toolWin = self.parent.nvizToolWin
  477. toolWin.UpdatePage('vector')
  478. toolWin.SetPage('vector')
  479. return id
  480. def UnloadVector(self, item, vecType=None):
  481. """Unload vector map overlay
  482. @param item layer item
  483. @param vecType vector type (lines, points)
  484. """
  485. layer = self.tree.GetPyData(item)[0]['maplayer']
  486. data = self.tree.GetPyData(item)[0]['nviz']['vector']
  487. if vecType is None:
  488. vecType = []
  489. for v in ('lines', 'points'):
  490. if UserSettings.Get(group='nviz', key='vector',
  491. subkey=[v, 'show']):
  492. vecType.append(v)
  493. for vtype in vecType:
  494. if not data[vtype].has_key('object'):
  495. continue
  496. id = data[vtype]['object']['id']
  497. if vtype == 'lines':
  498. ret = self.nvizClass.UnloadVector(id, False)
  499. else:
  500. ret = self.nvizClass.UnloadVector(id, True)
  501. if ret == 0:
  502. print >> sys.stderr, "Nviz:" + _("Unable to unload vector map <%(name)s> (%(type)s)") % \
  503. { 'name': layer.name, 'type' : vtype }
  504. else:
  505. print "Nviz:" + _("Vector map <%(name)s> (%(type)s) unloaded successfully") % \
  506. { 'name' : layer.name, 'type' : vtype }
  507. data[vtype].pop('object')
  508. self.layers.remove(id)
  509. # update tools window
  510. if hasattr(self.parent, "nvizToolWin") and \
  511. vecType is None:
  512. toolWin = self.parent.nvizToolWin
  513. # remove surface page
  514. if toolWin.notebook.GetSelection() == toolWin.page['surface']['id']:
  515. toolWin.notebook.RemovePage(toolWin.page['surface']['id'])
  516. toolWin.page['surface']['id'] = -1
  517. toolWin.page['settings']['id'] = 1
  518. def GetDrawMode(self, mode=None, style=None, shade=None, string=False):
  519. """Get surface draw mode (value) from description/selection
  520. @param mode,style,shade modes
  521. @param string if True input parameters are strings otherwise
  522. selections
  523. """
  524. value = 0
  525. desc = {}
  526. if string:
  527. if mode is not None:
  528. if mode == 'coarse':
  529. value |= wxnviz.DM_WIRE
  530. elif mode == 'fine':
  531. value |= wxnviz.DM_POLY
  532. else: # both
  533. value |= wxnviz.DM_WIRE_POLY
  534. if style is not None:
  535. if style == 'wire':
  536. value |= wxnviz.DM_GRID_WIRE
  537. else: # surface
  538. value |= wxnviz.DM_GRID_SURF
  539. if shade is not None:
  540. if shade == 'flat':
  541. value |= wxnviz.DM_FLAT
  542. else: # surface
  543. value |= wxnviz.DM_GOURAUD
  544. return value
  545. # -> string is False
  546. if mode is not None:
  547. if mode == 0: # coarse
  548. value |= wxnviz.DM_WIRE
  549. desc['mode'] = 'coarse'
  550. elif mode == 1: # fine
  551. value |= wxnviz.DM_POLY
  552. desc['mode'] = 'fine'
  553. else: # both
  554. value |= wxnviz.DM_WIRE_POLY
  555. desc['mode'] = 'both'
  556. if style is not None:
  557. if style == 0: # wire
  558. value |= wxnviz.DM_GRID_WIRE
  559. desc['style'] = 'wire'
  560. else: # surface
  561. value |= wxnviz.DM_GRID_SURF
  562. desc['style'] = 'surface'
  563. if shade is not None:
  564. if shade == 0:
  565. value |= wxnviz.DM_FLAT
  566. desc['shading'] = 'flat'
  567. else: # surface
  568. value |= wxnviz.DM_GOURAUD
  569. desc['shading'] = 'gouraud'
  570. return (value, desc)
  571. def SetSurfaceDefaultProp(self, data):
  572. """Set default surface data properties"""
  573. #
  574. # attributes
  575. #
  576. for attrb in ('shine', ):
  577. data['attribute'][attrb] = {}
  578. for key, value in UserSettings.Get(group='nviz', key='volume',
  579. subkey=attrb).iteritems():
  580. data['attribute'][attrb][key] = value
  581. data['attribute'][attrb]['update'] = None
  582. #
  583. # draw
  584. #
  585. data['draw']['all'] = False # apply only for current surface
  586. for control, value in UserSettings.Get(group='nviz', key='surface', subkey='draw').iteritems():
  587. if control[:3] == 'res':
  588. if not data['draw'].has_key('resolution'):
  589. data['draw']['resolution'] = {}
  590. if not data['draw']['resolution'].has_key('update'):
  591. data['draw']['resolution']['update'] = None
  592. data['draw']['resolution'][control[4:]] = value
  593. continue
  594. if control == 'wire-color':
  595. value = str(value[0]) + ':' + str(value[1]) + ':' + str(value[2])
  596. elif control in ('mode', 'style', 'shading'):
  597. if not data['draw'].has_key('mode'):
  598. data['draw']['mode'] = {}
  599. continue
  600. data['draw'][control] = { 'value' : value }
  601. data['draw'][control]['update'] = None
  602. value, desc = self.GetDrawMode(UserSettings.Get(group='nviz', key='surface', subkey=['draw', 'mode']),
  603. UserSettings.Get(group='nviz', key='surface', subkey=['draw', 'style']),
  604. UserSettings.Get(group='nviz', key='surface', subkey=['draw', 'shading']))
  605. data['draw']['mode'] = { 'value' : value,
  606. 'desc' : desc,
  607. 'update': None }
  608. def SetVolumeDefaultProp(self, data):
  609. """Set default volume data properties"""
  610. #
  611. # draw
  612. #
  613. for control, value in UserSettings.Get(group='nviz', key='volume', subkey='draw').iteritems():
  614. if control == 'mode':
  615. continue
  616. if control == 'shading':
  617. sel = UserSettings.Get(group='nviz', key='surface', subkey=['draw', 'shading'])
  618. value, desc = self.GetDrawMode(shade=sel, string=False)
  619. data['draw']['shading'] = { 'value' : value,
  620. 'desc' : desc['shading'] }
  621. elif control == 'mode':
  622. sel = UserSettings.Get(group='nviz', key='volume', subkey=['draw', 'mode'])
  623. if sel == 0:
  624. desc = 'isosurface'
  625. else:
  626. desc = 'slice'
  627. data['draw']['mode'] = { 'value' : sel,
  628. 'desc' : desc, }
  629. else:
  630. data['draw'][control] = { 'value' : value }
  631. if not data['draw'][control].has_key('update'):
  632. data['draw'][control]['update'] = None
  633. #
  634. # isosurface attributes
  635. #
  636. for attrb in ('shine', ):
  637. data['attribute'][attrb] = {}
  638. for key, value in UserSettings.Get(group='nviz', key='volume',
  639. subkey=attrb).iteritems():
  640. data['attribute'][attrb][key] = value
  641. def SetVectorDefaultProp(self, data):
  642. """Set default vector data properties"""
  643. self.SetVectorLinesDefaultProp(data['lines'])
  644. self.SetVectorPointsDefaultProp(data['points'])
  645. def SetVectorLinesDefaultProp(self, data):
  646. """Set default vector properties -- lines"""
  647. # width
  648. data['width'] = {'value' : UserSettings.Get(group='nviz', key='vector',
  649. subkey=['lines', 'width']) }
  650. # color
  651. value = UserSettings.Get(group='nviz', key='vector',
  652. subkey=['lines', 'color'])
  653. color = str(value[0]) + ':' + str(value[1]) + ':' + str(value[2])
  654. data['color'] = { 'value' : color }
  655. # mode
  656. if UserSettings.Get(group='nviz', key='vector',
  657. subkey=['lines', 'flat']):
  658. type = 'flat'
  659. map = None
  660. else:
  661. rasters = self.GetLayerNames('raster')
  662. if len(rasters) > 0:
  663. type = 'surface'
  664. map = rasters[0]
  665. else:
  666. type = 'flat'
  667. map = None
  668. data['mode'] = {}
  669. data['mode']['type'] = type
  670. data['mode']['update'] = None
  671. if map:
  672. data['mode']['surface'] = map
  673. # height
  674. data['height'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  675. subkey=['lines', 'height']) }
  676. if data.has_key('object'):
  677. for attrb in ('color', 'width', 'mode', 'height'):
  678. data[attrb]['update'] = None
  679. def SetVectorPointsDefaultProp(self, data):
  680. """Set default vector properties -- points"""
  681. # size
  682. data['size'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  683. subkey=['points', 'size']) }
  684. # width
  685. data['width'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  686. subkey=['points', 'width']) }
  687. # marker
  688. data['marker'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  689. subkey=['points', 'marker']) }
  690. # color
  691. value = UserSettings.Get(group='nviz', key='vector',
  692. subkey=['points', 'color'])
  693. color = str(value[0]) + ':' + str(value[1]) + ':' + str(value[2])
  694. data['color'] = { 'value' : color }
  695. # mode
  696. data['mode'] = { 'type' : 'surface',
  697. 'surface' : '', }
  698. rasters = self.GetLayerNames('raster')
  699. if len(rasters) > 0:
  700. data['mode']['surface'] = rasters[0]
  701. # height
  702. data['height'] = { 'value' : UserSettings.Get(group='nviz', key='vector',
  703. subkey=['points', 'height']) }
  704. if data.has_key('object'):
  705. for attrb in ('size', 'width', 'marker',
  706. 'color', 'surface', 'height'):
  707. data[attrb]['update'] = None
  708. def Reset(self):
  709. """Reset (unload data)"""
  710. for item in self.layers:
  711. type = self.tree.GetPyData(item)[0]['maplayer'].type
  712. if type == 'raster':
  713. self.UnloadRaster(item)
  714. elif type == '3d-raster':
  715. self.UnloadRaster3d(item)
  716. elif type == 'vector':
  717. self.UnloadVector(item)
  718. self.init = False
  719. def OnZoomToMap(self, event):
  720. """
  721. Set display extents to match selected raster
  722. or vector map or volume.
  723. @todo vector, volume
  724. """
  725. layer = self.GetSelectedLayer()
  726. if layer is None:
  727. return
  728. Debug.msg (3, "GLWindow.OnZoomToMap(): layer=%s, type=%s" % \
  729. (layer.name, layer.type))
  730. self.nvizClass.SetViewportDefault()
  731. def ResetView(self):
  732. """Reset to default view"""
  733. self.view['z-exag']['value'], \
  734. self.iview['height']['value'], \
  735. self.iview['height']['min'], \
  736. self.iview['height']['max'] = self.nvizClass.SetViewDefault()
  737. self.view['pos']['x'] = UserSettings.Get(group='nviz', key='view',
  738. subkey=('pos', 'x'))
  739. self.view['pos']['y'] = UserSettings.Get(group='nviz', key='view',
  740. subkey=('pos', 'x'))
  741. self.view['persp']['value'] = UserSettings.Get(group='nviz', key='view',
  742. subkey=('persp', 'value'))
  743. self.view['twist']['value'] = UserSettings.Get(group='nviz', key='view',
  744. subkey=('twist', 'value'))
  745. event = wxUpdateView(zExag=False)
  746. wx.PostEvent(self, event)
  747. def UpdateMapObjProperties(self, event):
  748. """Generic method to update data layer properties"""
  749. data = event.data
  750. if data.has_key('surface'):
  751. id = data['surface']['object']['id']
  752. self.UpdateSurfaceProperties(id, data['surface'])
  753. # -> initialized
  754. data['surface']['object']['init'] = True
  755. elif data.has_key('volume'):
  756. id = data['volume']['object']['id']
  757. self.UpdateVolumeProperties(id, data['volume'])
  758. # -> initialized
  759. data['volume']['object']['init'] = True
  760. elif data.has_key('vector'):
  761. for type in ('lines', 'points'):
  762. if data['vector'][type].has_key('object'):
  763. id = data['vector'][type]['object']['id']
  764. self.UpdateVectorProperties(id, data['vector'], type)
  765. # -> initialized
  766. data['vector'][type]['object']['init'] = True
  767. def UpdateSurfaceProperties(self, id, data):
  768. """Update surface map object properties"""
  769. # surface attributes
  770. for attrb in ('topo', 'color', 'mask',
  771. 'transp', 'shine', 'emit'):
  772. if not data['attribute'].has_key(attrb) or \
  773. not data['attribute'][attrb].has_key('update'):
  774. continue
  775. map = data['attribute'][attrb]['map']
  776. value = data['attribute'][attrb]['value']
  777. if map is None: # unset
  778. # only optional attributes
  779. if attrb == 'mask':
  780. # TODO: invert mask
  781. # TODO: broken in NVIZ
  782. self.nvizClass.UnsetSurfaceMask(id)
  783. elif attrb == 'transp':
  784. self.nvizClass.UnsetSurfaceTransp(id)
  785. elif attrb == 'emit':
  786. self.nvizClass.UnsetSurfaceEmit(id)
  787. else:
  788. if type(value) == type('') and \
  789. len(value) <= 0: # ignore empty values (TODO: warning)
  790. continue
  791. if attrb == 'topo':
  792. self.nvizClass.SetSurfaceTopo(id, map, str(value))
  793. elif attrb == 'color':
  794. self.nvizClass.SetSurfaceColor(id, map, str(value))
  795. elif attrb == 'mask':
  796. # TODO: invert mask
  797. # TODO: broken in NVIZ
  798. self.nvizClass.SetSurfaceMask(id, False, str(value))
  799. elif attrb == 'transp':
  800. self.nvizClass.SetSurfaceTransp(id, map, str(value))
  801. elif attrb == 'shine':
  802. self.nvizClass.SetSurfaceShine(id, map, str(value))
  803. elif attrb == 'emit':
  804. self.nvizClass.SetSurfaceEmit(id, map, str(value))
  805. data['attribute'][attrb].pop('update')
  806. # draw res
  807. if data['draw']['resolution'].has_key('update'):
  808. coarse = data['draw']['resolution']['coarse']
  809. fine = data['draw']['resolution']['fine']
  810. if data['draw']['all']:
  811. self.nvizClass.SetSurfaceRes(-1, fine, coarse)
  812. else:
  813. self.nvizClass.SetSurfaceRes(id, fine, coarse)
  814. data['draw']['resolution'].pop('update')
  815. # draw style
  816. if data['draw']['mode'].has_key('update'):
  817. if data['draw']['mode']['value'] < 0: # need to calculate
  818. data['draw']['mode']['value'] = \
  819. self.GetDrawMode(mode=data['draw']['mode']['desc']['mode'],
  820. style=data['draw']['mode']['desc']['style'],
  821. shade=data['draw']['mode']['desc']['shading'],
  822. string=True)
  823. style = data['draw']['mode']['value']
  824. if data['draw']['all']:
  825. self.nvizClass.SetSurfaceStyle(-1, style)
  826. else:
  827. self.nvizClass.SetSurfaceStyle(id, style)
  828. data['draw']['mode'].pop('update')
  829. # wire color
  830. if data['draw']['wire-color'].has_key('update'):
  831. color = data['draw']['wire-color']['value']
  832. if data['draw']['all']:
  833. self.nvizClass.SetWireColor(-1, str(color))
  834. else:
  835. self.nvizClass.SetWireColor(id, str(color))
  836. data['draw']['wire-color'].pop('update')
  837. # position
  838. if data['position'].has_key('update'):
  839. x = data['position']['x']
  840. y = data['position']['y']
  841. z = data['position']['z']
  842. self.nvizClass.SetSurfacePosition(id, x, y, z)
  843. data['position'].pop('update')
  844. def UpdateVolumeProperties(self, id, data, isosurfId=None):
  845. """Update volume (isosurface/slice) map object properties"""
  846. #
  847. # draw
  848. #
  849. if data['draw']['resolution'].has_key('update'):
  850. self.nvizClass.SetIsosurfaceRes(id, data['draw']['resolution']['value'])
  851. data['draw']['resolution'].pop('update')
  852. if data['draw']['shading'].has_key('update'):
  853. if data['draw']['shading']['value'] < 0: # need to calculate
  854. data['draw']['shading']['value'] = \
  855. self.GetDrawMode(shade=data['draw']['shading'],
  856. string=False)
  857. data['draw']['shading'].pop('update')
  858. #
  859. # isosurface attributes
  860. #
  861. isosurfId = 0
  862. for isosurf in data['isosurface']:
  863. for attrb in ('color', 'mask',
  864. 'transp', 'shine', 'emit'):
  865. if not isosurf.has_key(attrb) or \
  866. not isosurf[attrb].has_key('update'):
  867. continue
  868. map = isosurf[attrb]['map']
  869. value = isosurf[attrb]['value']
  870. if map is None: # unset
  871. # only optional attributes
  872. if attrb == 'mask':
  873. # TODO: invert mask
  874. # TODO: broken in NVIZ
  875. self.nvizClass.UnsetIsosurfaceMask(id, isosurfId)
  876. elif attrb == 'transp':
  877. self.nvizClass.UnsetIsosurfaceTransp(id, isosurfId)
  878. elif attrb == 'emit':
  879. self.nvizClass.UnsetIsosurfaceEmit(id, isosurfId)
  880. else:
  881. if type(value) == type('') and \
  882. len(value) <= 0: # ignore empty values (TODO: warning)
  883. continue
  884. elif attrb == 'color':
  885. self.nvizClass.SetIsosurfaceColor(id, isosurfId, map, str(value))
  886. elif attrb == 'mask':
  887. # TODO: invert mask
  888. # TODO: broken in NVIZ
  889. self.nvizClass.SetIsosurfaceMask(id, isosurfId, False, str(value))
  890. elif attrb == 'transp':
  891. self.nvizClass.SetIsosurfaceTransp(id, isosurfId, map, str(value))
  892. elif attrb == 'shine':
  893. self.nvizClass.SetIsosurfaceShine(id, isosurfId, map, str(value))
  894. elif attrb == 'emit':
  895. self.nvizClass.SetIsosurfaceEmit(id, isosurfId, map, str(value))
  896. isosurf[attrb].pop('update')
  897. isosurfId += 1
  898. def UpdateVectorProperties(self, id, data, type):
  899. """Update vector layer properties
  900. @param id layer id
  901. @param data properties
  902. @param type lines/points
  903. """
  904. if type == 'points':
  905. self.UpdateVectorPointsProperties(id, data[type])
  906. else:
  907. self.UpdateVectorLinesProperties(id, data[type])
  908. def UpdateVectorLinesProperties(self, id, data):
  909. """Update vector line map object properties"""
  910. # mode
  911. if data['color'].has_key('update') or \
  912. data['width'].has_key('update') or \
  913. data['mode'].has_key('update'):
  914. width = data['width']['value']
  915. color = data['color']['value']
  916. if data['mode']['type'] == 'flat':
  917. flat = True
  918. if data.has_key('surface'):
  919. data.pop('surface')
  920. else:
  921. flat = False
  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']['value'])
  934. data['height'].pop('update')
  935. # surface
  936. if data['mode'].has_key('update'):
  937. sid = self.GetLayerId(type='raster', name=data['mode']['surface'])
  938. if sid > -1:
  939. self.nvizClass.SetVectorLineSurface(id, sid)
  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. sid = self.GetLayerId(type='raster', name=data['mode']['surface'])
  969. if sid > -1:
  970. self.nvizClass.SetVectorPointSurface(id, sid)
  971. data['mode'].pop('update')
  972. def GetLayerNames(self, type):
  973. """Return list of map layer names of given type"""
  974. layerName = []
  975. for item in self.layers:
  976. layerName.append(self.tree.GetPyData(item)[0]['maplayer'].GetName())
  977. return layerName
  978. def GetLayerId(self, type, name):
  979. """Get layer object id or -1"""
  980. for item in self.layers:
  981. mapName = self.tree.GetPyData(item)[0]['maplayer'].GetName()
  982. data = self.tree.GetPyData(item)[0]['nviz']
  983. if type == 'raster':
  984. return data['surface']['object']['id']
  985. elif type == 'vpoint':
  986. return data['vector']['points']['object']['id']
  987. elif type == 'vline':
  988. return data['vector']['lines']['object']['id']
  989. elif type == '3d-raster':
  990. return data['volume']['object']['id']
  991. return -1