123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- """
- @package rlisetup.sampling_frame
- @brief r.li.setup - draw sample frame
- Classes:
- - sampling_frame::RLiSetupMapPanel
- - sampling_frame::RLiSetupToolbar
- - sampling_frame::GraphicsSetItem
- (C) 2013 by the GRASS Development Team
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
- @author Anna Petrasova <kratochanna gmail.com>
- """
- import os
- import wx
- import wx.aui
- # start new import
- import tempfile
- from core.gcmd import RunCommand
- import grass.script.core as grass
- from core import gcmd
- from core.giface import StandaloneGrassInterface
- from mapwin.base import MapWindowProperties
- from mapwin.buffered import BufferedMapWindow
- from core.render import Map
- from gui_core.toolbars import BaseToolbar, BaseIcons, ToolSwitcher
- from icons.icon import MetaIcon
- from core.gcmd import GMessage
- from grass.pydispatch.signal import Signal
- from grass.pydispatch.errors import DispatcherKeyError
- from .functions import SamplingType, checkMapExists
- class Circle:
- def __init__(self, pt, r):
- self.point = pt
- self.radius = r
- class MaskedArea(object):
- def __init__(self, region, raster, radius):
- self.region = region
- self.raster = raster
- self.radius = radius
- class RLiSetupMapPanel(wx.Panel):
- """Panel with mapwindow used in r.li.setup"""
- def __init__(self, parent, samplingType, icon=None, map_=None):
- wx.Panel.__init__(self, parent=parent)
- self.mapWindowProperties = MapWindowProperties()
- self.mapWindowProperties.setValuesFromUserSettings()
- giface = StandaloneGrassInterface()
- self.samplingtype = samplingType
- self.parent = parent
- if map_:
- self.map_ = map_
- else:
- self.map_ = Map()
- self.map_.region = self.map_.GetRegion()
- self._mgr = wx.aui.AuiManager(self)
- self.mapWindow = BufferedMapWindow(parent=self, giface=giface,
- Map=self.map_,
- properties=self.mapWindowProperties)
- self._mgr.AddPane(self.mapWindow, wx.aui.AuiPaneInfo().CentrePane().
- Dockable(True).BestSize((-1, -1)).Name('mapwindow').
- CloseButton(False).DestroyOnClose(True).
- Layer(0))
- self._toolSwitcher = ToolSwitcher()
- self._toolSwitcher.toggleToolChanged.connect(self._onToolChanged)
- self.toolbar = RLiSetupToolbar(self, self._toolSwitcher)
- self.catId = 1
- self._mgr.AddPane(self.toolbar,
- wx.aui.AuiPaneInfo().
- Name("maptoolbar").Caption(_("Map Toolbar")).
- ToolbarPane().Left().Name('mapToolbar').
- CloseButton(False).Layer(1).Gripper(False).
- BestSize((self.toolbar.GetBestSize())))
- self._mgr.Update()
- if self.samplingtype == SamplingType.REGIONS:
- self.afterRegionDrawn = Signal('RLiSetupMapPanel.afterRegionDrawn')
- self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
- graphicsType='line')
- elif self.samplingtype in [SamplingType.MUNITSR, SamplingType.MMVWINR]:
- self.sampleFrameChanged = Signal(
- 'RLiSetupMapPanel.sampleFrameChanged')
- self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
- graphicsType='rectangle')
- elif self.samplingtype in [SamplingType.MUNITSC, SamplingType.MMVWINC]:
- self.afterCircleDrawn = Signal('RLiSetupMapPanel.afterCircleDrawn')
- self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
- graphicsType='line')
- else:
- self.sampleFrameChanged = Signal(
- 'RLiSetupMapPanel.sampleFrameChanged')
- self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
- graphicsType='rectangle')
- self._registeredGraphics.AddPen('rlisetup', wx.Pen(wx.GREEN, width=2,
- style=wx.SOLID))
- self._registeredGraphics.AddItem(coords=[[0, 0], [0, 0]],
- penName='rlisetup', hide=True)
- if self.samplingtype != SamplingType.VECT:
- self.toolbar.SelectDefault()
- def GetMap(self):
- return self.map_
- def OnPan(self, event):
- """Panning, set mouse to drag."""
- self.mapWindow.SetModePan()
- def OnZoomIn(self, event):
- """Zoom in the map."""
- self.mapWindow.SetModeZoomIn()
- def OnZoomOut(self, event):
- """Zoom out the map."""
- self.mapWindow.SetModeZoomOut()
- def OnZoomToMap(self, event):
- layers = self.map_.GetListOfLayers()
- self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
- def OnDrawRadius(self, event):
- """Start draw mode"""
- self.mapWindow.mouse['use'] = "None"
- self.mapWindow.mouse['box'] = "line"
- self.mapWindow.pen = wx.Pen(colour=wx.RED, width=1,
- style=wx.SHORT_DASH)
- self.mapWindow.SetNamedCursor('cross')
- self.mapWindow.mouseLeftUp.connect(self._radiusDrawn)
- def OnDigitizeRegion(self, event):
- """Start draw mode"""
- self.mapWindow.mouse['use'] = "None"
- self.mapWindow.mouse['box'] = "line"
- self.mapWindow.pen = wx.Pen(colour=wx.RED, width=1,
- style=wx.SHORT_DASH)
- self.mapWindow.SetNamedCursor('cross')
- self.mapWindow.mouseLeftUp.connect(self._lineSegmentDrawn)
- self.mapWindow.mouseDClick.connect(self._mouseDbClick)
- self._registeredGraphics.GetItem(0).SetCoords([])
- def OnDraw(self, event):
- """Start draw mode"""
- self.mapWindow.mouse['use'] = "None"
- self.mapWindow.mouse['box'] = "box"
- self.mapWindow.pen = wx.Pen(colour=wx.RED, width=2,
- style=wx.SHORT_DASH)
- self.mapWindow.SetNamedCursor('cross')
- self.mapWindow.mouseLeftUp.connect(self._rectangleDrawn)
- def _lineSegmentDrawn(self, x, y):
- item = self._registeredGraphics.GetItem(0)
- coords = item.GetCoords()
- if len(coords) == 0:
- coords.extend([self.mapWindow.Pixel2Cell(
- self.mapWindow.mouse['begin'])])
- coords.extend([[x, y]])
- item.SetCoords(coords)
- item.SetPropertyVal('hide', False)
- self.mapWindow.ClearLines()
- self._registeredGraphics.Draw()
- def _mouseDbClick(self, x, y):
- item = self._registeredGraphics.GetItem(0)
- coords = item.GetCoords()
- coords.extend([[x, y]])
- item.SetCoords(coords)
- item.SetPropertyVal('hide', False)
- self.mapWindow.ClearLines()
- self._registeredGraphics.Draw()
- self.createRegion()
- def createRegion(self):
- dlg = wx.TextEntryDialog(None, 'Name of sample region',
- 'Create region', 'region' + str(self.catId))
- ret = dlg.ShowModal()
- while True:
- if ret == wx.ID_OK:
- raster = dlg.GetValue()
- if checkMapExists(raster):
- GMessage(
- parent=self, message=_(
- "The raster file %s already"
- " exists, please change name") %
- raster)
- ret = dlg.ShowModal()
- else:
- dlg.Destroy()
- marea = self.writeArea(
- self._registeredGraphics.GetItem(0).GetCoords(), raster)
- self.nextRegion(next=True, area=marea)
- break
- else:
- self.nextRegion(next=False)
- break
- def nextRegion(self, next=True, area=None):
- self.mapWindow.ClearLines()
- item = self._registeredGraphics.GetItem(0)
- item.SetCoords([])
- item.SetPropertyVal('hide', True)
- layers = self.map_.GetListOfLayers()
- self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
- if next is True:
- self.afterRegionDrawn.emit(marea=area)
- else:
- gcmd.GMessage(parent=self.parent, message=_(
- "Raster map not created. Please redraw region."))
- def writeArea(self, coords, rasterName):
- polyfile = tempfile.NamedTemporaryFile(delete=False)
- polyfile.write("AREA\n")
- for coor in coords:
- east, north = coor
- point = " %s %s\n" % (east, north)
- polyfile.write(point)
- catbuf = "=%d a\n" % self.catId
- polyfile.write(catbuf)
- self.catId = self.catId + 1
- polyfile.close()
- region_settings = grass.parse_command('g.region', flags='p',
- delimiter=':')
- pname = polyfile.name.split('/')[-1]
- tmpraster = "rast_" + pname
- tmpvector = "vect_" + pname
- wx.BeginBusyCursor()
- wx.GetApp().Yield()
- RunCommand('r.in.poly', input=polyfile.name, output=tmpraster,
- rows=region_settings['rows'], overwrite=True)
- RunCommand('r.to.vect', input=tmpraster, output=tmpvector,
- type='area', overwrite=True)
- RunCommand('v.to.rast', input=tmpvector, output=rasterName,
- value=1, use='val')
- wx.EndBusyCursor()
- grass.use_temp_region()
- grass.run_command('g.region', vector=tmpvector)
- region = grass.region()
- marea = MaskedArea(region, rasterName)
- RunCommand('g.remove', flags='f', type='raster', name=tmpraster)
- RunCommand('g.remove', flags='f', type='vector', name=tmpvector)
- os.unlink(polyfile.name)
- return marea
- def _onToolChanged(self):
- """Helper function to disconnect drawing"""
- try:
- self.mapWindow.mouseLeftUp.disconnect(self._rectangleDrawn)
- self.mapWindow.mouseLeftUp.disconnect(self._radiusDrawn)
- self.mapWindow.mouseMoving.disconnect(self._mouseMoving)
- self.mapWindow.mouseLeftDown.disconnect(self._mouseLeftDown)
- self.mapWindow.mouseDClick.disconnect(self._mouseDbClick)
- except DispatcherKeyError:
- pass
- def _radiusDrawn(self, x, y):
- """When drawing finished, get region values"""
- mouse = self.mapWindow.mouse
- item = self._registeredGraphics.GetItem(0)
- p1 = mouse['begin']
- p2 = mouse['end']
- dist, (north, east) = self.mapWindow.Distance(p1, p2, False)
- circle = Circle(p1, dist)
- self.mapWindow.ClearLines()
- self.mapWindow.pdcTmp.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
- pen = wx.Pen(colour=wx.RED, width=2)
- self.mapWindow.pdcTmp.SetPen(pen)
- self.mapWindow.pdcTmp.DrawCircle(circle.point[0], circle.point[1],
- circle.radius)
- self._registeredGraphics.Draw()
- self.createCricle(circle)
- def createCricle(self, c):
- dlg = wx.TextEntryDialog(None,
- 'Name of sample circle region',
- 'Create circle region',
- 'circle' + str(self.catId))
- ret = dlg.ShowModal()
- while True:
- if ret == wx.ID_OK:
- raster = dlg.GetValue()
- if checkMapExists(raster):
- GMessage(
- parent=self, message=_(
- "The raster file %s already"
- " exists, please change name") %
- raster)
- ret = dlg.ShowModal()
- else:
- dlg.Destroy()
- circle = self.writeCircle(c, raster)
- self.nextCircle(next=True, circle=circle)
- break
- else:
- self.nextCircle(next=False)
- break
- def nextCircle(self, next=True, circle=None):
- self.mapWindow.ClearLines()
- item = self._registeredGraphics.GetItem(0)
- item.SetPropertyVal('hide', True)
- layers = self.map_.GetListOfLayers()
- self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
- if next is True:
- self.afterCircleDrawn.emit(region=circle)
- else:
- gcmd.GMessage(parent=self.parent, message=_(
- "Raster map not created. redraw region again."))
- def writeCircle(self, circle, rasterName):
- coords = self.mapWindow.Pixel2Cell(circle.point)
- RunCommand('r.circle', output=rasterName, max=circle.radius,
- coordinate=coords, flags="b")
- grass.use_temp_region()
- grass.run_command('g.region', zoom=rasterName)
- region = grass.region()
- marea = MaskedArea(region, rasterName, circle.radius)
- return marea
- def _rectangleDrawn(self):
- """When drawing finished, get region values"""
- mouse = self.mapWindow.mouse
- item = self._registeredGraphics.GetItem(0)
- p1 = self.mapWindow.Pixel2Cell(mouse['begin'])
- p2 = self.mapWindow.Pixel2Cell(mouse['end'])
- item.SetCoords([p1, p2])
- region = {'n': max(p1[1], p2[1]),
- 's': min(p1[1], p2[1]),
- 'w': min(p1[0], p2[0]),
- 'e': max(p1[0], p2[0])}
- item.SetPropertyVal('hide', False)
- self.mapWindow.ClearLines()
- self._registeredGraphics.Draw()
- if self.samplingtype in [SamplingType.MUNITSR, SamplingType.MMVWINR]:
- dlg = wx.MessageDialog(self, "Is this area ok?",
- "select sampling unit",
- wx.YES_NO | wx.ICON_QUESTION)
- ret = dlg.ShowModal()
- if ret == wx.ID_YES:
- grass.use_temp_region()
- grass.run_command('g.region', n=region['n'], s=region['s'],
- e=region['e'], w=region['w'])
- tregion = grass.region()
- self.sampleFrameChanged.emit(region=tregion)
- self.mapWindow.ClearLines()
- item = self._registeredGraphics.GetItem(0)
- item.SetPropertyVal('hide', True)
- layers = self.map_.GetListOfLayers()
- self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False,
- render=True)
- else:
- self.nextRegion(next=False)
- dlg.Destroy()
- elif self.samplingtype != SamplingType.WHOLE:
- """When drawing finished, get region values"""
- self.sampleFrameChanged.emit(region=region)
- icons = {
- 'draw': MetaIcon(
- img='edit',
- label=_('Draw sampling frame'),
- desc=_('Draw sampling frame by clicking and dragging')),
- 'digitizeunit': MetaIcon(
- img='edit',
- label=_('Draw sampling rectangle'),
- desc=_('Draw sampling rectangle by clicking and dragging')),
- 'digitizeunitc': MetaIcon(
- img='line-create',
- label=_('Draw sampling circle'),
- desc=_('Draw sampling circle radius by clicking and dragging')),
- 'digitizeregion': MetaIcon(
- img='polygon-create',
- label=_('Draw sampling region'),
- desc=_('Draw sampling region by polygon. Right Double click to end drawing'))}
- class RLiSetupToolbar(BaseToolbar):
- """IClass toolbar
- """
- def __init__(self, parent, toolSwitcher):
- """RLiSetup toolbar constructor
- """
- BaseToolbar.__init__(self, parent, toolSwitcher,
- style=wx.NO_BORDER | wx.TB_VERTICAL)
- self.InitToolbar(self._toolbarData())
- if self.parent.samplingtype == SamplingType.REGIONS:
- self._default = self.digitizeregion
- elif self.parent.samplingtype in [SamplingType.MUNITSR,
- SamplingType.MMVWINR]:
- self._default = self.digitizeunit
- elif self.parent.samplingtype in [SamplingType.MUNITSC,
- SamplingType.MMVWINC]:
- self._default = self.digitizeunitc
- elif self.parent.samplingtype == SamplingType.VECT:
- self._default = None
- else:
- self._default = self.draw
- for tool in (self._default, self.pan, self.zoomIn, self.zoomOut):
- if tool:
- self.toolSwitcher.AddToolToGroup(group='mouseUse',
- toolbar=self, tool=tool)
- # realize the toolbar
- self.Realize()
- def _toolbarData(self):
- """Toolbar data"""
- if self.parent.samplingtype == SamplingType.REGIONS:
- drawTool = ('digitizeregion', icons['digitizeregion'],
- self.parent.OnDigitizeRegion, wx.ITEM_CHECK)
- elif self.parent.samplingtype in [SamplingType.MUNITSR,
- SamplingType.MMVWINR]:
- drawTool = ('digitizeunit', icons['digitizeunit'],
- self.parent.OnDraw, wx.ITEM_CHECK)
- elif self.parent.samplingtype in [SamplingType.MUNITSC,
- SamplingType.MMVWINC]:
- drawTool = ('digitizeunitc', icons['digitizeunitc'],
- self.parent.OnDrawRadius, wx.ITEM_CHECK)
- else:
- drawTool = ('draw', icons['draw'], self.parent.OnDraw,
- wx.ITEM_CHECK)
- if self.parent.samplingtype == SamplingType.VECT:
- return self._getToolbarData((
- ('pan', BaseIcons['pan'], self.parent.OnPan,
- wx.ITEM_CHECK),
- ('zoomIn', BaseIcons['zoomIn'], self.parent.OnZoomIn,
- wx.ITEM_CHECK),
- ('zoomOut', BaseIcons['zoomOut'], self.parent.OnZoomOut,
- wx.ITEM_CHECK),
- ('zoomExtent', BaseIcons['zoomExtent'],
- self.parent.OnZoomToMap),))
- else:
- return self._getToolbarData(
- (drawTool, (None,),
- ('pan', BaseIcons['pan'],
- self.parent.OnPan, wx.ITEM_CHECK),
- ('zoomIn', BaseIcons['zoomIn'],
- self.parent.OnZoomIn, wx.ITEM_CHECK),
- ('zoomOut', BaseIcons['zoomOut'],
- self.parent.OnZoomOut, wx.ITEM_CHECK),
- ('zoomExtent', BaseIcons['zoomExtent'],
- self.parent.OnZoomToMap),))
|