frame.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. """!
  2. @package iclass::frame
  3. @brief wxIClass frame with toolbar for digitizing training areas and
  4. for spectral signature analysis.
  5. Classes:
  6. - frame::IClassMapFrame
  7. - frame::MapManager
  8. (C) 2006-2011 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 Vaclav Petras <wenzeslaus gmail.com>
  13. @author Anna Kratochvilova <kratochanna gmail.com>
  14. """
  15. import os
  16. import sys
  17. #if __name__ == "__main__":
  18. sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "gui", "wxpython"))
  19. import copy
  20. import wx
  21. from ctypes import *
  22. from core import globalvar
  23. try:
  24. from grass.lib.imagery import *
  25. from grass.lib.vector import *
  26. except ImportError, e:
  27. sys.stderr.write(_("Loading imagery lib failed"))
  28. #sys.path.append(os.path.join(globalvar.ETCWXDIR, "icons"))
  29. import grass.script as grass
  30. from mapdisp import statusbar as sb
  31. from mapdisp.mapwindow import BufferedWindow
  32. from vdigit.toolbars import VDigitToolbar
  33. from gui_core.mapdisp import DoubleMapFrame
  34. from core.render import Map, MapLayer
  35. from core.gcmd import RunCommand, GMessage
  36. from gui_core.dialogs import SetOpacityDialog
  37. import grass.script as grass
  38. from iclass.digit import IClassVDigitWindow, IClassIVDigit
  39. from iclass.toolbars import IClassMapToolbar, IClassMiscToolbar,\
  40. IClassToolbar, IClassMapManagerToolbar
  41. from iclass.statistics import Statistics, BandStatistics
  42. from iclass.dialogs import CategoryListCtrl, IClassCategoryManagerDialog,\
  43. IClassGroupDialog, IClassMapDialog
  44. from iclass.plots import PlotPanel
  45. class IClassMapFrame(DoubleMapFrame):
  46. """! wxIClass main frame
  47. It has two map windows one for digitizing training areas and one for
  48. result preview.
  49. It generates histograms, raster maps and signature files using
  50. @c I_iclass_* functions from C imagery library.
  51. It is wxGUI counterpart of old i.class module.
  52. """
  53. def __init__(self, parent = None, title = _("Supervised Classification Tool"),
  54. toolbars = ["iClassMap", "iClassMisc", "vdigit", "iClass"],
  55. size = (800, 600), name = 'IClassWindow', **kwargs):
  56. """!
  57. @param parent (no parent is expected)
  58. @param title window title
  59. @param toolbars dictionary of active toolbars (defalult value represents all toolbars)
  60. @param size default size
  61. """
  62. DoubleMapFrame.__init__(self, parent = parent, title = title,
  63. name = name,
  64. firstMap = Map(), secondMap = Map(),
  65. **kwargs)
  66. self.firstMapWindow = IClassVDigitWindow(self, map = self.firstMap)
  67. self.secondMapWindow = BufferedWindow(self, Map = self.secondMap)
  68. self.MapWindow = self.firstMapWindow # current by default
  69. self._bindWindowsActivation()
  70. self.SetSize(size)
  71. #
  72. # Add toolbars
  73. #
  74. toolbarsCopy = toolbars[:]
  75. self.AddToolbar(toolbarsCopy.pop(0))
  76. if sys.platform == 'win32':
  77. toolbarsCopy.reverse()
  78. for toolb in toolbarsCopy:
  79. self.AddToolbar(toolb)
  80. self.firstMapWindow.SetToolbar(self.toolbars['vdigit'])
  81. self.GetMapToolbar().GetActiveMapTool().Bind(wx.EVT_CHOICE, self.OnUpdateActive)
  82. #
  83. # Add statusbar
  84. #
  85. # items for choice
  86. self.statusbarItems = [sb.SbCoordinates,
  87. sb.SbRegionExtent,
  88. sb.SbCompRegionExtent,
  89. sb.SbShowRegion,
  90. sb.SbAlignExtent,
  91. sb.SbResolution,
  92. sb.SbDisplayGeometry,
  93. sb.SbMapScale,
  94. sb.SbGoTo,
  95. sb.SbProjection]
  96. self.statusbarItemsHiddenInNviz = (sb.SbAlignExtent,
  97. sb.SbDisplayGeometry,
  98. sb.SbShowRegion,
  99. sb.SbResolution,
  100. sb.SbMapScale)
  101. # create statusbar and its manager
  102. statusbar = self.CreateStatusBar(number = 4, style = 0)
  103. statusbar.SetStatusWidths([-5, -2, -1, -1])
  104. self.statusbarManager = sb.SbManager(mapframe = self, statusbar = statusbar)
  105. # fill statusbar manager
  106. self.statusbarManager.AddStatusbarItemsByClass(self.statusbarItems, mapframe = self, statusbar = statusbar)
  107. self.statusbarManager.AddStatusbarItem(sb.SbMask(self, statusbar = statusbar, position = 2))
  108. self.statusbarManager.AddStatusbarItem(sb.SbRender(self, statusbar = statusbar, position = 3))
  109. self.statusbarManager.Update()
  110. self.trainingMapManager = MapManager(self, mapWindow = self.GetFirstWindow(),
  111. Map = self.GetFirstMap())
  112. self.previewMapManager = MapManager(self, mapWindow = self.GetSecondWindow(),
  113. Map = self.GetSecondMap())
  114. self.InitStatistics()
  115. #self.InitTestStatistics()
  116. # PyPlot init
  117. self.plotPanel = PlotPanel(self, statDict = self.statisticsDict,
  118. statList = self.statisticsList)
  119. self._addPanes()
  120. self._mgr.Update()
  121. self.trainingMapManager.SetToolbar(self.toolbars['iClassTrainingMapManager'])
  122. self.previewMapManager.SetToolbar(self.toolbars['iClassPreviewMapManager'])
  123. # default action
  124. self.OnPan(event = None)
  125. wx.CallAfter(self.AddTrainingAreaMap)
  126. #self.dialogs['category'] = None
  127. self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
  128. def OnCloseWindow(self, event):
  129. self.Destroy()
  130. def __del__(self):
  131. """! Frees C structs and removes vector map and all raster maps."""
  132. I_free_signatures(self.signatures)
  133. I_free_group_ref(self.refer)
  134. for st in self.cStatisticsDict.values():
  135. I_iclass_free_statistics(st)
  136. self.RemoveTempVector()
  137. for i in self.statisticsList:
  138. self.RemoveTempRaster(self.statisticsDict[i].rasterName)
  139. def OnHelp(self, event):
  140. """!Show help page"""
  141. grass.run_command('g.manual',
  142. entry = 'wxGUI.IClass')
  143. def CreateTempVector(self):
  144. """!Create temporary vector map for training areas"""
  145. vectorPath = grass.tempfile(create = False)
  146. vectorName = 'trAreas' + os.path.basename(vectorPath).replace('.','')
  147. cmd = ('v.edit', {'tool': 'create',
  148. 'map': vectorName})
  149. ret = RunCommand(prog = cmd[0],
  150. parent = self,
  151. overwrite = True,
  152. **cmd[1])
  153. if ret != 0:
  154. return False
  155. return vectorName
  156. def RemoveTempVector(self):
  157. """!Removes temporary vector map with training areas"""
  158. ret = RunCommand(prog = 'g.remove',
  159. parent = self,
  160. vect = self.trainingAreaVector)
  161. if ret != 0:
  162. return False
  163. return True
  164. def RemoveTempRaster(self, raster):
  165. """!Removes temporary raster maps"""
  166. ret = RunCommand(prog = 'g.remove',
  167. parent = self,
  168. rast = raster)
  169. if ret != 0:
  170. return False
  171. return True
  172. def AddToolbar(self, name):
  173. """!Add defined toolbar to the window
  174. Currently known toolbars are:
  175. - 'iClassMap' - basic map toolbar
  176. - 'iClass' - iclass tools
  177. - 'iClassMisc' - miscellaneous (help)
  178. - 'vdigit' - digitizer toolbar (areas)
  179. Toolbars 'iClassPreviewMapManager' are added in _addPanes().
  180. """
  181. if name == "iClassMap":
  182. self.toolbars[name] = IClassMapToolbar(self)
  183. self._mgr.AddPane(self.toolbars[name],
  184. wx.aui.AuiPaneInfo().
  185. Name(name).Caption(_("Map Toolbar")).
  186. ToolbarPane().Top().
  187. LeftDockable(False).RightDockable(False).
  188. BottomDockable(False).TopDockable(True).
  189. CloseButton(False).Layer(2).Row(1).
  190. BestSize((self.toolbars[name].GetBestSize())))
  191. if name == "iClass":
  192. self.toolbars[name] = IClassToolbar(self)
  193. self._mgr.AddPane(self.toolbars[name],
  194. wx.aui.AuiPaneInfo().
  195. Name(name).Caption(_("IClass Toolbar")).
  196. ToolbarPane().Top().
  197. LeftDockable(False).RightDockable(False).
  198. BottomDockable(False).TopDockable(True).
  199. CloseButton(False).Layer(2).Row(2).
  200. BestSize((self.toolbars[name].GetBestSize())))
  201. if name == "iClassMisc":
  202. self.toolbars[name] = IClassMiscToolbar(self)
  203. self._mgr.AddPane(self.toolbars[name],
  204. wx.aui.AuiPaneInfo().
  205. Name(name).Caption(_("IClass Misc Toolbar")).
  206. ToolbarPane().Top().
  207. LeftDockable(False).RightDockable(False).
  208. BottomDockable(False).TopDockable(True).
  209. CloseButton(False).Layer(2).Row(2).
  210. BestSize((self.toolbars[name].GetBestSize())))
  211. if name == "vdigit":
  212. self.toolbars[name] = VDigitToolbar(self, MapWindow = self.GetFirstWindow(),
  213. tools = ['addArea', 'moveVertex', 'addVertex',
  214. 'removeVertex', 'editLine',
  215. 'moveLine', 'deleteLine'])
  216. self._mgr.AddPane(self.toolbars[name],
  217. wx.aui.AuiPaneInfo().
  218. Name(name).Caption(_("Digitization Toolbar")).
  219. ToolbarPane().Top().
  220. LeftDockable(False).RightDockable(False).
  221. BottomDockable(False).TopDockable(True).
  222. CloseButton(False).Layer(2).Row(2).
  223. BestSize((self.toolbars[name].GetBestSize())))
  224. def _addPanes(self):
  225. """!Add mapwindows and toolbars to aui manager"""
  226. name = 'iClassPreviewMapManager'
  227. self.toolbars[name] = IClassMapManagerToolbar(self, self.previewMapManager)
  228. self._mgr.AddPane(self.toolbars[name],
  229. wx.aui.AuiPaneInfo().ToolbarPane().Movable().
  230. Name(name).
  231. CloseButton(False).Center().Layer(0).
  232. BestSize((self.toolbars[name].GetBestSize())))
  233. self._mgr.AddPane(self.GetSecondWindow(), wx.aui.AuiPaneInfo().
  234. Name("preview").Caption(_("Preview Display")).
  235. Dockable(False).Floatable(False).CloseButton(False).
  236. Center().Layer(0))
  237. name = 'iClassTrainingMapManager'
  238. self.toolbars[name] = IClassMapManagerToolbar(self, self.trainingMapManager)
  239. self._mgr.AddPane(self.toolbars[name],
  240. wx.aui.AuiPaneInfo().ToolbarPane().
  241. Name(name).
  242. CloseButton(False).Center().Layer(0).
  243. BestSize((self.toolbars[name].GetBestSize())))
  244. self._mgr.AddPane(self.GetFirstWindow(), wx.aui.AuiPaneInfo().
  245. Name("training").Caption(_("Training Areas Display")).
  246. Dockable(False).Floatable(False).CloseButton(False).
  247. Center().Layer(0))
  248. self._mgr.AddPane(self.plotPanel, wx.aui.AuiPaneInfo().
  249. Name("plots").Caption(_("Plots")).
  250. Dockable(False).Floatable(False).CloseButton(False).
  251. Left().Layer(1).BestSize((400, -1)))
  252. def IsStandalone(self):
  253. """!Check if Map display is standalone"""
  254. return True
  255. def OnUpdateActive(self, event):
  256. """!
  257. @todo move to DoubleMapFrame?
  258. """
  259. if self.GetMapToolbar().GetActiveMap() == 0:
  260. self.MapWindow = self.firstMapWindow
  261. self.Map = self.firstMap
  262. else:
  263. self.MapWindow = self.secondMapWindow
  264. self.Map = self.secondMap
  265. self.UpdateActive(self.MapWindow)
  266. # for wingrass
  267. if os.name == 'nt':
  268. self.MapWindow.SetFocus()
  269. def UpdateActive(self, win):
  270. """!
  271. @todo move to DoubleMapFrame?
  272. """
  273. mapTb = self.GetMapToolbar()
  274. # optionally disable tool zoomback tool
  275. mapTb.Enable('zoomback', enable = (len(self.MapWindow.zoomhistory) > 1))
  276. if mapTb.GetActiveMap() != (win == self.secondMapWindow):
  277. mapTb.SetActiveMap((win == self.secondMapWindow))
  278. self.StatusbarUpdate()
  279. def GetMapToolbar(self):
  280. """!Returns toolbar with zooming tools"""
  281. return self.toolbars['iClassMap']
  282. def OnZoomMenu(self, event):
  283. """!Popup Zoom menu """
  284. zoommenu = wx.Menu()
  285. # Add items to the menu
  286. zoomsource = wx.MenuItem(zoommenu, wx.ID_ANY, _('Adjust Training Area Display to Preview Display'))
  287. zoommenu.AppendItem(zoomsource)
  288. self.Bind(wx.EVT_MENU, self.OnZoomToPreview, zoomsource)
  289. zoomtarget = wx.MenuItem(zoommenu, wx.ID_ANY, _('Adjust Preview display to Training Area Display'))
  290. zoommenu.AppendItem(zoomtarget)
  291. self.Bind(wx.EVT_MENU, self.OnZoomToTraining, zoomtarget)
  292. # Popup the menu. If an item is selected then its handler
  293. # will be called before PopupMenu returns.
  294. self.PopupMenu(zoommenu)
  295. zoommenu.Destroy()
  296. def OnZoomToTraining(self, event):
  297. """!Set preview display to match extents of training display """
  298. if not self.MapWindow == self.GetSecondWindow():
  299. self.MapWindow = self.GetSecondWindow()
  300. self.Map = self.GetSecondMap()
  301. self.UpdateActive(self.GetSecondWindow())
  302. newreg = self.firstMap.GetCurrentRegion()
  303. self.GetSecondMap().region = copy.copy(newreg)
  304. self.Render(self.GetSecondWindow())
  305. def OnZoomToPreview(self, event):
  306. """!Set preview display to match extents of training display """
  307. if not self.MapWindow == self.GetFirstWindow():
  308. self.MapWindow = self.GetFirstWindow()
  309. self.Map = self.GetFirstMap()
  310. self.UpdateActive(self.GetFirstWindow())
  311. newreg = self.GetSecondMap().GetCurrentRegion()
  312. self.GetFirstMap().region = copy.copy(newreg)
  313. self.Render(self.GetFirstWindow())
  314. def OnAddBands(self, event):
  315. """!Add imagery group"""
  316. dlg = IClassGroupDialog(self, group = self.group)
  317. if dlg.ShowModal() == wx.ID_OK:
  318. group = grass.find_file(name = dlg.GetGroup(), element = 'group')
  319. if group['fullname']:
  320. self.group = group['fullname']
  321. dlg.Destroy()
  322. def OnCategoryManager(self, event):
  323. """!Show category management dialog"""
  324. dlg = IClassCategoryManagerDialog(self)
  325. dlg.Show()
  326. def CategoryChanged(self, currentCat):
  327. """!Updates everything which depends on current category.
  328. Updates number of stddev, histograms, layer in preview display.
  329. """
  330. nstd = self.statisticsDict[currentCat].nstd
  331. self.toolbars['iClass'].UpdateStddev(nstd)
  332. self.plotPanel.UpdateCategory(currentCat)
  333. self.plotPanel.OnPlotTypeSelected(None)
  334. name = self.statisticsDict[currentCat].rasterName
  335. name = self.previewMapManager.GetAlias(name)
  336. if name:
  337. self.previewMapManager.SelectLayer(name)
  338. def UpdateRasterName(self, newName, cat):
  339. """!Update alias of raster map when category name is changed"""
  340. origName = self.statisticsDict[cat].rasterName
  341. self.previewMapManager.SetAlias(origName, newName)
  342. def StddevChanged(self, cat, nstd):
  343. """!Standard deviation multiplier changed, rerender map, histograms"""
  344. stat = self.statisticsDict[cat]
  345. stat.nstd = nstd
  346. raster = stat.rasterName
  347. cstat = self.cStatisticsDict[cat]
  348. I_iclass_statistics_set_nstd(cstat, nstd)
  349. I_iclass_create_raster(cstat, self.refer, raster)
  350. self.Render(self.GetSecondWindow())
  351. stat.SetBandStatistics(cstat)
  352. self.plotPanel.StddevChanged()
  353. def AddRasterMap(self, name, firstMap = True, secondMap = True):
  354. """!Add raster map to Map"""
  355. cmdlist = ['d.rast', 'map=%s' % name]
  356. if firstMap:
  357. self.GetFirstMap().AddLayer(type='raster', command=cmdlist, l_active=True,
  358. name=name, l_hidden=False, l_opacity=1.0, l_render=False)
  359. self.Render(self.GetFirstWindow())
  360. if secondMap:
  361. self.GetSecondMap().AddLayer(type='raster', command=cmdlist, l_active=True,
  362. name=name, l_hidden=False, l_opacity=1.0, l_render=False)
  363. self.Render(self.GetSecondWindow())
  364. def AddTrainingAreaMap(self):
  365. """!Add vector map with training areas to Map (training
  366. sub-display)"""
  367. vname = self.CreateTempVector()
  368. if vname:
  369. self.trainingAreaVector = vname
  370. else:
  371. GMessage(parent = self, message = _("Failed to create temporary vector map."))
  372. return
  373. mapLayer = self.GetFirstMap().AddLayer(type = 'vector',
  374. command = ['d.vect', 'map=%s' % vname],
  375. name = vname, l_active = False)
  376. self.toolbars['vdigit'].StartEditing(mapLayer)
  377. self.Render(self.GetFirstWindow())
  378. def OnRunAnalysis(self, event):
  379. """!Run analysis and update plots"""
  380. if self.RunAnalysis():
  381. currentCat = self.GetCurrentCategoryIdx()
  382. self.plotPanel.UpdatePlots(group = self.group, currentCat = currentCat,
  383. statDict = self.statisticsDict,
  384. statList = self.statisticsList)
  385. def RunAnalysis(self):
  386. """!Run analysis
  387. Calls C functions to compute all statistics and creates raster maps.
  388. Signatures are created but signature file is not.
  389. """
  390. #self.firstMapWindow.digit.CloseMap()
  391. self.poMapInfo = self.firstMapWindow.digit.GetDisplay().poMapInfo
  392. if not self.CheckInput(group = self.group, vector = self.trainingAreaVector):
  393. return
  394. for statistic in self.cStatisticsDict.values():
  395. I_iclass_free_statistics(statistic)
  396. self.cStatisticsDict = {}
  397. # init Ref struct with the files in group */
  398. I_free_group_ref(self.refer)
  399. if (not I_iclass_init_group(self.group, self.refer)):
  400. return False
  401. I_free_signatures(self.signatures)
  402. I_iclass_init_signatures(self.signatures, self.refer)
  403. cats = self.statisticsList[:]
  404. for i in cats:
  405. stats = self.statisticsDict[i]
  406. statistics_obj = IClass_statistics()
  407. statistics = pointer(statistics_obj)
  408. I_iclass_init_statistics(statistics,
  409. stats.category,
  410. stats.name,
  411. stats.color,
  412. stats.nstd)
  413. if I_iclass_analysis(statistics, self.refer, self.poMapInfo, "1",
  414. self.group, stats.rasterName):
  415. # tests
  416. self.cStatisticsDict[i] = statistics
  417. stats.SetStatistics(statistics)
  418. stats.SetReady()
  419. self.statisticsDict[stats.category] = stats
  420. #self.ConvertToNull(name = stats.rasterName)
  421. self.previewMapManager.AddLayer(name = stats.rasterName, resultsLayer = True)
  422. # write statistics
  423. I_iclass_add_signature(self.signatures, statistics)
  424. else:
  425. I_iclass_free_statistics(statistics)
  426. return True
  427. def OnSaveSigFile(self, event):
  428. """!Asks for signature file name and saves it."""
  429. if not self.group:
  430. GMessage(parent = self, message = _("No imagery group selected."))
  431. return
  432. dlg = wx.TextEntryDialog(self, message = _("Enter name of signature file:"),
  433. caption = _("Save signature file"))
  434. if self.sigFile:
  435. dlg.SetValue(self.sigFile)
  436. if dlg.ShowModal() == wx.ID_OK:
  437. file = dlg.GetValue()
  438. self.WriteSignatures(self.signatures, self.group, file)
  439. dlg.Destroy()
  440. def InitStatistics(self):
  441. """!Initialize variables and c structures neccessary for
  442. computing statistics.
  443. """
  444. self.group = None
  445. self.sigFile = None
  446. self.statisticsDict = {}
  447. self.statisticsList = []
  448. self.cStatisticsDict = {}
  449. self.signatures_obj = Signature()
  450. self.signatures = pointer(self.signatures_obj)
  451. I_init_signatures(self.signatures, 0) # must be freed on exit
  452. refer_obj = Ref()
  453. self.refer = pointer(refer_obj)
  454. I_init_group_ref(self.refer) # must be freed on exit
  455. def WriteSignatures(self, signatures, group, filename):
  456. """!Writes current signatures to signature file
  457. @param signatures signature (c structure)
  458. @param group imagery group
  459. @param filename signature file name
  460. """
  461. I_iclass_write_signatures(signatures, group, group, filename)
  462. def CheckInput(self, group, vector):
  463. """!Check if input is valid"""
  464. # check if group is ok
  465. if not group:
  466. GMessage(parent = self,
  467. message = _("No imagery group selected. "
  468. "Operation cancelled."))
  469. return False
  470. groupLayers = self.GetGroupLayers(group)
  471. nLayers = len(groupLayers)
  472. if nLayers <= 1:
  473. GMessage(parent = self,
  474. message = _("Group <%s> does not have enough files "
  475. "(it has %d files). Operation cancelled.") % (group, nLayers))
  476. return False
  477. #check if vector has any areas
  478. vectorInfo = grass.vector_info(vector)
  479. numAreas = Vect_get_num_areas(self.poMapInfo)
  480. if numAreas <= 0:
  481. GMessage(parent = self,
  482. message = _("No areas given. "
  483. "Operation cancelled."))
  484. return False
  485. # check if vector is inside raster
  486. rasterInfo = grass.raster_info(groupLayers[0])
  487. if vectorInfo['north'] > rasterInfo['north'] or \
  488. vectorInfo['south'] < rasterInfo['south'] or \
  489. vectorInfo['east'] > rasterInfo['east'] or \
  490. vectorInfo['west'] < rasterInfo['west']:
  491. GMessage(parent = self,
  492. message = _("Vector features are outside raster layers. "
  493. "Operation cancelled."))
  494. return False
  495. return True
  496. def GetGroupLayers(self, group):
  497. """! Get layers in group
  498. @todo consider moving this function to core module for convenient
  499. """
  500. res = RunCommand('i.group',
  501. flags = 'g',
  502. group = group,
  503. read = True).strip()
  504. if res.split('\n')[0]:
  505. return res.split('\n')
  506. return []
  507. def ConvertToNull(self, name):
  508. """! Sets value which represents null values for given raster map.
  509. @param name raster map name
  510. """
  511. RunCommand('r.null',
  512. map = name,
  513. setnull = 0)
  514. def GetCurrentCategoryIdx(self):
  515. """!Returns current category number"""
  516. return self.toolbars['iClass'].GetSelectedCategoryIdx()
  517. def OnZoomIn(self, event):
  518. """!Enable zooming for plots"""
  519. super(IClassMapFrame, self).OnZoomIn(event)
  520. self.plotPanel.EnableZoom(type = 1)
  521. def OnZoomOut(self, event):
  522. """!Enable zooming for plots"""
  523. super(IClassMapFrame, self).OnZoomOut(event)
  524. self.plotPanel.EnableZoom(type = -1)
  525. def OnPan(self, event):
  526. """!Enable paanning for plots"""
  527. super(IClassMapFrame, self).OnPan(event)
  528. self.plotPanel.EnablePan()
  529. class MapManager:
  530. """! Class for managing map renderer.
  531. It is connected with iClassMapManagerToolbar.
  532. """
  533. def __init__(self, frame, mapWindow, Map):
  534. """!
  535. It is expected that \a mapWindow is conected with \a Map.
  536. @param frame application main window
  537. @param mapWindow map window instance
  538. @param Map map renderer instance
  539. """
  540. self.map = Map
  541. self.frame = frame
  542. self.mapWindow = mapWindow
  543. self.toolbar = None
  544. self.layerName = {}
  545. def SetToolbar(self, toolbar):
  546. self.toolbar = toolbar
  547. def AddLayer(self, name, resultsLayer = False):
  548. """!Adds layer to Map and update toolbar
  549. @param name layer (raster) name
  550. @param resultsLayer True if layer is temp. raster showing the results of computation
  551. """
  552. if (resultsLayer and
  553. name in [l.GetName() for l in self.map.GetListOfLayers(l_name = name)]):
  554. self.frame.Render(self.mapWindow)
  555. return
  556. cmdlist = ['d.rast', 'map=%s' % name]
  557. self.map.AddLayer(type = 'raster', command = cmdlist, l_active = True,
  558. name = name, l_hidden = False, l_opacity = 1.0, l_render = True)
  559. self.frame.Render(self.mapWindow)
  560. if resultsLayer:
  561. alias = self._addSuffix(name.rsplit("_", 1)[0])
  562. self.layerName[alias] = name
  563. name = alias
  564. else:
  565. self.layerName[name] = name
  566. self.toolbar.choice.Insert(name, 0)
  567. self.toolbar.choice.SetSelection(0)
  568. def RemoveLayer(self, name, idx):
  569. """!Removes layer from Map and update toolbar"""
  570. self.map.GetListOfLayers(l_type = 'raster')
  571. name = self.layerName[name]
  572. self.map.RemoveLayer(name = name)
  573. del self.layerName[name]
  574. self.toolbar.choice.Delete(idx)
  575. if not self.toolbar.choice.IsEmpty():
  576. self.toolbar.choice.SetSelection(0)
  577. self.frame.Render(self.mapWindow)
  578. def SelectLayer(self, name):
  579. """!Moves selected layer to top"""
  580. layers = self.map.GetListOfLayers(l_type = 'raster')
  581. idx = None
  582. for i, layer in enumerate(layers):
  583. if self.layerName[name] == layer.GetName():
  584. idx = i
  585. break
  586. if idx is not None: # should not happen
  587. layers.append(layers.pop(idx))
  588. choice = self.toolbar.choice
  589. idx = choice.FindString(name)
  590. choice.Delete(idx)
  591. choice.Insert(name, 0)
  592. choice.SetSelection(0)
  593. #layers.reverse()
  594. self.map.ReorderLayers(layers)
  595. self.frame.Render(self.mapWindow)
  596. def SetOpacity(self, name):
  597. """!Sets opacity of layers."""
  598. name = self.layerName[name]
  599. layers = self.map.GetListOfLayers(l_name = name)
  600. if not layers:
  601. return
  602. # works for first layer only
  603. oldOpacity = layers[0].GetOpacity()
  604. dlg = SetOpacityDialog(self.frame, opacity = oldOpacity)
  605. if dlg.ShowModal() == wx.ID_OK:
  606. self.map.ChangeOpacity(layer = layers[0], l_opacity = dlg.GetOpacity())
  607. dlg.Destroy()
  608. self.frame.Render(self.mapWindow)
  609. def _addSuffix(self, name):
  610. suffix = _('results')
  611. return '_'.join((name, suffix))
  612. def GetAlias(self, name):
  613. """!Returns alias for layer"""
  614. name = [k for k, v in self.layerName.iteritems() if v == name]
  615. if name:
  616. return name[0]
  617. return None
  618. def SetAlias(self, original, alias):
  619. name = self.GetAlias(original)
  620. if name:
  621. self.layerName[self._addSuffix(alias)] = original
  622. del self.layerName[name]
  623. idx = self.toolbar.choice.FindString(name)
  624. if idx != wx.NOT_FOUND:
  625. self.toolbar.choice.SetString(idx, self._addSuffix(alias))
  626. def test():
  627. import gettext
  628. import core.render as render
  629. gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
  630. app = wx.PySimpleApp()
  631. wx.InitAllImageHandlers()
  632. frame = IClassMapFrame()
  633. frame.Show()
  634. app.MainLoop()
  635. if __name__ == "__main__":
  636. test()