123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582 |
- """
- @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"].label),
- icons["digitizeregion"],
- self.parent.OnDigitizeRegion,
- wx.ITEM_CHECK,
- )
- elif self.parent.samplingtype in [SamplingType.MUNITSR, SamplingType.MMVWINR]:
- drawTool = (
- ("digitizeunit", icons["digitizeunit"].label),
- icons["digitizeunit"],
- self.parent.OnDraw,
- wx.ITEM_CHECK,
- )
- elif self.parent.samplingtype in [SamplingType.MUNITSC, SamplingType.MMVWINC]:
- drawTool = (
- ("digitizeunitc", icons["digitizeunitc"].label),
- icons["digitizeunitc"],
- self.parent.OnDrawRadius,
- wx.ITEM_CHECK,
- )
- else:
- drawTool = (
- ("draw", icons["draw"].label),
- icons["draw"],
- self.parent.OnDraw,
- wx.ITEM_CHECK,
- )
- if self.parent.samplingtype == SamplingType.VECT:
- return self._getToolbarData(
- (
- (
- ("pan", BaseIcons["pan"].label),
- BaseIcons["pan"],
- self.parent.OnPan,
- wx.ITEM_CHECK,
- ),
- (
- ("zoomIn", BaseIcons["zoomIn"].label),
- BaseIcons["zoomIn"],
- self.parent.OnZoomIn,
- wx.ITEM_CHECK,
- ),
- (
- ("zoomOut", BaseIcons["zoomOut"].label),
- BaseIcons["zoomOut"],
- self.parent.OnZoomOut,
- wx.ITEM_CHECK,
- ),
- (
- ("zoomExtent", BaseIcons["zoomExtent"].label),
- BaseIcons["zoomExtent"],
- self.parent.OnZoomToMap,
- ),
- )
- )
- else:
- return self._getToolbarData(
- (
- drawTool,
- (None,),
- (
- ("pan", BaseIcons["pan"].label),
- BaseIcons["pan"],
- self.parent.OnPan,
- wx.ITEM_CHECK,
- ),
- (
- ("zoomIn", BaseIcons["zoomIn"].label),
- BaseIcons["zoomIn"],
- self.parent.OnZoomIn,
- wx.ITEM_CHECK,
- ),
- (
- ("zoomOut", BaseIcons["zoomOut"].label),
- BaseIcons["zoomOut"],
- self.parent.OnZoomOut,
- wx.ITEM_CHECK,
- ),
- (
- ("zoomExtent", BaseIcons["zoomExtent"].label),
- BaseIcons["zoomExtent"],
- self.parent.OnZoomToMap,
- ),
- )
- )
|