GRASS Programmer's Manual
6.4.2(2012)
|
00001 """ 00002 @package nviz_mapdisp.py 00003 00004 @brief Nviz extension for wxGUI 00005 00006 This module implements 3D visualization mode of map display. 00007 00008 List of classes: 00009 - GLWindow 00010 00011 (C) 2008-2009 by the GRASS Development Team 00012 00013 This program is free software under the GNU General Public 00014 License (>=v2). Read the file COPYING that comes with GRASS 00015 for details. 00016 00017 @author Martin Landa <landa.martin gmail.com> (Google SoC 2008) 00018 """ 00019 00020 import os 00021 import sys 00022 import time 00023 import copy 00024 import math 00025 00026 from threading import Thread 00027 00028 import wx 00029 import wx.lib.scrolledpanel as scrolled 00030 from wx.lib.newevent import NewEvent 00031 from wx import glcanvas 00032 00033 import gcmd 00034 import globalvar 00035 from debug import Debug 00036 from mapdisp_window import MapWindow 00037 from goutput import wxCmdOutput 00038 from preferences import globalSettings as UserSettings 00039 from workspace import Nviz as NvizDefault 00040 00041 try: 00042 import wxnviz 00043 except (ImportError, NameError): 00044 pass 00045 00046 wxUpdateProperties, EVT_UPDATE_PROP = NewEvent() 00047 wxUpdateView, EVT_UPDATE_VIEW = NewEvent() 00048 wxUpdateLight, EVT_UPDATE_LIGHT = NewEvent() 00049 00050 class NvizThread(Thread): 00051 def __init__(self, log, progressbar, window): 00052 Thread.__init__(self) 00053 00054 self.log = log 00055 self.progressbar = progressbar 00056 self.window = window 00057 00058 self._display = None 00059 00060 self.setDaemon(True) 00061 00062 def run(self): 00063 self._display = wxnviz.Nviz(self.log, self.progressbar) 00064 00065 def GetDisplay(self): 00066 """!Get display instance""" 00067 return self._display 00068 00069 class GLWindow(MapWindow, glcanvas.GLCanvas): 00070 """!OpenGL canvas for Map Display Window""" 00071 def __init__(self, parent, id = wx.ID_ANY, 00072 Map = None, tree = None, lmgr = None): 00073 self.parent = parent # MapFrame 00074 00075 glcanvas.GLCanvas.__init__(self, parent, id) 00076 MapWindow.__init__(self, parent, id, 00077 Map, tree, lmgr) 00078 self.Hide() 00079 00080 self.init = False 00081 self.initView = False 00082 00083 # render mode 00084 self.render = { 'quick' : False, 00085 # do not render vector lines in quick mode 00086 'vlines' : False, 00087 'vpoints' : False } 00088 00089 # list of loaded map layers (layer tree items) 00090 self.layers = list() 00091 # list of query points 00092 self.qpoints = list() 00093 00094 # 00095 # use display region instead of computational 00096 # 00097 os.environ['GRASS_REGION'] = self.Map.SetRegion() 00098 00099 # 00100 # create nviz instance 00101 # 00102 if self.lmgr: 00103 self.log = self.lmgr.goutput 00104 logerr = self.lmgr.goutput.GetLog(err = True) 00105 logmsg = self.lmgr.goutput.GetLog() 00106 else: 00107 self.log = logmsg = sys.stdout 00108 logerr = sys.stderr 00109 00110 self.nvizThread = NvizThread(logerr, 00111 self.parent.statusbarWin['progress'], 00112 logmsg) 00113 self.nvizThread.start() 00114 time.sleep(.1) 00115 self._display = self.nvizThread.GetDisplay() 00116 00117 # GRASS_REGION needed only for initialization 00118 del os.environ['GRASS_REGION'] 00119 00120 self.img = wx.Image(self.Map.mapfile, wx.BITMAP_TYPE_ANY) 00121 00122 # size of MapWindow, to avoid resizing if size is the same 00123 self.size = (0,0) 00124 00125 # 00126 # default values 00127 # 00128 self.view = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'view')) # copy 00129 self.iview = UserSettings.Get(group = 'nviz', key = 'view', internal = True) 00130 00131 self.nvizDefault = NvizDefault() 00132 self.light = copy.deepcopy(UserSettings.Get(group = 'nviz', key = 'light')) # copy 00133 00134 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) 00135 self.Bind(wx.EVT_SIZE, self.OnSize) 00136 self.Bind(wx.EVT_PAINT, self.OnPaint) 00137 self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) 00138 self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseAction) 00139 self.Bind(wx.EVT_MOTION, self.OnMotion) 00140 00141 self.Bind(EVT_UPDATE_PROP, self.UpdateMapObjProperties) 00142 self.Bind(EVT_UPDATE_VIEW, self.UpdateView) 00143 self.Bind(EVT_UPDATE_LIGHT, self.UpdateLight) 00144 00145 self.Bind(wx.EVT_CLOSE, self.OnClose) 00146 00147 def OnClose(self, event): 00148 # cleanup when window actually closes (on quit) and not just is hidden 00149 self.Reset() 00150 00151 def OnEraseBackground(self, event): 00152 pass # do nothing, to avoid flashing on MSW 00153 00154 def OnSize(self, event): 00155 size = self.GetClientSize() 00156 if self.size != size \ 00157 and self.GetContext(): 00158 Debug.msg(3, "GLCanvas.OnSize(): w = %d, h = %d" % \ 00159 (size.width, size.height)) 00160 self.SetCurrent() 00161 self._display.ResizeWindow(size.width, 00162 size.height) 00163 self.size = size 00164 event.Skip() 00165 00166 def OnPaint(self, event): 00167 Debug.msg(1, "GLCanvas.OnPaint()") 00168 00169 dc = wx.PaintDC(self) 00170 self.SetCurrent() 00171 00172 if not self.initView: 00173 self._display.InitView() 00174 self.initView = True 00175 00176 self.LoadDataLayers() 00177 self.UnloadDataLayers() 00178 00179 if not self.init: 00180 self.ResetView() 00181 00182 if hasattr(self.lmgr, "nviz"): 00183 self.lmgr.nviz.UpdatePage('view') 00184 self.lmgr.nviz.UpdatePage('light') 00185 layer = self.GetSelectedLayer() 00186 if layer: 00187 if layer.type == 'raster': 00188 self.lmgr.nviz.UpdatePage('surface') 00189 self.lmgr.nviz.UpdatePage('fringe') 00190 elif layer.type == 'vector': 00191 self.lmgr.nviz.UpdatePage('vector') 00192 00193 ### self.lmgr.nviz.UpdateSettings() 00194 00195 # update widgets 00196 win = self.lmgr.nviz.FindWindowById( \ 00197 self.lmgr.nviz.win['vector']['lines']['surface']) 00198 win.SetItems(self.GetLayerNames('raster')) 00199 00200 self.init = True 00201 00202 self.UpdateMap() 00203 00204 def OnMouseAction(self, event): 00205 # change perspective with mouse wheel 00206 wheel = event.GetWheelRotation() 00207 00208 if wheel != 0: 00209 current = event.GetPositionTuple()[:] 00210 Debug.msg (5, "GLWindow.OnMouseMotion(): wheel = %d" % wheel) 00211 prev_value = self.view['persp']['value'] 00212 if wheel > 0: 00213 value = -1 * self.view['persp']['step'] 00214 else: 00215 value = self.view['persp']['step'] 00216 self.view['persp']['value'] += value 00217 if self.view['persp']['value'] < 1: 00218 self.view['persp']['value'] = 1 00219 elif self.view['persp']['value'] > 100: 00220 self.view['persp']['value'] = 100 00221 00222 if prev_value != self.view['persp']['value']: 00223 if hasattr(self.lmgr, "nviz"): 00224 self.lmgr.nviz.UpdateSettings() 00225 00226 self._display.SetView(self.view['position']['x'], self.view['position']['y'], 00227 self.iview['height']['value'], 00228 self.view['persp']['value'], 00229 self.view['twist']['value']) 00230 00231 # redraw map 00232 self.OnPaint(None) 00233 00234 # update statusbar 00235 ### self.parent.StatusbarUpdate() 00236 00237 event.Skip() 00238 00239 def Pixel2Cell(self, (x, y)): 00240 """!Convert image coordinates to real word coordinates 00241 00242 @param x, y image coordinates 00243 00244 @return easting, northing 00245 @return None on error 00246 """ 00247 size = self.GetClientSize() 00248 # UL -> LL 00249 sid, x, y, z = self._display.GetPointOnSurface(x, y) 00250 00251 if not sid: 00252 return None 00253 00254 return (x, y) 00255 00256 def OnLeftUp(self, event): 00257 self.ReleaseMouse() 00258 if self.mouse["use"] == "nvizQuerySurface": 00259 self.OnQuerySurface(event) 00260 elif self.mouse["use"] == "nvizQueryVector": 00261 self.OnQueryVector(event) 00262 00263 def OnQuerySurface(self, event): 00264 """!Query surface on given position""" 00265 result = self._display.QueryMap(event.GetX(), event.GetY()) 00266 if result: 00267 self.qpoints.append((result['x'], result['y'], result['z'])) 00268 self.log.WriteLog("%-30s: %.3f" % (_("Easting"), result['x'])) 00269 self.log.WriteLog("%-30s: %.3f" % (_("Northing"), result['y'])) 00270 self.log.WriteLog("%-30s: %.3f" % (_("Elevation"), result['z'])) 00271 self.log.WriteLog("%-30s: %s" % (_("Surface map elevation"), result['elevation'])) 00272 self.log.WriteLog("%-30s: %s" % (_("Surface map color"), result['color'])) 00273 if len(self.qpoints) > 1: 00274 prev = self.qpoints[-2] 00275 curr = self.qpoints[-1] 00276 dxy = math.sqrt(pow(prev[0]-curr[0], 2) + 00277 pow(prev[1]-curr[1], 2)) 00278 dxyz = math.sqrt(pow(prev[0]-curr[0], 2) + 00279 pow(prev[1]-curr[1], 2) + 00280 pow(prev[2]-curr[2], 2)) 00281 self.log.WriteLog("%-30s: %.3f" % (_("XY distance from previous"), dxy)) 00282 self.log.WriteLog("%-30s: %.3f" % (_("XYZ distance from previous"), dxyz)) 00283 self.log.WriteLog("%-30s: %.3f" % (_("Distance along surface"), 00284 self._display.GetDistanceAlongSurface(result['id'], 00285 (curr[0], curr[1]), 00286 (prev[0], prev[1]), 00287 useExag = False))) 00288 self.log.WriteLog("%-30s: %.3f" % (_("Distance along exag. surface"), 00289 self._display.GetDistanceAlongSurface(result['id'], 00290 (curr[0], curr[1]), 00291 (prev[0], prev[1]), 00292 useExag = True))) 00293 self.log.WriteCmdLog('-' * 80) 00294 else: 00295 self.log.WriteLog(_("No point on surface")) 00296 self.log.WriteCmdLog('-' * 80) 00297 00298 def OnQueryVector(self, event): 00299 """!Query vector on given position""" 00300 self.log.WriteWarning(_("Function not implemented yet")) 00301 self.log.WriteCmdLog('-' * 80) 00302 00303 def UpdateView(self, event): 00304 """!Change view settings""" 00305 data = self.view 00306 self._display.SetView(data['position']['x'], data['position']['y'], 00307 self.iview['height']['value'], 00308 data['persp']['value'], 00309 data['twist']['value']) 00310 00311 if event and event.zExag and 'value' in data['z-exag']: 00312 self._display.SetZExag(data['z-exag']['value']) 00313 00314 if event: 00315 event.Skip() 00316 00317 def UpdateLight(self, event): 00318 """!Change light settings""" 00319 data = self.light 00320 self._display.SetLight(x = data['position']['x'], y = data['position']['y'], 00321 z = data['position']['z'] / 100., color = data['color'], 00322 bright = data['bright'] / 100., 00323 ambient = data['ambient'] / 100.) 00324 self._display.DrawLightingModel() 00325 00326 def UpdateMap(self, render = True): 00327 """!Updates the canvas anytime there is a change to the 00328 underlaying images or to the geometry of the canvas. 00329 00330 @param render re-render map composition 00331 """ 00332 start = time.clock() 00333 00334 self.resize = False 00335 00336 if self.render['quick'] is False: 00337 self.parent.statusbarWin['progress'].Show() 00338 self.parent.statusbarWin['progress'].SetRange(2) 00339 self.parent.statusbarWin['progress'].SetValue(0) 00340 00341 if self.render['quick'] is False: 00342 self.parent.statusbarWin['progress'].SetValue(1) 00343 self._display.Draw(False, -1) 00344 elif self.render['quick'] is True: 00345 # quick 00346 mode = wxnviz.DRAW_QUICK_SURFACE | wxnviz.DRAW_QUICK_VOLUME 00347 if self.render['vlines']: 00348 mode |= wxnviz.DRAW_QUICK_VLINES 00349 if self.render['vpoints']: 00350 mode |= wxnviz.DRAW_QUICK_VPOINTS 00351 self._display.Draw(True, mode) 00352 else: # None -> reuse last rendered image 00353 pass # TODO 00354 00355 self.SwapBuffers() 00356 00357 stop = time.clock() 00358 00359 if self.render['quick'] is False: 00360 self.parent.statusbarWin['progress'].SetValue(2) 00361 # hide process bar 00362 self.parent.statusbarWin['progress'].Hide() 00363 00364 Debug.msg(3, "GLWindow.UpdateMap(): quick = %d, -> time = %g" % \ 00365 (self.render['quick'], (stop-start))) 00366 00367 def EraseMap(self): 00368 """!Erase the canvas 00369 """ 00370 self._display.EraseMap() 00371 self.SwapBuffers() 00372 00373 def IsLoaded(self, item): 00374 """!Check if layer (item) is already loaded 00375 00376 @param item layer item 00377 """ 00378 layer = self.tree.GetPyData(item)[0]['maplayer'] 00379 data = self.tree.GetPyData(item)[0]['nviz'] 00380 00381 if not data: 00382 return 0 00383 00384 if layer.type == 'raster': 00385 if 'object' not in data['surface']: 00386 return 0 00387 elif layer.type == 'vector': 00388 if 'object' not in data['vlines'] and \ 00389 'object' not in data['points']: 00390 return 0 00391 00392 return 1 00393 00394 def _GetDataLayers(self, item, litems): 00395 """!Return get list of enabled map layers""" 00396 # load raster & vector maps 00397 while item and item.IsOk(): 00398 type = self.tree.GetPyData(item)[0]['type'] 00399 if type == 'group': 00400 subItem = self.tree.GetFirstChild(item)[0] 00401 self._GetDataLayers(subItem, litems) 00402 item = self.tree.GetNextSibling(item) 00403 00404 if not item.IsChecked() or \ 00405 type not in ('raster', 'vector', '3d-raster'): 00406 item = self.tree.GetNextSibling(item) 00407 continue 00408 00409 litems.append(item) 00410 00411 item = self.tree.GetNextSibling(item) 00412 00413 def LoadDataLayers(self): 00414 """!Load raster/vector from current layer tree 00415 00416 @todo volumes 00417 """ 00418 if not self.tree: 00419 return 00420 00421 listOfItems = [] 00422 item = self.tree.GetFirstChild(self.tree.root)[0] 00423 self._GetDataLayers(item, listOfItems) 00424 00425 start = time.time() 00426 00427 while(len(listOfItems) > 0): 00428 item = listOfItems.pop() 00429 type = self.tree.GetPyData(item)[0]['type'] 00430 if item in self.layers: 00431 continue 00432 try: 00433 if type == 'raster': 00434 self.LoadRaster(item) 00435 elif type == '3d-raster': 00436 self.LoadRaster3d(item) 00437 elif type == 'vector': 00438 # data = self.tree.GetPyData(item)[0]['nviz'] 00439 # vecType = [] 00440 # if data and 'vector' in data: 00441 # for v in ('lines', 'points'): 00442 # if data['vector'][v]: 00443 # vecType.append(v) 00444 layer = self.tree.GetPyData(item)[0]['maplayer'] 00445 npoints, nlines, nfeatures, mapIs3D = self.lmgr.nviz.VectorInfo(layer) 00446 if npoints > 0: 00447 self.LoadVector(item, points = True) 00448 if nlines > 0: 00449 self.LoadVector(item, points = False) 00450 except gcmd.GException, e: 00451 GError(parent = self, 00452 message = e.value) 00453 self.init = False 00454 00455 stop = time.time() 00456 00457 Debug.msg(3, "GLWindow.LoadDataLayers(): time = %f" % (stop-start)) 00458 00459 def UnloadDataLayers(self): 00460 """!Unload any layers that have been deleted from layer tree""" 00461 if not self.tree: 00462 return 00463 00464 listOfItems = [] 00465 item = self.tree.GetFirstChild(self.tree.root)[0] 00466 self._GetDataLayers(item, listOfItems) 00467 00468 start = time.time() 00469 00470 for layer in self.layers: 00471 if layer not in listOfItems: 00472 ltype = self.tree.GetPyData(layer)[0]['type'] 00473 try: 00474 if ltype == 'raster': 00475 self.UnloadRaster(layer) 00476 elif ltype == '3d-raster': 00477 self.UnloadRaster3d(layer) 00478 elif ltype == 'vector': 00479 self.UnloadVector(layer, True) 00480 self.UnloadVector(layer, False) 00481 00482 self.UpdateView(None) 00483 except gcmd.GException, e: 00484 gcmd.GError(parent = self, 00485 message = e.value) 00486 00487 self.lmgr.nviz.UpdateSettings() 00488 00489 stop = time.time() 00490 00491 Debug.msg(3, "GLWindow.UnloadDataLayers(): time = %f" % (stop-start)) 00492 00493 def SetVectorFromCmd(self, item, data): 00494 """!Set 3D view properties from cmd (d.vect) 00495 00496 @param item Layer Tree item 00497 @param nviz data 00498 """ 00499 cmd = self.tree.GetPyData(item)[0]['cmd'] 00500 if cmd[0] != 'd.vect': 00501 return 00502 for opt in cmd[1:]: 00503 try: 00504 key, value = opt.split('=') 00505 except ValueError: 00506 continue 00507 if key == 'color': 00508 data['lines']['color']['value'] = value 00509 data['points']['color']['value'] = value 00510 00511 def SetMapObjProperties(self, item, id, nvizType): 00512 """!Set map object properties 00513 00514 Properties must be afterwards updated by 00515 UpdateMapObjProperties(). 00516 00517 @param item layer item 00518 @param id nviz layer id (or -1) 00519 @param nvizType nviz data type (surface, points, vector) 00520 """ 00521 type = self.tree.GetPyData(item)[0]['maplayer'].type 00522 # reference to original layer properties (can be None) 00523 data = self.tree.GetPyData(item)[0]['nviz'] 00524 00525 if not data: 00526 # init data structure 00527 self.tree.GetPyData(item)[0]['nviz'] = {} 00528 data = self.tree.GetPyData(item)[0]['nviz'] 00529 00530 if type == 'raster': 00531 # reset to default properties 00532 data[nvizType] = self.nvizDefault.SetSurfaceDefaultProp() 00533 00534 elif type == 'vector': 00535 # reset to default properties (lines/points) 00536 data['vector'] = self.nvizDefault.SetVectorDefaultProp() 00537 self.SetVectorFromCmd(item, data['vector']) 00538 00539 elif type == '3d-raster': 00540 # reset to default properties 00541 data[nvizType] = self.nvizDefault.SetVolumeDefaultProp() 00542 00543 else: 00544 # complete data (use default values) 00545 if type == 'raster': 00546 data['surface'] = self.nvizDefault.SetSurfaceDefaultProp() 00547 if type == 'vector': 00548 if not data['vector']['lines']: 00549 self.nvizDefault.SetVectorLinesDefaultProp(data['vector']['lines']) 00550 if not data['vector']['points']: 00551 self.nvizDefault.SetVectorPointsDefaultProp(data['vector']['points']) 00552 00553 # set updates 00554 for sec in data.keys(): 00555 for sec1 in data[sec].keys(): 00556 for sec2 in data[sec][sec1].keys(): 00557 if sec2 != 'all': 00558 data[sec][sec1][sec2]['update'] = None 00559 00560 event = wxUpdateProperties(data = data) 00561 wx.PostEvent(self, event) 00562 00563 # set id 00564 if id > 0: 00565 if type in ('raster', '3d-raster'): 00566 data[nvizType]['object'] = { 'id' : id, 00567 'init' : False } 00568 elif type == 'vector': 00569 data['vector'][nvizType]['object'] = { 'id' : id, 00570 'init' : False } 00571 00572 return data 00573 00574 def LoadRaster(self, item): 00575 """!Load 2d raster map and set surface attributes 00576 00577 @param layer item 00578 """ 00579 return self._loadRaster(item) 00580 00581 def LoadRaster3d(self, item): 00582 """!Load 3d raster map and set surface attributes 00583 00584 @param layer item 00585 """ 00586 return self._loadRaster(item) 00587 00588 def _loadRaster(self, item): 00589 """!Load 2d/3d raster map and set its attributes 00590 00591 @param layer item 00592 """ 00593 layer = self.tree.GetPyData(item)[0]['maplayer'] 00594 00595 if layer.type not in ('raster', '3d-raster'): 00596 return 00597 00598 if layer.type == 'raster': 00599 id = self._display.LoadSurface(str(layer.name), None, None) 00600 nvizType = 'surface' 00601 errorMsg = _("Loading raster map") 00602 elif layer.type == '3d-raster': 00603 id = self._display.LoadVolume(str(layer.name), None, None) 00604 nvizType = 'volume' 00605 errorMsg = _("Loading 3d raster map") 00606 else: 00607 id = -1 00608 00609 if id < 0: 00610 if layer.type in ('raster', '3d-raster'): 00611 self.log.WriteError("%s <%s> %s" % (errorMsg, layer.name, _("failed"))) 00612 else: 00613 self.log.WriteError(_("Unsupported layer type '%s'") % layer.type) 00614 00615 self.layers.append(item) 00616 00617 # set default/workspace layer properties 00618 data = self.SetMapObjProperties(item, id, nvizType) 00619 00620 # update properties 00621 event = wxUpdateProperties(data = data) 00622 wx.PostEvent(self, event) 00623 00624 # update tools window 00625 if hasattr(self.lmgr, "nviz") and \ 00626 item == self.GetSelectedLayer(type = 'item'): 00627 toolWin = self.lmgr.nviz 00628 if layer.type == 'raster': 00629 win = toolWin.FindWindowById( \ 00630 toolWin.win['vector']['lines']['surface']) 00631 win.SetItems(self.GetLayerNames(layer.type)) 00632 00633 #toolWin.UpdatePage(nvizType) 00634 #toolWin.SetPage(nvizType) 00635 00636 return id 00637 00638 def UnloadRaster(self, item): 00639 """!Unload 2d raster map 00640 00641 @param layer item 00642 """ 00643 return self._unloadRaster(item) 00644 00645 def UnloadRaster3d(self, item): 00646 """!Unload 3d raster map 00647 00648 @param layer item 00649 """ 00650 return self._unloadRaster(item) 00651 00652 def _unloadRaster(self, item): 00653 """!Unload 2d/3d raster map 00654 00655 @param item layer item 00656 """ 00657 layer = self.tree.GetPyData(item)[0]['maplayer'] 00658 00659 if layer.type not in ('raster', '3d-raster'): 00660 return 00661 00662 data = self.tree.GetPyData(item)[0]['nviz'] 00663 00664 if layer.type == 'raster': 00665 nvizType = 'surface' 00666 unloadFn = self._display.UnloadSurface 00667 errorMsg = _("Unable to unload raster map") 00668 successMsg = _("Raster map") 00669 else: 00670 nvizType = 'volume' 00671 unloadFn = self._display.UnloadVolume 00672 errorMsg = _("Unable to unload 3d raster map") 00673 successMsg = _("3d raster map") 00674 00675 id = data[nvizType]['object']['id'] 00676 00677 if unloadFn(id) == 0: 00678 self.log.WriteError("%s <%s>" % (errorMsg, layer.name)) 00679 else: 00680 self.log.WriteLog("%s <%s> %s" % (successMsg, layer.name, _("unloaded successfully"))) 00681 00682 data[nvizType].pop('object') 00683 00684 self.layers.remove(item) 00685 00686 # update tools window 00687 if hasattr(self.lmgr, "nviz") and \ 00688 layer.type == 'raster': 00689 toolWin = self.lmgr.nviz 00690 win = toolWin.FindWindowById( \ 00691 toolWin.win['vector']['lines']['surface']) 00692 win.SetItems(self.GetLayerNames(layer.type)) 00693 00694 def LoadVector(self, item, points = None): 00695 """!Load 2D or 3D vector map overlay 00696 00697 @param item layer item 00698 @param points True to load points, False to load lines, None 00699 to load both 00700 """ 00701 layer = self.tree.GetPyData(item)[0]['maplayer'] 00702 if layer.type != 'vector': 00703 return 00704 00705 # set default properties 00706 if points is None: 00707 self.SetMapObjProperties(item, -1, 'lines') 00708 self.SetMapObjProperties(item, -1, 'points') 00709 vecTypes = ('points', 'lines') 00710 elif points: 00711 self.SetMapObjProperties(item, -1, 'points') 00712 vecTypes = ('points', ) 00713 else: 00714 self.SetMapObjProperties(item, -1, 'lines') 00715 vecTypes = ('lines', ) 00716 00717 id = -1 00718 for vecType in vecTypes: 00719 if vecType == 'lines': 00720 id = self._display.LoadVector(str(layer.GetName()), False) 00721 else: 00722 id = self._display.LoadVector(str(layer.GetName()), True) 00723 if id < 0: 00724 self.log.WriteError(_("Loading vector map <%(name)s> (%(type)s) failed") % \ 00725 { 'name' : layer.name, 'type' : vecType }) 00726 # update layer properties 00727 self.SetMapObjProperties(item, id, vecType) 00728 00729 self.layers.append(item) 00730 00731 # update properties 00732 data = self.tree.GetPyData(item)[0]['nviz'] 00733 event = wxUpdateProperties(data = data) 00734 wx.PostEvent(self, event) 00735 00736 # update tools window 00737 if hasattr(self.lmgr, "nviz") and \ 00738 item == self.GetSelectedLayer(type = 'item'): 00739 toolWin = self.lmgr.nviz 00740 00741 toolWin.UpdatePage('vector') 00742 ### toolWin.SetPage('vector') 00743 00744 return id 00745 00746 def UnloadVector(self, item, points = None): 00747 """!Unload vector map overlay 00748 00749 @param item layer item 00750 @param points,lines True to unload given feature type 00751 """ 00752 layer = self.tree.GetPyData(item)[0]['maplayer'] 00753 data = self.tree.GetPyData(item)[0]['nviz']['vector'] 00754 00755 # if vecType is None: 00756 # vecType = [] 00757 # for v in ('lines', 'points'): 00758 # if UserSettings.Get(group = 'nviz', key = 'vector', 00759 # subkey = [v, 'show']): 00760 # vecType.append(v) 00761 00762 if points is None: 00763 vecTypes = ('points', 'lines') 00764 elif points: 00765 vecTypes = ('points', ) 00766 else: 00767 vecTypes = ('lines', ) 00768 00769 for vecType in vecTypes: 00770 if 'object' not in data[vecType]: 00771 continue 00772 00773 id = data[vecType]['object']['id'] 00774 00775 if vecType == 'lines': 00776 ret = self._display.UnloadVector(id, False) 00777 else: 00778 ret = self._display.UnloadVector(id, True) 00779 if ret == 0: 00780 self.log.WriteError(_("Unable to unload vector map <%(name)s> (%(type)s)") % \ 00781 { 'name': layer.name, 'type' : vecType }) 00782 else: 00783 self.log.WriteLog(_("Vector map <%(name)s> (%(type)s) unloaded successfully") % \ 00784 { 'name' : layer.name, 'type' : vecType }) 00785 00786 data[vecType].pop('object') 00787 00788 ### self.layers.remove(id) 00789 00790 def Reset(self): 00791 """!Reset (unload data)""" 00792 for item in self.layers: 00793 type = self.tree.GetPyData(item)[0]['maplayer'].type 00794 if type == 'raster': 00795 self.UnloadRaster(item) 00796 elif type == '3d-raster': 00797 self.UnloadRaster3d(item) 00798 elif type == 'vector': 00799 self.UnloadVector(item) 00800 00801 self.init = False 00802 00803 def OnZoomToMap(self, event): 00804 """!Set display extents to match selected raster or vector 00805 map or volume. 00806 00807 @todo vector, volume 00808 """ 00809 layer = self.GetSelectedLayer() 00810 00811 if layer is None: 00812 return 00813 00814 Debug.msg (3, "GLWindow.OnZoomToMap(): layer = %s, type = %s" % \ 00815 (layer.name, layer.type)) 00816 00817 self._display.SetViewportDefault() 00818 00819 def ResetView(self): 00820 """!Reset to default view""" 00821 self.view['z-exag']['value'], \ 00822 self.iview['height']['value'], \ 00823 self.iview['height']['min'], \ 00824 self.iview['height']['max'] = self._display.SetViewDefault() 00825 00826 self.view['z-exag']['min'] = 0 00827 self.view['z-exag']['max'] = self.view['z-exag']['value'] * 10 00828 00829 self.view['position']['x'] = UserSettings.Get(group = 'nviz', key = 'view', 00830 subkey = ('position', 'x')) 00831 self.view['position']['y'] = UserSettings.Get(group = 'nviz', key = 'view', 00832 subkey = ('position', 'y')) 00833 self.view['persp']['value'] = UserSettings.Get(group = 'nviz', key = 'view', 00834 subkey = ('persp', 'value')) 00835 00836 self.view['twist']['value'] = UserSettings.Get(group = 'nviz', key = 'view', 00837 subkey = ('twist', 'value')) 00838 00839 event = wxUpdateView(zExag = False) 00840 wx.PostEvent(self, event) 00841 00842 def UpdateMapObjProperties(self, event): 00843 """!Generic method to update data layer properties""" 00844 data = event.data 00845 00846 if 'surface' in data: 00847 id = data['surface']['object']['id'] 00848 self.UpdateSurfaceProperties(id, data['surface']) 00849 # -> initialized 00850 data['surface']['object']['init'] = True 00851 00852 elif 'volume' in data: 00853 id = data['volume']['object']['id'] 00854 self.UpdateVolumeProperties(id, data['volume']) 00855 # -> initialized 00856 data['volume']['object']['init'] = True 00857 00858 elif 'vector' in data: 00859 for type in ('lines', 'points'): 00860 if 'object' in data['vector'][type]: 00861 id = data['vector'][type]['object']['id'] 00862 self.UpdateVectorProperties(id, data['vector'], type) 00863 # -> initialized 00864 data['vector'][type]['object']['init'] = True 00865 00866 def UpdateSurfaceProperties(self, id, data): 00867 """!Update surface map object properties""" 00868 # surface attributes 00869 for attrb in ('topo', 'color', 'mask', 00870 'transp', 'shine', 'emit'): 00871 if attrb not in data['attribute'] or \ 00872 'update' not in data['attribute'][attrb]: 00873 continue 00874 00875 map = data['attribute'][attrb]['map'] 00876 value = data['attribute'][attrb]['value'] 00877 00878 if map is None: # unset 00879 # only optional attributes 00880 if attrb == 'mask': 00881 # TODO: invert mask 00882 # TODO: broken in NVIZ 00883 self._display.UnsetSurfaceMask(id) 00884 elif attrb == 'transp': 00885 self._display.UnsetSurfaceTransp(id) 00886 elif attrb == 'emit': 00887 self._display.UnsetSurfaceEmit(id) 00888 else: 00889 if type(value) == type('') and \ 00890 len(value) <= 0: # ignore empty values (TODO: warning) 00891 continue 00892 if attrb == 'topo': 00893 self._display.SetSurfaceTopo(id, map, str(value)) 00894 elif attrb == 'color': 00895 self._display.SetSurfaceColor(id, map, str(value)) 00896 elif attrb == 'mask': 00897 # TODO: invert mask 00898 # TODO: broken in NVIZ 00899 self._display.SetSurfaceMask(id, False, str(value)) 00900 elif attrb == 'transp': 00901 self._display.SetSurfaceTransp(id, map, str(value)) 00902 elif attrb == 'shine': 00903 self._display.SetSurfaceShine(id, map, str(value)) 00904 elif attrb == 'emit': 00905 self._display.SetSurfaceEmit(id, map, str(value)) 00906 data['attribute'][attrb].pop('update') 00907 00908 # draw res 00909 if 'update' in data['draw']['resolution']: 00910 coarse = data['draw']['resolution']['coarse'] 00911 fine = data['draw']['resolution']['fine'] 00912 00913 if data['draw']['all']: 00914 self._display.SetSurfaceRes(-1, fine, coarse) 00915 else: 00916 self._display.SetSurfaceRes(id, fine, coarse) 00917 data['draw']['resolution'].pop('update') 00918 00919 # draw style 00920 if 'update' in data['draw']['mode']: 00921 if data['draw']['mode']['value'] < 0: # need to calculate 00922 data['draw']['mode']['value'] = \ 00923 self.nvizDefault.GetDrawMode(mode = data['draw']['mode']['desc']['mode'], 00924 style = data['draw']['mode']['desc']['style'], 00925 shade = data['draw']['mode']['desc']['shading'], 00926 string = True) 00927 style = data['draw']['mode']['value'] 00928 if data['draw']['all']: 00929 self._display.SetSurfaceStyle(-1, style) 00930 else: 00931 self._display.SetSurfaceStyle(id, style) 00932 data['draw']['mode'].pop('update') 00933 00934 # wire color 00935 if 'update' in data['draw']['wire-color']: 00936 color = data['draw']['wire-color']['value'] 00937 if data['draw']['all']: 00938 self._display.SetWireColor(-1, str(color)) 00939 else: 00940 self._display.SetWireColor(id, str(color)) 00941 data['draw']['wire-color'].pop('update') 00942 00943 # position 00944 if 'update' in data['position']: 00945 x = data['position']['x'] 00946 y = data['position']['y'] 00947 z = data['position']['z'] 00948 self._display.SetSurfacePosition(id, x, y, z) 00949 data['position'].pop('update') 00950 data['draw']['all'] = False 00951 00952 def UpdateVolumeProperties(self, id, data, isosurfId = None): 00953 """!Update volume (isosurface/slice) map object properties""" 00954 if 'update' in data['draw']['resolution']: 00955 self._display.SetIsosurfaceRes(id, data['draw']['resolution']['value']) 00956 data['draw']['resolution'].pop('update') 00957 00958 if 'update' in data['draw']['shading']: 00959 if data['draw']['shading']['value'] < 0: # need to calculate 00960 data['draw']['shading']['value'] = \ 00961 self.nvizDefault.GetDrawMode(shade = data['draw']['shading'], 00962 string = False) 00963 data['draw']['shading'].pop('update') 00964 00965 # 00966 # isosurface attributes 00967 # 00968 isosurfId = 0 00969 for isosurf in data['isosurface']: 00970 for attrb in ('color', 'mask', 00971 'transp', 'shine', 'emit'): 00972 if attrb not in isosurf or \ 00973 'update' not in isosurf[attrb]: 00974 continue 00975 map = isosurf[attrb]['map'] 00976 value = isosurf[attrb]['value'] 00977 00978 if map is None: # unset 00979 # only optional attributes 00980 if attrb == 'mask': 00981 # TODO: invert mask 00982 # TODO: broken in NVIZ 00983 self._display.UnsetIsosurfaceMask(id, isosurfId) 00984 elif attrb == 'transp': 00985 self._display.UnsetIsosurfaceTransp(id, isosurfId) 00986 elif attrb == 'emit': 00987 self._display.UnsetIsosurfaceEmit(id, isosurfId) 00988 else: 00989 if type(value) == type('') and \ 00990 len(value) <= 0: # ignore empty values (TODO: warning) 00991 continue 00992 elif attrb == 'color': 00993 self._display.SetIsosurfaceColor(id, isosurfId, map, str(value)) 00994 elif attrb == 'mask': 00995 # TODO: invert mask 00996 # TODO: broken in NVIZ 00997 self._display.SetIsosurfaceMask(id, isosurfId, False, str(value)) 00998 elif attrb == 'transp': 00999 self._display.SetIsosurfaceTransp(id, isosurfId, map, str(value)) 01000 elif attrb == 'shine': 01001 self._display.SetIsosurfaceShine(id, isosurfId, map, str(value)) 01002 elif attrb == 'emit': 01003 self._display.SetIsosurfaceEmit(id, isosurfId, map, str(value)) 01004 isosurf[attrb].pop('update') 01005 isosurfId += 1 01006 01007 def UpdateVectorProperties(self, id, data, type): 01008 """!Update vector layer properties 01009 01010 @param id layer id 01011 @param data properties 01012 @param type lines/points 01013 """ 01014 if type == 'points': 01015 self.UpdateVectorPointsProperties(id, data[type]) 01016 else: 01017 self.UpdateVectorLinesProperties(id, data[type]) 01018 01019 def UpdateVectorLinesProperties(self, id, data): 01020 """!Update vector line map object properties""" 01021 # mode 01022 if 'update' in data['color'] or \ 01023 'update' in data['width'] or \ 01024 'update' in data['mode']: 01025 width = data['width']['value'] 01026 color = data['color']['value'] 01027 if data['mode']['type'] == 'flat': 01028 flat = True 01029 if 'surface' in data: 01030 data.pop('surface') 01031 else: 01032 flat = False 01033 01034 self._display.SetVectorLineMode(id, color, 01035 width, flat) 01036 01037 if 'update' in data['color']: 01038 data['color'].pop('update') 01039 if 'update' in data['width']: 01040 data['width'].pop('update') 01041 if 'update' in data['mode']: 01042 data['mode'].pop('update') 01043 01044 # height 01045 if 'update' in data['height']: 01046 self._display.SetVectorLineHeight(id, 01047 data['height']['value']) 01048 data['height'].pop('update') 01049 01050 # surface 01051 if 'update' in data['mode']: 01052 sid = self.GetLayerId(type = 'raster', name = data['mode']['surface']) 01053 if sid > -1: 01054 self._display.SetVectorLineSurface(id, sid) 01055 01056 data['mode'].pop('update') 01057 01058 def UpdateVectorPointsProperties(self, id, data): 01059 """!Update vector point map object properties""" 01060 if 'update' in data['size'] or \ 01061 'update' in data['width'] or \ 01062 'update' in data['marker'] or \ 01063 'update' in data['color']: 01064 ret = self._display.SetVectorPointMode(id, data['color']['value'], 01065 data['width']['value'], float(data['size']['value']), 01066 data['marker']['value'] + 1) 01067 01068 error = None 01069 if ret == -1: 01070 error = _("Vector point layer not found (id = %d)") % id 01071 elif ret == -2: 01072 error = _("Unable to set data layer properties (id = %d)") % id 01073 01074 if error: 01075 raise gcmd.GException(_("Setting data layer properties failed.\n\n%s") % error) 01076 01077 for prop in ('size', 'width', 'marker', 'color'): 01078 if 'update' in data[prop]: 01079 data[prop].pop('update') 01080 01081 # height 01082 if 'update' in data['height']: 01083 self._display.SetVectorPointHeight(id, 01084 data['height']['value']) 01085 data['height'].pop('update') 01086 01087 # surface 01088 if 'update' in data['mode']: 01089 sid = self.GetLayerId(type = 'raster', name = data['mode']['surface']) 01090 if sid > -1: 01091 self._display.SetVectorPointSurface(id, sid) 01092 01093 data['mode'].pop('update') 01094 01095 def GetLayerNames(self, type): 01096 """!Return list of map layer names of given type""" 01097 layerName = [] 01098 01099 for item in self.layers: 01100 mapLayer = self.tree.GetPyData(item)[0]['maplayer'] 01101 if type != mapLayer.GetType(): 01102 continue 01103 01104 layerName.append(mapLayer.GetName()) 01105 01106 return layerName 01107 01108 def GetLayerId(self, type, name): 01109 """!Get layer object id or -1""" 01110 if len(name) < 1: 01111 return -1 01112 01113 for item in self.layers: 01114 mapLayer = self.tree.GetPyData(item)[0]['maplayer'] 01115 if type != mapLayer.GetType() or \ 01116 name != mapLayer.GetName(): 01117 continue 01118 01119 data = self.tree.GetPyData(item)[0]['nviz'] 01120 01121 if type == 'raster': 01122 return data['surface']['object']['id'] 01123 elif type == 'vpoint': 01124 return data['vector']['points']['object']['id'] 01125 elif type == 'vline': 01126 return data['vector']['lines']['object']['id'] 01127 elif type == '3d-raster': 01128 return data['volume']['object']['id'] 01129 01130 return -1 01131 01132 def SaveToFile(self, FileName, FileType, width, height): 01133 """!This draws the DC to a buffer that can be saved to a file. 01134 01135 @todo fix BufferedPaintDC 01136 01137 @param FileName file name 01138 @param FileType type of bitmap 01139 @param width image width 01140 @param height image height 01141 """ 01142 self._display.SaveToFile(FileName, width, height) 01143 01144 # pbuffer = wx.EmptyBitmap(max(1, self.Map.width), max(1, self.Map.height)) 01145 # dc = wx.BufferedPaintDC(self, pbuffer) 01146 # dc.Clear() 01147 # self.SetCurrent() 01148 # self._display.Draw(False, -1) 01149 # pbuffer.SaveFile(FileName, FileType) 01150 # self.SwapBuffers() 01151 01152 def GetDisplay(self): 01153 """!Get display instance""" 01154 return self._display 01155 01156 def ZoomToMap(self): 01157 """!Reset view 01158 """ 01159 self.lmgr.nviz.OnResetView(None) 01160