sampling_frame.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. # -*- coding: utf-8 -*-
  2. """!
  3. @package rlisetup.sampling_frame
  4. @brief r.li.setup - draw sample frame
  5. Classes:
  6. - sampling_frame::RLiSetupMapPanel
  7. - sampling_frame::RLiSetupToolbar
  8. - sampling_frame::GraphicsSetItem
  9. (C) 2013 by the GRASS Development Team
  10. This program is free software under the GNU General Public License
  11. (>=v2). Read the file COPYING that comes with GRASS for details.
  12. @author Anna Petrasova <kratochanna gmail.com>
  13. """
  14. import os
  15. import sys
  16. import wx
  17. import wx.aui
  18. #start new import
  19. import tempfile
  20. from core.gcmd import RunCommand
  21. import grass.script.core as grass
  22. from core import gcmd
  23. try:
  24. from grass.lib.gis import *
  25. from grass.lib.vector import *
  26. from grass.lib.raster import *
  27. except ImportError:
  28. pass
  29. #end new import
  30. # adding a path to wxGUI modules
  31. if __name__ == '__main__':
  32. WXGUIBASE = os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython')
  33. if WXGUIBASE not in sys.path:
  34. sys.path.append(WXGUIBASE)
  35. from core.utils import _
  36. from core.giface import StandaloneGrassInterface
  37. from mapwin.base import MapWindowProperties
  38. from mapwin.buffered import BufferedMapWindow
  39. from core.render import Map
  40. from gui_core.toolbars import BaseToolbar, BaseIcons, ToolSwitcher
  41. from icons.icon import MetaIcon
  42. from grass.pydispatch.signal import Signal
  43. from grass.pydispatch.errors import DispatcherKeyError
  44. from functions import SamplingType
  45. class Circle:
  46. def __init__(self, pt, r):
  47. self.point = pt
  48. self.radius = r
  49. class MaskedArea(object):
  50. def __init__(self, region, raster):
  51. self.region = region
  52. self.raster = raster
  53. class RLiSetupMapPanel(wx.Panel):
  54. """!Panel with mapwindow used in r.li.setup"""
  55. def __init__(self, parent, samplingType, graphicsType="rect", icon=None,
  56. map_=None):
  57. wx.Panel.__init__(self, parent=parent)
  58. self.mapWindowProperties = MapWindowProperties()
  59. self.mapWindowProperties.setValuesFromUserSettings()
  60. giface = StandaloneGrassInterface()
  61. self.samplingtype = samplingType
  62. self.gtype = graphicsType
  63. self.parent = parent
  64. ##print self.gtype
  65. ##print samplingType
  66. if map_:
  67. self.map_ = map_
  68. else:
  69. self.map_ = Map()
  70. self.map_.region = self.map_.GetRegion()
  71. self._mgr = wx.aui.AuiManager(self)
  72. self.mapWindow = BufferedMapWindow(parent=self, giface=giface,
  73. Map=self.map_,
  74. properties=self.mapWindowProperties)
  75. self._mgr.AddPane(self.mapWindow, wx.aui.AuiPaneInfo().CentrePane().
  76. Dockable(True).BestSize((-1, -1)).Name('mapwindow').
  77. CloseButton(False).DestroyOnClose(True).
  78. Layer(0))
  79. self._toolSwitcher = ToolSwitcher()
  80. self._toolSwitcher.toggleToolChanged.connect(self._onToolChanged)
  81. self.toolbar = RLiSetupToolbar(self, self._toolSwitcher)
  82. self.catId = 1
  83. self._mgr.AddPane(self.toolbar,
  84. wx.aui.AuiPaneInfo().
  85. Name("maptoolbar").Caption(_("Map Toolbar")).
  86. ToolbarPane().Left().Name('mapToolbar').
  87. CloseButton(False).Layer(1).Gripper(False).
  88. BestSize((self.toolbar.GetBestSize())))
  89. self._mgr.Update()
  90. #print self.samplingtype
  91. if self.samplingtype == SamplingType.REGIONS:
  92. self.afterRegionDrawn = Signal('RLiSetupMapPanel.afterRegionDrawn')
  93. self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='line')
  94. elif self.samplingtype in [SamplingType.MUNITSR, SamplingType.KUNITSR,
  95. SamplingType.KMVWINR, SamplingType.MMVWINR]:
  96. self.sampleFrameChanged = Signal('RLiSetupMapPanel.sampleFrameChanged')
  97. self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='rectangle')
  98. elif self.samplingtype in [SamplingType.MUNITSC, SamplingType.KUNITSC,
  99. SamplingType.KMVWINC, SamplingType.MMVWINC]:
  100. self.afterCircleDrawn = Signal('RLiSetupMapPanel.afterCircleDrawn')
  101. self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='line')
  102. else:
  103. self.sampleFrameChanged = Signal('RLiSetupMapPanel.sampleFrameChanged')
  104. self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='rectangle')
  105. self._registeredGraphics.AddPen('rlisetup', wx.Pen(wx.GREEN, width=2,
  106. style=wx.SOLID))
  107. self._registeredGraphics.AddItem(coords=[[0, 0], [0, 0]],
  108. penName='rlisetup', hide=True)
  109. if self.samplingtype != SamplingType.VECT:
  110. self.toolbar.SelectDefault()
  111. def GetMap(self):
  112. return self.map_
  113. def OnPan(self, event):
  114. """!Panning, set mouse to drag."""
  115. self.mapWindow.SetModePan()
  116. def OnZoomIn(self, event):
  117. """!Zoom in the map."""
  118. self.mapWindow.SetModeZoomIn()
  119. def OnZoomOut(self, event):
  120. """!Zoom out the map."""
  121. self.mapWindow.SetModeZoomOut()
  122. def OnZoomToMap(self, event):
  123. layers = self.map_.GetListOfLayers()
  124. self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
  125. def OnDrawRadius(self, event):
  126. """!Start draw mode"""
  127. self.mapWindow.mouse['use'] = "None"
  128. self.mapWindow.mouse['box'] = "line"
  129. self.mapWindow.pen = wx.Pen(colour=wx.RED, width=1,
  130. style=wx.SHORT_DASH)
  131. self.mapWindow.SetNamedCursor('cross')
  132. self.mapWindow.mouseLeftUp.connect(self._radiusDrawn)
  133. def OnDigitizeRegion(self, event):
  134. """!Start draw mode"""
  135. self.mapWindow.mouse['use'] = "None"
  136. self.mapWindow.mouse['box'] = "line"
  137. self.mapWindow.pen = wx.Pen(colour=wx.RED, width=1,
  138. style=wx.SHORT_DASH)
  139. self.mapWindow.SetNamedCursor('cross')
  140. self.mapWindow.mouseLeftUp.connect(self._lineSegmentDrawn)
  141. self.mapWindow.mouseDClick.connect(self._mouseDbClick)
  142. self._registeredGraphics.GetItem(0).SetCoords([])
  143. def OnDraw(self, event):
  144. """!Start draw mode"""
  145. self.mapWindow.mouse['use'] = "None"
  146. self.mapWindow.mouse['box'] = "box"
  147. self.mapWindow.pen = wx.Pen(colour=wx.RED, width=2,
  148. style=wx.SHORT_DASH)
  149. self.mapWindow.SetNamedCursor('cross')
  150. self.mapWindow.mouseLeftUp.connect(self._rectangleDrawn)
  151. def _lineSegmentDrawn(self, x, y):
  152. item = self._registeredGraphics.GetItem(0)
  153. coords = item.GetCoords()
  154. if len(coords) == 0:
  155. coords.extend([self.mapWindow.Pixel2Cell(self.mapWindow.mouse['begin'])])
  156. coords.extend([[x, y]])
  157. item.SetCoords(coords)
  158. item.SetPropertyVal('hide', False)
  159. self.mapWindow.ClearLines()
  160. self._registeredGraphics.Draw(self.mapWindow.pdcTmp)
  161. def _mouseDbClick(self, x, y):
  162. item = self._registeredGraphics.GetItem(0)
  163. coords = item.GetCoords()
  164. coords.extend([[x, y]])
  165. item.SetCoords(coords)
  166. item.SetPropertyVal('hide', False)
  167. self.mapWindow.ClearLines()
  168. self._registeredGraphics.Draw(self.mapWindow.pdc)
  169. self.createRegion()
  170. def createRegion(self):
  171. dlg = wx.TextEntryDialog(None, 'Name of sample region',
  172. 'Create region', 'region' + str(self.catId))
  173. ret = dlg.ShowModal()
  174. if ret == wx.ID_OK:
  175. raster = dlg.GetValue()
  176. marea = self.writeArea(self._registeredGraphics.GetItem(0).GetCoords(), raster)
  177. self.nextRegion(next=True, area=marea)
  178. else:
  179. self.nextRegion(next=False)
  180. dlg.Destroy()
  181. def nextRegion(self, next=True, area=None):
  182. self.mapWindow.ClearLines()
  183. item = self._registeredGraphics.GetItem(0)
  184. item.SetCoords([])
  185. item.SetPropertyVal('hide', True)
  186. layers = self.map_.GetListOfLayers()
  187. self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
  188. if next is True:
  189. self.afterRegionDrawn.emit(marea=area)
  190. else:
  191. gcmd.GMessage(parent=self.parent,
  192. message=_("Raster map not created. Please redraw region."))
  193. def writeArea(self, coords, rasterName):
  194. polyfile = tempfile.NamedTemporaryFile(delete=False)
  195. polyfile.write("AREA\n")
  196. for coor in coords:
  197. east, north = coor
  198. point = " %s %s\n" % (east, north)
  199. polyfile.write(point)
  200. catbuf = "=%d a\n" % self.catId
  201. polyfile.write(catbuf)
  202. self.catId = self.catId + 1
  203. polyfile.close()
  204. region_settings = grass.parse_command('g.region', flags='p',
  205. delimiter=':')
  206. pname = polyfile.name.split('/')[-1]
  207. tmpraster = "rast_" + pname
  208. tmpvector = "vect_" + pname
  209. wx.BeginBusyCursor()
  210. wx.Yield()
  211. RunCommand('r.in.poly', input=polyfile.name, output=tmpraster,
  212. rows=region_settings['rows'], overwrite=True)
  213. RunCommand('r.to.vect', input=tmpraster, output=tmpvector,
  214. type='area', overwrite=True)
  215. RunCommand('v.to.rast', input=tmpvector, output=rasterName,
  216. value=1, use='val', overwrite=True)
  217. wx.EndBusyCursor()
  218. grass.use_temp_region()
  219. grass.run_command('g.region', vect=tmpvector)
  220. region = grass.region()
  221. marea = MaskedArea(region, rasterName)
  222. RunCommand('g.remove', rast=tmpraster)
  223. RunCommand('g.remove', vect=tmpvector)
  224. os.unlink(polyfile.name)
  225. return marea
  226. def _onToolChanged(self):
  227. """!Helper function to disconnect drawing"""
  228. try:
  229. self.mapWindow.mouseLeftUp.disconnect(self._rectangleDrawn)
  230. self.mapWindow.mouseLeftUp.disconnect(self._radiusDrawn)
  231. self.mapWindow.mouseMoving.disconnect(self._mouseMoving)
  232. self.mapWindow.mouseLeftDown.disconnect(self._mouseLeftDown)
  233. self.mapWindow.mouseDClick.disconnect(self._mouseDbClick)
  234. except DispatcherKeyError:
  235. pass
  236. def _radiusDrawn(self, x, y):
  237. """!When drawing finished, get region values"""
  238. mouse = self.mapWindow.mouse
  239. item = self._registeredGraphics.GetItem(0)
  240. p1 = mouse['begin']
  241. p2 = mouse['end']
  242. dist, (north, east) = self.mapWindow.Distance(p1, p2, False)
  243. circle = Circle(p1, dist)
  244. self.mapWindow.ClearLines()
  245. self.mapWindow.pdcTmp.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
  246. pen = wx.Pen(colour=wx.RED, width=2)
  247. self.mapWindow.pdcTmp.SetPen(pen)
  248. self.mapWindow.pdcTmp.DrawCircle(circle.point[0], circle.point[1],
  249. circle.radius)
  250. self._registeredGraphics.Draw(self.mapWindow.pdcTmp)
  251. self.createCricle(circle)
  252. def createCricle(self, c):
  253. dlg = wx.TextEntryDialog(None, 'Name of sample region',
  254. 'Create region', 'region' + str(self.catId))
  255. ret = dlg.ShowModal()
  256. if ret == wx.ID_OK:
  257. raster = dlg.GetValue()
  258. circle = self.writeCircle(c, raster)
  259. self.nextCircle(next=True, circle=c)
  260. else:
  261. self.nextCircle(next=False)
  262. dlg.Destroy()
  263. def nextCircle(self, next=True, circle=None):
  264. self.mapWindow.ClearLines()
  265. item = self._registeredGraphics.GetItem(0)
  266. item.SetPropertyVal('hide', True)
  267. layers = self.map_.GetListOfLayers()
  268. self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
  269. if next is True:
  270. self.afterCircleDrawn.emit(mcircle=circle)
  271. else:
  272. gcmd.GMessage(parent=self.parent,
  273. message=_("Raster map not created. redraw region again."))
  274. def writeCircle(self, circle, rasterName):
  275. polyfile = tempfile.NamedTemporaryFile(delete=False)
  276. polyfile.write("AREA\n")
  277. for coor in coords:
  278. east, north = coor
  279. point = " %s %s\n" % (east, north)
  280. polyfile.write(point)
  281. catbuf = "=%d a\n" % self.catId
  282. polyfile.write(catbuf)
  283. self.catId = self.catId + 1
  284. polyfile.close()
  285. region_settings = grass.parse_command('g.region', flags='p',
  286. delimiter=':')
  287. pname = polyfile.name.split('/')[-1]
  288. tmpraster = "rast_" + pname
  289. tmpvector = "vect_" + pname
  290. RunCommand('r.in.poly', input=polyfile.name, output=tmpraster,
  291. rows=region_settings['rows'], overwrite=True)
  292. RunCommand('r.to.vect', input=tmpraster, output=tmpvector,
  293. type='area', overwrite=True)
  294. RunCommand('v.to.rast', input=tmpvector, output=rasterName,
  295. value=1, use='val', overwrite=True)
  296. grass.use_temp_region()
  297. grass.run_command('g.region', vect=tmpvector)
  298. region = grass.region()
  299. marea = MaskedArea(region, rasterName)
  300. RunCommand('g.remove', rast=tmpraster)
  301. RunCommand('g.remove', vect=tmpvector)
  302. os.unlink(polyfile.name)
  303. return marea
  304. def _rectangleDrawn(self):
  305. """!When drawing finished, get region values"""
  306. mouse = self.mapWindow.mouse
  307. item = self._registeredGraphics.GetItem(0)
  308. p1 = self.mapWindow.Pixel2Cell(mouse['begin'])
  309. p2 = self.mapWindow.Pixel2Cell(mouse['end'])
  310. item.SetCoords([p1, p2])
  311. region = {'n': max(p1[1], p2[1]),
  312. 's': min(p1[1], p2[1]),
  313. 'w': min(p1[0], p2[0]),
  314. 'e': max(p1[0], p2[0])}
  315. item.SetPropertyVal('hide', False)
  316. self.mapWindow.ClearLines()
  317. self._registeredGraphics.Draw(self.mapWindow.pdcTmp)
  318. if self.samplingtype == SamplingType.MUNITSR:
  319. dlg = wx.MessageDialog(self, "Is this area ok?",
  320. "select sampling unit",
  321. wx.YES_NO | wx.ICON_QUESTION)
  322. ret = dlg.ShowModal()
  323. if ret == wx.ID_YES:
  324. grass.use_temp_region()
  325. grass.run_command('g.region', n=region['n'], s=region['s'],
  326. e=region['e'], w=region['w'])
  327. tregion = grass.region()
  328. self.sampleFrameChanged.emit(region=tregion)
  329. self.mapWindow.ClearLines()
  330. item = self._registeredGraphics.GetItem(0)
  331. item.SetPropertyVal('hide', True)
  332. layers = self.map_.GetListOfLayers()
  333. self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False,
  334. render=True)
  335. else:
  336. self.nextRegion(next=False)
  337. dlg.Destroy()
  338. elif self.samplingtype != SamplingType.WHOLE:
  339. """!When drawing finished, get region values"""
  340. self.sampleFrameChanged.emit(region=region)
  341. icons = {'draw': MetaIcon(img='edit',
  342. label=_('Draw sampling frame'),
  343. desc=_('Draw sampling frame by clicking and dragging')),
  344. 'digitizeunit': MetaIcon(img='edit',
  345. label=_('Draw sampling rectangle'),
  346. desc=_('Draw sampling rectangle by clicking and dragging')),
  347. 'digitizeunitc': MetaIcon(img='line-create',
  348. label=_('Draw sampling circle'),
  349. desc=_('Draw sampling circle radius by clicking and dragging')),
  350. 'digitizeregion': MetaIcon(img='polygon-create',
  351. label=_('Draw sampling region'),
  352. desc=_('Draw sampling region by polygon. Right Double click to end drawing'))}
  353. class RLiSetupToolbar(BaseToolbar):
  354. """!IClass toolbar
  355. """
  356. def __init__(self, parent, toolSwitcher):
  357. """!RLiSetup toolbar constructor
  358. """
  359. BaseToolbar.__init__(self, parent, toolSwitcher,
  360. style=wx.NO_BORDER | wx.TB_VERTICAL)
  361. self.InitToolbar(self._toolbarData())
  362. """
  363. if self.parent.samplingtype == SamplingType.REGIONS:
  364. self._default = self.digitizeregion
  365. self.toolSwitcher.AddToolToGroup(group='mouseUse', toolbar=self, tool=self.digitizeregion)
  366. elif self.parent.samplingtype == SamplingType.MUNITSR:
  367. self._default = self.digitizeunit
  368. self.toolSwitcher.AddToolToGroup(group='mouseUse', toolbar=self, tool=self.digitizeunit)
  369. else:
  370. self._default = self.draw
  371. self.toolSwitcher.AddToolToGroup(group='mouseUse', toolbar=self, tool=self.draw)
  372. """
  373. if self.parent.samplingtype == SamplingType.REGIONS:
  374. self._default = self.digitizeregion
  375. elif self.parent.samplingtype == SamplingType.MUNITSR:
  376. self._default = self.digitizeunit
  377. elif self.parent.samplingtype == SamplingType.MUNITSC:
  378. self._default = self.digitizeunitc
  379. elif self.parent.samplingtype == SamplingType.VECT:
  380. self._default = None
  381. else:
  382. self._default = self.draw
  383. for tool in (self._default, self.pan, self.zoomIn, self.zoomOut):
  384. if tool:
  385. self.toolSwitcher.AddToolToGroup(group='mouseUse',
  386. toolbar=self, tool=tool)
  387. # realize the toolbar
  388. self.Realize()
  389. def _toolbarData(self):
  390. """!Toolbar data"""
  391. if self.parent.samplingtype == SamplingType.REGIONS:
  392. drawTool = ('digitizeregion', icons['digitizeregion'],
  393. self.parent.OnDigitizeRegion,
  394. wx.ITEM_CHECK)
  395. elif self.parent.samplingtype == SamplingType.MUNITSR:
  396. drawTool = ('digitizeunit', icons['digitizeunit'],
  397. self.parent.OnDraw,
  398. wx.ITEM_CHECK)
  399. elif self.parent.samplingtype == SamplingType.MUNITSC:
  400. drawTool = ('digitizeunitc', icons['digitizeunitc'],
  401. self.parent.OnDrawRadius,
  402. wx.ITEM_CHECK)
  403. else:
  404. drawTool = ('draw', icons['draw'],
  405. self.parent.OnDraw,
  406. wx.ITEM_CHECK)
  407. if self.parent.samplingtype == SamplingType.VECT:
  408. return self._getToolbarData((
  409. ('pan', BaseIcons['pan'],
  410. self.parent.OnPan,
  411. wx.ITEM_CHECK),
  412. ('zoomIn', BaseIcons['zoomIn'],
  413. self.parent.OnZoomIn,
  414. wx.ITEM_CHECK),
  415. ('zoomOut', BaseIcons['zoomOut'],
  416. self.parent.OnZoomOut,
  417. wx.ITEM_CHECK),
  418. ('zoomExtent', BaseIcons['zoomExtent'],
  419. self.parent.OnZoomToMap),))
  420. else:
  421. return self._getToolbarData((drawTool, (None, ),
  422. ('pan', BaseIcons['pan'],
  423. self.parent.OnPan,
  424. wx.ITEM_CHECK),
  425. ('zoomIn', BaseIcons['zoomIn'],
  426. self.parent.OnZoomIn,
  427. wx.ITEM_CHECK),
  428. ('zoomOut', BaseIcons['zoomOut'],
  429. self.parent.OnZoomOut,
  430. wx.ITEM_CHECK),
  431. ('zoomExtent', BaseIcons['zoomExtent'],
  432. self.parent.OnZoomToMap),))