nviz_mapdisp.py 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163
  1. """!
  2. @package nviz_mapdisp.py
  3. @brief wxGUI 3D view mode (map canvas)
  4. This module implements 3D visualization mode for map display.
  5. List of classes:
  6. - NvizThread
  7. - GLWindow
  8. (C) 2008-2010 by the GRASS Development Team
  9. This program is free software under the GNU General Public
  10. License (>=v2). Read the file COPYING that comes with GRASS
  11. for details.
  12. @author Martin Landa <landa.martin gmail.com> (Google SoC 2008/2010)
  13. """
  14. import os
  15. import sys
  16. import time
  17. import copy
  18. import math
  19. from threading import Thread
  20. import wx
  21. import wx.lib.scrolledpanel as scrolled
  22. from wx.lib.newevent import NewEvent
  23. from wx import glcanvas
  24. import gcmd
  25. import globalvar
  26. from debug import Debug
  27. from mapdisp_window import MapWindow
  28. from goutput import wxCmdOutput
  29. from preferences import globalSettings as UserSettings
  30. from workspace import Nviz as NvizDefault
  31. import wxnviz
  32. wxUpdateProperties, EVT_UPDATE_PROP = NewEvent()
  33. wxUpdateView, EVT_UPDATE_VIEW = NewEvent()
  34. wxUpdateLight, EVT_UPDATE_LIGHT = NewEvent()
  35. class NvizThread(Thread):
  36. def __init__(self, log, progressbar, window):
  37. Thread.__init__(self)
  38. self.log = log
  39. self.progressbar = progressbar
  40. self.window = window
  41. self._display = None
  42. self.setDaemon(True)
  43. def run(self):
  44. self._display = wxnviz.Nviz(self.log, self.progressbar)
  45. def GetDisplay(self):
  46. """!Get display instance"""
  47. return self._display
  48. class GLWindow(MapWindow, glcanvas.GLCanvas):
  49. """!OpenGL canvas for Map Display Window"""
  50. def __init__(self, parent, id = wx.ID_ANY,
  51. Map = None, tree = None, lmgr = None):
  52. self.parent = parent # MapFrame
  53. glcanvas.GLCanvas.__init__(self, parent, id)
  54. MapWindow.__init__(self, parent, id,
  55. Map, tree, lmgr)
  56. self.Hide()
  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 = list()
  66. # list of query points
  67. self.qpoints = list()
  68. #
  69. # use display region instead of computational
  70. #
  71. os.environ['GRASS_REGION'] = self.Map.SetRegion()
  72. #
  73. # create nviz instance
  74. #
  75. if self.lmgr:
  76. self.log = self.lmgr.goutput
  77. logerr = self.lmgr.goutput.cmd_stderr
  78. logmsg = self.lmgr.goutput.cmd_output
  79. else:
  80. self.log = logmsg = sys.stdout
  81. logerr = sys.stderr
  82. self.nvizThread = NvizThread(logerr,
  83. self.parent.statusbarWin['progress'],
  84. logmsg)
  85. self.nvizThread.start()
  86. time.sleep(.1)
  87. self._display = self.nvizThread.GetDisplay()
  88. # GRASS_REGION needed only for initialization
  89. del os.environ['GRASS_REGION']
  90. self.img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY)
  91. #
  92. # default values
  93. #
  94. self.view = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'view')) # copy
  95. self.iview = UserSettings.Get(group = 'nviz', key = 'view', internal = True)
  96. self.nvizDefault = NvizDefault()
  97. self.light = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'light')) # copy
  98. self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
  99. self.Bind(wx.EVT_SIZE, self.OnSize)
  100. self.Bind(wx.EVT_PAINT, self.OnPaint)
  101. self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
  102. self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseAction)
  103. self.Bind(wx.EVT_MOTION, self.OnMotion)
  104. self.Bind(EVT_UPDATE_PROP, self.UpdateMapObjProperties)
  105. self.Bind(EVT_UPDATE_VIEW, self.UpdateView)
  106. self.Bind(EVT_UPDATE_LIGHT, self.UpdateLight)
  107. self.Bind(wx.EVT_CLOSE, self.OnClose)
  108. def OnClose(self, event):
  109. # cleanup when window actually closes (on quit) and not just is hidden
  110. self.Reset()
  111. def OnEraseBackground(self, event):
  112. pass # do nothing, to avoid flashing on MSW
  113. def OnSize(self, event):
  114. size = self.GetClientSize()
  115. if self.GetContext():
  116. Debug.msg(3, "GLCanvas.OnSize(): w = %d, h = %d" % \
  117. (size.width, size.height))
  118. self.SetCurrent()
  119. self._display.ResizeWindow(size.width,
  120. size.height)
  121. event.Skip()
  122. def OnPaint(self, event):
  123. Debug.msg(1, "GLCanvas.OnPaint()")
  124. dc = wx.PaintDC(self)
  125. self.DoPaint()
  126. def DoPaint(self):
  127. self.SetCurrent()
  128. if not self.initView:
  129. self._display.InitView()
  130. self.initView = True
  131. self.LoadDataLayers()
  132. self.UnloadDataLayers()
  133. if not self.init:
  134. self.ResetView()
  135. if hasattr(self.lmgr, "nviz"):
  136. self.lmgr.nviz.UpdatePage('view')
  137. self.lmgr.nviz.UpdatePage('light')
  138. layer = self.GetSelectedLayer()
  139. if layer:
  140. if layer.type == 'raster':
  141. self.lmgr.nviz.UpdatePage('surface')
  142. self.lmgr.nviz.UpdatePage('fringe')
  143. elif layer.type == 'vector':
  144. self.lmgr.nviz.UpdatePage('vector')
  145. ### self.lmgr.nviz.UpdateSettings()
  146. # update widgets
  147. win = self.lmgr.nviz.FindWindowById( \
  148. self.lmgr.nviz.win['vector']['lines']['surface'])
  149. win.SetItems(self.GetLayerNames('raster'))
  150. self.init = True
  151. self.UpdateMap()
  152. def OnMouseAction(self, event):
  153. # change perspective with mouse wheel
  154. wheel = event.GetWheelRotation()
  155. if wheel != 0:
  156. current = event.GetPositionTuple()[:]
  157. Debug.msg (5, "GLWindow.OnMouseMotion(): wheel = %d" % wheel)
  158. prev_value = self.view['persp']['value']
  159. if wheel > 0:
  160. value = -1 * self.view['persp']['step']
  161. else:
  162. value = self.view['persp']['step']
  163. self.view['persp']['value'] += value
  164. if self.view['persp']['value'] < 1:
  165. self.view['persp']['value'] = 1
  166. elif self.view['persp']['value'] > 100:
  167. self.view['persp']['value'] = 100
  168. if prev_value != self.view['persp']['value']:
  169. if hasattr(self.lmgr, "nviz"):
  170. self.lmgr.nviz.UpdateSettings()
  171. self._display.SetView(self.view['position']['x'], self.view['position']['y'],
  172. self.iview['height']['value'],
  173. self.view['persp']['value'],
  174. self.view['twist']['value'])
  175. # redraw map
  176. self.DoPaint()
  177. # update statusbar
  178. ### self.parent.StatusbarUpdate()
  179. event.Skip()
  180. def Pixel2Cell(self, (x, y)):
  181. """!Convert image coordinates to real word coordinates
  182. @param x, y image coordinates
  183. @return easting, northing
  184. @return None on error
  185. """
  186. size = self.GetClientSize()
  187. # UL -> LL
  188. sid, x, y, z = self._display.GetPointOnSurface(x, y)
  189. if not sid:
  190. return None
  191. return (x, y)
  192. def OnLeftUp(self, event):
  193. self.ReleaseMouse()
  194. if self.mouse["use"] == "nvizQuerySurface":
  195. self.OnQuerySurface(event)
  196. elif self.mouse["use"] == "nvizQueryVector":
  197. self.OnQueryVector(event)
  198. def OnQuerySurface(self, event):
  199. """!Query surface on given position"""
  200. result = self._display.QueryMap(event.GetX(), event.GetY())
  201. if result:
  202. self.qpoints.append((result['x'], result['y'], result['z']))
  203. self.log.WriteLog("%-30s: %.3f" % (_("Easting"), result['x']))
  204. self.log.WriteLog("%-30s: %.3f" % (_("Northing"), result['y']))
  205. self.log.WriteLog("%-30s: %.3f" % (_("Elevation"), result['z']))
  206. self.log.WriteLog("%-30s: %s" % (_("Surface map elevation"), result['elevation']))
  207. self.log.WriteLog("%-30s: %s" % (_("Surface map color"), result['color']))
  208. if len(self.qpoints) > 1:
  209. prev = self.qpoints[-2]
  210. curr = self.qpoints[-1]
  211. dxy = math.sqrt(pow(prev[0]-curr[0], 2) +
  212. pow(prev[1]-curr[1], 2))
  213. dxyz = math.sqrt(pow(prev[0]-curr[0], 2) +
  214. pow(prev[1]-curr[1], 2) +
  215. pow(prev[2]-curr[2], 2))
  216. self.log.WriteLog("%-30s: %.3f" % (_("XY distance from previous"), dxy))
  217. self.log.WriteLog("%-30s: %.3f" % (_("XYZ distance from previous"), dxyz))
  218. self.log.WriteLog("%-30s: %.3f" % (_("Distance along surface"),
  219. self._display.GetDistanceAlongSurface(result['id'],
  220. (curr[0], curr[1]),
  221. (prev[0], prev[1]),
  222. useExag = False)))
  223. self.log.WriteLog("%-30s: %.3f" % (_("Distance along exag. surface"),
  224. self._display.GetDistanceAlongSurface(result['id'],
  225. (curr[0], curr[1]),
  226. (prev[0], prev[1]),
  227. useExag = True)))
  228. self.log.WriteCmdLog('-' * 80)
  229. else:
  230. self.log.WriteLog(_("No point on surface"))
  231. self.log.WriteCmdLog('-' * 80)
  232. def OnQueryVector(self, event):
  233. """!Query vector on given position"""
  234. self.log.WriteWarning(_("Function not implemented yet"))
  235. self.log.WriteCmdLog('-' * 80)
  236. def UpdateView(self, event):
  237. """!Change view settings"""
  238. data = self.view
  239. self._display.SetView(data['position']['x'], data['position']['y'],
  240. self.iview['height']['value'],
  241. data['persp']['value'],
  242. data['twist']['value'])
  243. if event and event.zExag and data['z-exag'].has_key('value'):
  244. self._display.SetZExag(data['z-exag']['value'])
  245. if event:
  246. event.Skip()
  247. def UpdateLight(self, event):
  248. """!Change light settings"""
  249. data = self.light
  250. self._display.SetLight(x = data['position']['x'], y = data['position']['y'],
  251. z = data['position']['z'], color = data['color'],
  252. bright = data['bright'] / 100.,
  253. ambient = data['ambient'] / 100.)
  254. self._display.DrawLightingModel()
  255. def UpdateMap(self, render = True):
  256. """!Updates the canvas anytime there is a change to the
  257. underlaying images or to the geometry of the canvas.
  258. @param render re-render map composition
  259. """
  260. start = time.clock()
  261. self.resize = False
  262. if self.render['quick'] is False:
  263. self.parent.statusbarWin['progress'].Show()
  264. self.parent.statusbarWin['progress'].SetRange(2)
  265. self.parent.statusbarWin['progress'].SetValue(0)
  266. if self.render['quick'] is False:
  267. self.parent.statusbarWin['progress'].SetValue(1)
  268. self._display.Draw(False, -1)
  269. elif self.render['quick'] is True:
  270. # quick
  271. mode = wxnviz.DRAW_QUICK_SURFACE | wxnviz.DRAW_QUICK_VOLUME
  272. if self.render['vlines']:
  273. mode |= wxnviz.DRAW_QUICK_VLINES
  274. if self.render['vpoints']:
  275. mode |= wxnviz.DRAW_QUICK_VPOINTS
  276. self._display.Draw(True, mode)
  277. else: # None -> reuse last rendered image
  278. pass # TODO
  279. self.SwapBuffers()
  280. stop = time.clock()
  281. if self.render['quick'] is False:
  282. self.parent.statusbarWin['progress'].SetValue(2)
  283. # hide process bar
  284. self.parent.statusbarWin['progress'].Hide()
  285. Debug.msg(3, "GLWindow.UpdateMap(): quick = %d, -> time = %g" % \
  286. (self.render['quick'], (stop-start)))
  287. def EraseMap(self):
  288. """!Erase the canvas
  289. """
  290. self._display.EraseMap()
  291. self.SwapBuffers()
  292. def IsLoaded(self, item):
  293. """!Check if layer (item) is already loaded
  294. @param item layer item
  295. """
  296. layer = self.tree.GetPyData(item)[0]['maplayer']
  297. data = self.tree.GetPyData(item)[0]['nviz']
  298. if not data:
  299. return 0
  300. if layer.type == 'raster':
  301. if not data['surface'].has_key('object'):
  302. return 0
  303. elif layer.type == 'vector':
  304. if not data['vlines'].has_key('object') and \
  305. not data['points'].has_key('object'):
  306. return 0
  307. return 1
  308. def _GetDataLayers(self, item, litems):
  309. """!Return get list of enabled map layers"""
  310. # load raster & vector maps
  311. while item and item.IsOk():
  312. type = self.tree.GetPyData(item)[0]['type']
  313. if type == 'group':
  314. subItem = self.tree.GetFirstChild(item)[0]
  315. self._GetDataLayers(subItem, litems)
  316. item = self.tree.GetNextSibling(item)
  317. if not item.IsChecked() or \
  318. type not in ('raster', 'vector', '3d-raster'):
  319. item = self.tree.GetNextSibling(item)
  320. continue
  321. litems.append(item)
  322. item = self.tree.GetNextSibling(item)
  323. def LoadDataLayers(self):
  324. """!Load raster/vector from current layer tree
  325. @todo volumes
  326. """
  327. if not self.tree:
  328. return
  329. listOfItems = []
  330. item = self.tree.GetFirstChild(self.tree.root)[0]
  331. self._GetDataLayers(item, listOfItems)
  332. start = time.time()
  333. while(len(listOfItems) > 0):
  334. item = listOfItems.pop()
  335. type = self.tree.GetPyData(item)[0]['type']
  336. if item in self.layers:
  337. continue
  338. try:
  339. if type == 'raster':
  340. self.LoadRaster(item)
  341. elif type == '3d-raster':
  342. self.LoadRaster3d(item)
  343. elif type == 'vector':
  344. # data = self.tree.GetPyData(item)[0]['nviz']
  345. # vecType = []
  346. # if data and data.has_key('vector'):
  347. # for v in ('lines', 'points'):
  348. # if data['vector'][v]:
  349. # vecType.append(v)
  350. layer = self.tree.GetPyData(item)[0]['maplayer']
  351. npoints, nlines, nfeatures, mapIs3D = self.lmgr.nviz.VectorInfo(layer)
  352. if npoints > 0:
  353. self.LoadVector(item, points = True)
  354. if nlines > 0:
  355. self.LoadVector(item, points = False)
  356. except gcmd.GException, e:
  357. GError(parent = self,
  358. message = e)
  359. self.init = False
  360. stop = time.time()
  361. Debug.msg(3, "GLWindow.LoadDataLayers(): time = %f" % (stop-start))
  362. def UnloadDataLayers(self):
  363. """!Unload any layers that have been deleted from layer tree"""
  364. if not self.tree:
  365. return
  366. listOfItems = []
  367. item = self.tree.GetFirstChild(self.tree.root)[0]
  368. self._GetDataLayers(item, listOfItems)
  369. start = time.time()
  370. for layer in self.layers:
  371. if layer not in listOfItems:
  372. ltype = self.tree.GetPyData(layer)[0]['type']
  373. try:
  374. if ltype == 'raster':
  375. self.UnloadRaster(layer)
  376. elif ltype == '3d-raster':
  377. self.UnloadRaster3d(layer)
  378. elif ltype == 'vector':
  379. data = self.tree.GetPyData(layer)[0]['nviz']
  380. vecType = []
  381. if data and data.has_key('vector'):
  382. for v in ('lines', 'points'):
  383. if data['vector'][v]:
  384. vecType.append(v)
  385. self.UnloadVector(layer, True)
  386. self.UnloadVector(layer, False)
  387. self.UpdateView(None)
  388. except gcmd.GException, e:
  389. gcmd.GError(parent = self,
  390. message = e)
  391. self.lmgr.nviz.UpdateSettings()
  392. stop = time.time()
  393. Debug.msg(3, "GLWindow.UnloadDataLayers(): time = %f" % (stop-start))
  394. def SetVectorFromCmd(self, item, data):
  395. """!Set 3D view properties from cmd (d.vect)
  396. @param item Layer Tree item
  397. @param nviz data
  398. """
  399. cmd = self.tree.GetPyData(item)[0]['cmd']
  400. if cmd[0] != 'd.vect':
  401. return
  402. for opt in cmd[1:]:
  403. try:
  404. key, value = opt.split('=')
  405. except ValueError:
  406. continue
  407. if key == 'color':
  408. data['lines']['color']['value'] = value
  409. data['points']['color']['value'] = value
  410. def SetMapObjProperties(self, item, id, nvizType):
  411. """!Set map object properties
  412. Properties must be afterwards updated by
  413. UpdateMapObjProperties().
  414. @param item layer item
  415. @param id nviz layer id (or -1)
  416. @param nvizType nviz data type (surface, points, vector)
  417. """
  418. type = self.tree.GetPyData(item)[0]['maplayer'].type
  419. # reference to original layer properties (can be None)
  420. data = self.tree.GetPyData(item)[0]['nviz']
  421. if not data:
  422. # init data structure
  423. self.tree.GetPyData(item)[0]['nviz'] = {}
  424. data = self.tree.GetPyData(item)[0]['nviz']
  425. if type == 'raster':
  426. # reset to default properties
  427. data[nvizType] = self.nvizDefault.SetSurfaceDefaultProp()
  428. elif type == 'vector':
  429. # reset to default properties (lines/points)
  430. data['vector'] = self.nvizDefault.SetVectorDefaultProp()
  431. self.SetVectorFromCmd(item, data['vector'])
  432. elif type == '3d-raster':
  433. # reset to default properties
  434. data[nvizType] = self.nvizDefault.SetVolumeDefaultProp()
  435. else:
  436. # complete data (use default values)
  437. if type == 'raster':
  438. data['surface'] = self.nvizDefault.SetSurfaceDefaultProp()
  439. if type == 'vector':
  440. if not data['vector']['lines']:
  441. self.nvizDefault.SetVectorLinesDefaultProp(data['vector']['lines'])
  442. if not data['vector']['points']:
  443. self.nvizDefault.SetVectorPointsDefaultProp(data['vector']['points'])
  444. # set updates
  445. for sec in data.keys():
  446. for sec1 in data[sec].keys():
  447. for sec2 in data[sec][sec1].keys():
  448. if sec2 != 'all':
  449. data[sec][sec1][sec2]['update'] = None
  450. event = wxUpdateProperties(data = data)
  451. wx.PostEvent(self, event)
  452. # set id
  453. if id > 0:
  454. if type in ('raster', '3d-raster'):
  455. data[nvizType]['object'] = { 'id' : id,
  456. 'init' : False }
  457. elif type == 'vector':
  458. data['vector'][nvizType]['object'] = { 'id' : id,
  459. 'init' : False }
  460. return data
  461. def LoadRaster(self, item):
  462. """!Load 2d raster map and set surface attributes
  463. @param layer item
  464. """
  465. return self._loadRaster(item)
  466. def LoadRaster3d(self, item):
  467. """!Load 3d raster map and set surface attributes
  468. @param layer item
  469. """
  470. return self._loadRaster(item)
  471. def _loadRaster(self, item):
  472. """!Load 2d/3d raster map and set its attributes
  473. @param layer item
  474. """
  475. layer = self.tree.GetPyData(item)[0]['maplayer']
  476. if layer.type not in ('raster', '3d-raster'):
  477. return
  478. if layer.type == 'raster':
  479. id = self._display.LoadSurface(str(layer.name), None, None)
  480. nvizType = 'surface'
  481. errorMsg = _("Loading raster map")
  482. elif layer.type == '3d-raster':
  483. id = self._display.LoadVolume(str(layer.name), None, None)
  484. nvizType = 'volume'
  485. errorMsg = _("Loading 3d raster map")
  486. else:
  487. id = -1
  488. if id < 0:
  489. if layer.type in ('raster', '3d-raster'):
  490. self.log.WriteError("%s <%s> %s" % (errorMsg, layer.name, _("failed")))
  491. else:
  492. self.log.WriteError(_("Unsupported layer type '%s'") % layer.type)
  493. self.layers.append(item)
  494. # set default/workspace layer properties
  495. data = self.SetMapObjProperties(item, id, nvizType)
  496. # update properties
  497. event = wxUpdateProperties(data = data)
  498. wx.PostEvent(self, event)
  499. # update tools window
  500. if hasattr(self.lmgr, "nviz") and \
  501. item == self.GetSelectedLayer(type = 'item'):
  502. toolWin = self.lmgr.nviz
  503. if layer.type == 'raster':
  504. win = toolWin.FindWindowById( \
  505. toolWin.win['vector']['lines']['surface'])
  506. win.SetItems(self.GetLayerNames(layer.type))
  507. #toolWin.UpdatePage(nvizType)
  508. #toolWin.SetPage(nvizType)
  509. return id
  510. def UnloadRaster(self, item):
  511. """!Unload 2d raster map
  512. @param layer item
  513. """
  514. return self._unloadRaster(item)
  515. def UnloadRaster3d(self, item):
  516. """!Unload 3d raster map
  517. @param layer item
  518. """
  519. return self._unloadRaster(item)
  520. def _unloadRaster(self, item):
  521. """!Unload 2d/3d raster map
  522. @param item layer item
  523. """
  524. layer = self.tree.GetPyData(item)[0]['maplayer']
  525. if layer.type not in ('raster', '3d-raster'):
  526. return
  527. data = self.tree.GetPyData(item)[0]['nviz']
  528. if layer.type == 'raster':
  529. nvizType = 'surface'
  530. unloadFn = self._display.UnloadSurface
  531. errorMsg = _("Unable to unload raster map")
  532. successMsg = _("Raster map")
  533. else:
  534. nvizType = 'volume'
  535. unloadFn = self._display.UnloadVolume
  536. errorMsg = _("Unable to unload 3d raster map")
  537. successMsg = _("3d raster map")
  538. id = data[nvizType]['object']['id']
  539. if unloadFn(id) == 0:
  540. self.log.WriteError("%s <%s>" % (errorMsg, layer.name))
  541. else:
  542. self.log.WriteLog("%s <%s> %s" % (successMsg, layer.name, _("unloaded successfully")))
  543. data[nvizType].pop('object')
  544. self.layers.remove(item)
  545. # update tools window
  546. if hasattr(self.lmgr, "nviz") and \
  547. layer.type == 'raster':
  548. toolWin = self.lmgr.nviz
  549. win = toolWin.FindWindowById( \
  550. toolWin.win['vector']['lines']['surface'])
  551. win.SetItems(self.GetLayerNames(layer.type))
  552. def LoadVector(self, item, points = None):
  553. """!Load 2D or 3D vector map overlay
  554. @param item layer item
  555. @param points True to load points, False to load lines, None
  556. to load both
  557. """
  558. layer = self.tree.GetPyData(item)[0]['maplayer']
  559. if layer.type != 'vector':
  560. return
  561. # set default properties
  562. if points is None:
  563. self.SetMapObjProperties(item, -1, 'lines')
  564. self.SetMapObjProperties(item, -1, 'points')
  565. vecTypes = ('points', 'lines')
  566. elif points:
  567. self.SetMapObjProperties(item, -1, 'points')
  568. vecTypes = ('points', )
  569. else:
  570. self.SetMapObjProperties(item, -1, 'lines')
  571. vecTypes = ('lines', )
  572. id = -1
  573. for vecType in vecTypes:
  574. if vecType == 'lines':
  575. id = self._display.LoadVector(str(layer.GetName()), False)
  576. else:
  577. id = self._display.LoadVector(str(layer.GetName()), True)
  578. if id < 0:
  579. self.log.WriteError(_("Loading vector map <%(name)s> (%(type)s) failed") % \
  580. { 'name' : layer.name, 'type' : vecType })
  581. # update layer properties
  582. self.SetMapObjProperties(item, id, vecType)
  583. self.layers.append(item)
  584. # update properties
  585. data = self.tree.GetPyData(item)[0]['nviz']
  586. event = wxUpdateProperties(data = data)
  587. wx.PostEvent(self, event)
  588. # update tools window
  589. if hasattr(self.lmgr, "nviz") and \
  590. item == self.GetSelectedLayer(type = 'item'):
  591. toolWin = self.lmgr.nviz
  592. toolWin.UpdatePage('vector')
  593. ### toolWin.SetPage('vector')
  594. return id
  595. def UnloadVector(self, item, points = None):
  596. """!Unload vector map overlay
  597. @param item layer item
  598. @param points,lines True to unload given feature type
  599. """
  600. layer = self.tree.GetPyData(item)[0]['maplayer']
  601. data = self.tree.GetPyData(item)[0]['nviz']['vector']
  602. # if vecType is None:
  603. # vecType = []
  604. # for v in ('lines', 'points'):
  605. # if UserSettings.Get(group = 'nviz', key = 'vector',
  606. # subkey = [v, 'show']):
  607. # vecType.append(v)
  608. if points is None:
  609. vecTypes = ('points', 'lines')
  610. elif points:
  611. vecTypes = ('points', )
  612. else:
  613. vecTypes = ('lines', )
  614. for vecType in vecTypes:
  615. if not data[vecType].has_key('object'):
  616. continue
  617. id = data[vecType]['object']['id']
  618. if vecType == 'lines':
  619. ret = self._display.UnloadVector(id, False)
  620. else:
  621. ret = self._display.UnloadVector(id, True)
  622. if ret == 0:
  623. self.log.WriteError(_("Unable to unload vector map <%(name)s> (%(type)s)") % \
  624. { 'name': layer.name, 'type' : vecType })
  625. else:
  626. self.log.WriteLog(_("Vector map <%(name)s> (%(type)s) unloaded successfully") % \
  627. { 'name' : layer.name, 'type' : vecType })
  628. data[vecType].pop('object')
  629. ### self.layers.remove(id)
  630. def Reset(self):
  631. """!Reset (unload data)"""
  632. for item in self.layers:
  633. type = self.tree.GetPyData(item)[0]['maplayer'].type
  634. if type == 'raster':
  635. self.UnloadRaster(item)
  636. elif type == '3d-raster':
  637. self.UnloadRaster3d(item)
  638. elif type == 'vector':
  639. self.UnloadVector(item)
  640. self.init = False
  641. def OnZoomToMap(self, event):
  642. """!Set display extents to match selected raster or vector
  643. map or volume.
  644. @todo vector, volume
  645. """
  646. layer = self.GetSelectedLayer()
  647. if layer is None:
  648. return
  649. Debug.msg (3, "GLWindow.OnZoomToMap(): layer = %s, type = %s" % \
  650. (layer.name, layer.type))
  651. self._display.SetViewportDefault()
  652. def ResetView(self):
  653. """!Reset to default view"""
  654. self.view['z-exag']['value'], \
  655. self.iview['height']['value'], \
  656. self.iview['height']['min'], \
  657. self.iview['height']['max'] = self._display.SetViewDefault()
  658. self.view['z-exag']['min'] = 0
  659. self.view['z-exag']['max'] = self.view['z-exag']['value'] * 10
  660. self.view['position']['x'] = UserSettings.Get(group = 'nviz', key = 'view',
  661. subkey = ('position', 'x'))
  662. self.view['position']['y'] = UserSettings.Get(group = 'nviz', key = 'view',
  663. subkey = ('position', 'y'))
  664. self.view['persp']['value'] = UserSettings.Get(group = 'nviz', key = 'view',
  665. subkey = ('persp', 'value'))
  666. self.view['twist']['value'] = UserSettings.Get(group = 'nviz', key = 'view',
  667. subkey = ('twist', 'value'))
  668. event = wxUpdateView(zExag = False)
  669. wx.PostEvent(self, event)
  670. def UpdateMapObjProperties(self, event):
  671. """!Generic method to update data layer properties"""
  672. data = event.data
  673. if data.has_key('surface'):
  674. id = data['surface']['object']['id']
  675. self.UpdateSurfaceProperties(id, data['surface'])
  676. # -> initialized
  677. data['surface']['object']['init'] = True
  678. elif data.has_key('volume'):
  679. id = data['volume']['object']['id']
  680. self.UpdateVolumeProperties(id, data['volume'])
  681. # -> initialized
  682. data['volume']['object']['init'] = True
  683. elif data.has_key('vector'):
  684. for type in ('lines', 'points'):
  685. if data['vector'][type].has_key('object'):
  686. id = data['vector'][type]['object']['id']
  687. self.UpdateVectorProperties(id, data['vector'], type)
  688. # -> initialized
  689. data['vector'][type]['object']['init'] = True
  690. def UpdateSurfaceProperties(self, id, data):
  691. """!Update surface map object properties"""
  692. # surface attributes
  693. for attrb in ('topo', 'color', 'mask',
  694. 'transp', 'shine', 'emit'):
  695. if not data['attribute'].has_key(attrb) or \
  696. not data['attribute'][attrb].has_key('update'):
  697. continue
  698. map = data['attribute'][attrb]['map']
  699. value = data['attribute'][attrb]['value']
  700. if map is None: # unset
  701. # only optional attributes
  702. if attrb == 'mask':
  703. # TODO: invert mask
  704. # TODO: broken in NVIZ
  705. self._display.UnsetSurfaceMask(id)
  706. elif attrb == 'transp':
  707. self._display.UnsetSurfaceTransp(id)
  708. elif attrb == 'emit':
  709. self._display.UnsetSurfaceEmit(id)
  710. else:
  711. if type(value) == type('') and \
  712. len(value) <= 0: # ignore empty values (TODO: warning)
  713. continue
  714. if attrb == 'topo':
  715. self._display.SetSurfaceTopo(id, map, str(value))
  716. elif attrb == 'color':
  717. self._display.SetSurfaceColor(id, map, str(value))
  718. elif attrb == 'mask':
  719. # TODO: invert mask
  720. # TODO: broken in NVIZ
  721. self._display.SetSurfaceMask(id, False, str(value))
  722. elif attrb == 'transp':
  723. self._display.SetSurfaceTransp(id, map, str(value))
  724. elif attrb == 'shine':
  725. self._display.SetSurfaceShine(id, map, str(value))
  726. elif attrb == 'emit':
  727. self._display.SetSurfaceEmit(id, map, str(value))
  728. data['attribute'][attrb].pop('update')
  729. # draw res
  730. if data['draw']['resolution'].has_key('update'):
  731. coarse = data['draw']['resolution']['coarse']
  732. fine = data['draw']['resolution']['fine']
  733. if data['draw']['all']:
  734. self._display.SetSurfaceRes(-1, fine, coarse)
  735. else:
  736. self._display.SetSurfaceRes(id, fine, coarse)
  737. data['draw']['resolution'].pop('update')
  738. # draw style
  739. if data['draw']['mode'].has_key('update'):
  740. if data['draw']['mode']['value'] < 0: # need to calculate
  741. data['draw']['mode']['value'] = \
  742. self.nvizDefault.GetDrawMode(mode = data['draw']['mode']['desc']['mode'],
  743. style = data['draw']['mode']['desc']['style'],
  744. shade = data['draw']['mode']['desc']['shading'],
  745. string = True)
  746. style = data['draw']['mode']['value']
  747. if data['draw']['all']:
  748. self._display.SetSurfaceStyle(-1, style)
  749. else:
  750. self._display.SetSurfaceStyle(id, style)
  751. data['draw']['mode'].pop('update')
  752. # wire color
  753. if data['draw']['wire-color'].has_key('update'):
  754. color = data['draw']['wire-color']['value']
  755. if data['draw']['all']:
  756. self._display.SetWireColor(-1, str(color))
  757. else:
  758. self._display.SetWireColor(id, str(color))
  759. data['draw']['wire-color'].pop('update')
  760. # position
  761. if data['position'].has_key('update'):
  762. x = data['position']['x']
  763. y = data['position']['y']
  764. z = data['position']['z']
  765. self._display.SetSurfacePosition(id, x, y, z)
  766. data['position'].pop('update')
  767. def UpdateVolumeProperties(self, id, data, isosurfId = None):
  768. """!Update volume (isosurface/slice) map object properties"""
  769. if data['draw']['resolution'].has_key('update'):
  770. self._display.SetIsosurfaceRes(id, data['draw']['resolution']['value'])
  771. data['draw']['resolution'].pop('update')
  772. if data['draw']['shading'].has_key('update'):
  773. if data['draw']['shading']['value'] < 0: # need to calculate
  774. data['draw']['shading']['value'] = \
  775. self.nvizDefault.GetDrawMode(shade = data['draw']['shading'],
  776. string = False)
  777. data['draw']['shading'].pop('update')
  778. #
  779. # isosurface attributes
  780. #
  781. isosurfId = 0
  782. for isosurf in data['isosurface']:
  783. for attrb in ('color', 'mask',
  784. 'transp', 'shine', 'emit'):
  785. if not isosurf.has_key(attrb) or \
  786. not isosurf[attrb].has_key('update'):
  787. continue
  788. map = isosurf[attrb]['map']
  789. value = isosurf[attrb]['value']
  790. if map is None: # unset
  791. # only optional attributes
  792. if attrb == 'mask':
  793. # TODO: invert mask
  794. # TODO: broken in NVIZ
  795. self._display.UnsetIsosurfaceMask(id, isosurfId)
  796. elif attrb == 'transp':
  797. self._display.UnsetIsosurfaceTransp(id, isosurfId)
  798. elif attrb == 'emit':
  799. self._display.UnsetIsosurfaceEmit(id, isosurfId)
  800. else:
  801. if type(value) == type('') and \
  802. len(value) <= 0: # ignore empty values (TODO: warning)
  803. continue
  804. elif attrb == 'color':
  805. self._display.SetIsosurfaceColor(id, isosurfId, map, str(value))
  806. elif attrb == 'mask':
  807. # TODO: invert mask
  808. # TODO: broken in NVIZ
  809. self._display.SetIsosurfaceMask(id, isosurfId, False, str(value))
  810. elif attrb == 'transp':
  811. self._display.SetIsosurfaceTransp(id, isosurfId, map, str(value))
  812. elif attrb == 'shine':
  813. self._display.SetIsosurfaceShine(id, isosurfId, map, str(value))
  814. elif attrb == 'emit':
  815. self._display.SetIsosurfaceEmit(id, isosurfId, map, str(value))
  816. isosurf[attrb].pop('update')
  817. isosurfId += 1
  818. def UpdateVectorProperties(self, id, data, type):
  819. """!Update vector layer properties
  820. @param id layer id
  821. @param data properties
  822. @param type lines/points
  823. """
  824. if type == 'points':
  825. self.UpdateVectorPointsProperties(id, data[type])
  826. else:
  827. self.UpdateVectorLinesProperties(id, data[type])
  828. def UpdateVectorLinesProperties(self, id, data):
  829. """!Update vector line map object properties"""
  830. # mode
  831. if data['color'].has_key('update') or \
  832. data['width'].has_key('update') or \
  833. data['mode'].has_key('update'):
  834. width = data['width']['value']
  835. color = data['color']['value']
  836. if data['mode']['type'] == 'flat':
  837. flat = True
  838. if data.has_key('surface'):
  839. data.pop('surface')
  840. else:
  841. flat = False
  842. self._display.SetVectorLineMode(id, color,
  843. width, flat)
  844. if data['color'].has_key('update'):
  845. data['color'].pop('update')
  846. if data['width'].has_key('update'):
  847. data['width'].pop('update')
  848. if data['mode'].has_key('update'):
  849. data['mode'].pop('update')
  850. # height
  851. if data['height'].has_key('update'):
  852. self._display.SetVectorLineHeight(id,
  853. data['height']['value'])
  854. data['height'].pop('update')
  855. # surface
  856. if data['mode'].has_key('update'):
  857. sid = self.GetLayerId(type = 'raster', name = data['mode']['surface'])
  858. if sid > -1:
  859. self._display.SetVectorLineSurface(id, sid)
  860. data['mode'].pop('update')
  861. def UpdateVectorPointsProperties(self, id, data):
  862. """!Update vector point map object properties"""
  863. if data['size'].has_key('update') or \
  864. data['width'].has_key('update') or \
  865. data['marker'].has_key('update') or \
  866. data['color'].has_key('update'):
  867. ret = self._display.SetVectorPointMode(id, data['color']['value'],
  868. data['width']['value'], float(data['size']['value']),
  869. data['marker']['value'] + 1)
  870. error = None
  871. if ret == -1:
  872. error = _("Vector point layer not found (id = %d)") % id
  873. elif ret == -2:
  874. error = _("Unable to set data layer properties (id = %d)") % id
  875. if error:
  876. raise gcmd.GException(_("Setting data layer properties failed.\n\n%s") % error)
  877. for prop in ('size', 'width', 'marker', 'color'):
  878. if data[prop].has_key('update'):
  879. data[prop].pop('update')
  880. # height
  881. if data['height'].has_key('update'):
  882. self._display.SetVectorPointHeight(id,
  883. data['height']['value'])
  884. data['height'].pop('update')
  885. # surface
  886. if data['mode'].has_key('update'):
  887. sid = self.GetLayerId(type = 'raster', name = data['mode']['surface'])
  888. if sid > -1:
  889. self._display.SetVectorPointSurface(id, sid)
  890. data['mode'].pop('update')
  891. def GetLayerNames(self, type):
  892. """!Return list of map layer names of given type"""
  893. layerName = []
  894. for item in self.layers:
  895. mapLayer = self.tree.GetPyData(item)[0]['maplayer']
  896. if type != mapLayer.GetType():
  897. continue
  898. layerName.append(mapLayer.GetName())
  899. return layerName
  900. def GetLayerId(self, type, name):
  901. """!Get layer object id or -1"""
  902. if len(name) < 1:
  903. return -1
  904. for item in self.layers:
  905. mapLayer = self.tree.GetPyData(item)[0]['maplayer']
  906. if type != mapLayer.GetType() or \
  907. name != mapLayer.GetName():
  908. continue
  909. data = self.tree.GetPyData(item)[0]['nviz']
  910. if type == 'raster':
  911. return data['surface']['object']['id']
  912. elif type == 'vpoint':
  913. return data['vector']['points']['object']['id']
  914. elif type == 'vline':
  915. return data['vector']['lines']['object']['id']
  916. elif type == '3d-raster':
  917. return data['volume']['object']['id']
  918. return -1
  919. def SaveToFile(self, FileName, FileType, width, height):
  920. """!This draws the DC to a buffer that can be saved to a file.
  921. @todo fix BufferedPaintDC
  922. @param FileName file name
  923. @param FileType type of bitmap
  924. @param width image width
  925. @param height image height
  926. """
  927. self._display.SaveToFile(FileName, width, height)
  928. # pbuffer = wx.EmptyBitmap(max(1, self.Map.width), max(1, self.Map.height))
  929. # dc = wx.BufferedPaintDC(self, pbuffer)
  930. # dc.Clear()
  931. # self.SetCurrent()
  932. # self._display.Draw(False, -1)
  933. # pbuffer.SaveFile(FileName, FileType)
  934. # self.SwapBuffers()
  935. def GetDisplay(self):
  936. """!Get display instance"""
  937. return self._display
  938. def ZoomToMap(self):
  939. """!Reset view
  940. """
  941. self.lmgr.nviz.OnResetView(None)