1
# -*- coding: utf-8 -*-
3
@package rlisetup.sampling_frame
5
@brief r.li.setup - draw sample frame
8
- sampling_frame::RLiSetupMapPanel
9
- sampling_frame::RLiSetupToolbar
10
- sampling_frame::GraphicsSetItem
12
(C) 2013 by the GRASS Development Team
14
This program is free software under the GNU General Public License
15
(>=v2). Read the file COPYING that comes with GRASS for details.
17
@author Anna Petrasova <kratochanna gmail.com>
28
from core.gcmd import RunCommand
29
import grass.script.core as grass
33
from grass.lib.gis import *
34
from grass.lib.vector import *
35
from grass.lib.raster import *
39
from core.utils import _
40
from core.giface import StandaloneGrassInterface
41
from mapwin.base import MapWindowProperties
42
from mapwin.buffered import BufferedMapWindow
43
from core.render import Map
44
from gui_core.toolbars import BaseToolbar, BaseIcons, ToolSwitcher
45
from icons.icon import MetaIcon
46
from core.gcmd import GMessage
47
from grass.pydispatch.signal import Signal
48
from grass.pydispatch.errors import DispatcherKeyError
50
from functions import SamplingType, checkMapExists
54
def __init__(self, pt, r):
59
class MaskedArea(object):
60
def __init__(self, region, raster, radius):
66
class RLiSetupMapPanel(wx.Panel):
67
"""Panel with mapwindow used in r.li.setup"""
68
def __init__(self, parent, samplingType, icon=None, map_=None):
69
wx.Panel.__init__(self, parent=parent)
71
self.mapWindowProperties = MapWindowProperties()
72
self.mapWindowProperties.setValuesFromUserSettings()
73
giface = StandaloneGrassInterface()
74
self.samplingtype = samplingType
81
self.map_.region = self.map_.GetRegion()
83
self._mgr = wx.aui.AuiManager(self)
84
self.mapWindow = BufferedMapWindow(parent=self, giface=giface,
86
properties=self.mapWindowProperties)
87
self._mgr.AddPane(self.mapWindow, wx.aui.AuiPaneInfo().CentrePane().
88
Dockable(True).BestSize((-1, -1)).Name('mapwindow').
89
CloseButton(False).DestroyOnClose(True).
91
self._toolSwitcher = ToolSwitcher()
92
self._toolSwitcher.toggleToolChanged.connect(self._onToolChanged)
93
self.toolbar = RLiSetupToolbar(self, self._toolSwitcher)
97
self._mgr.AddPane(self.toolbar,
99
Name("maptoolbar").Caption(_("Map Toolbar")).
100
ToolbarPane().Left().Name('mapToolbar').
101
CloseButton(False).Layer(1).Gripper(False).
102
BestSize((self.toolbar.GetBestSize())))
105
if self.samplingtype == SamplingType.REGIONS:
106
self.afterRegionDrawn = Signal('RLiSetupMapPanel.afterRegionDrawn')
107
self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='line')
108
elif self.samplingtype in [SamplingType.MUNITSR, SamplingType.MMVWINR]:
109
self.sampleFrameChanged = Signal('RLiSetupMapPanel.sampleFrameChanged')
110
self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='rectangle')
111
elif self.samplingtype in [SamplingType.MUNITSC, SamplingType.MMVWINC]:
112
self.afterCircleDrawn = Signal('RLiSetupMapPanel.afterCircleDrawn')
113
self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='line')
115
self.sampleFrameChanged = Signal('RLiSetupMapPanel.sampleFrameChanged')
116
self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='rectangle')
118
self._registeredGraphics.AddPen('rlisetup', wx.Pen(wx.GREEN, width=2,
120
self._registeredGraphics.AddItem(coords=[[0, 0], [0, 0]],
121
penName='rlisetup', hide=True)
123
if self.samplingtype != SamplingType.VECT:
124
self.toolbar.SelectDefault()
129
def OnPan(self, event):
130
"""Panning, set mouse to drag."""
131
self.mapWindow.SetModePan()
133
def OnZoomIn(self, event):
134
"""Zoom in the map."""
135
self.mapWindow.SetModeZoomIn()
137
def OnZoomOut(self, event):
138
"""Zoom out the map."""
139
self.mapWindow.SetModeZoomOut()
141
def OnZoomToMap(self, event):
142
layers = self.map_.GetListOfLayers()
143
self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
145
def OnDrawRadius(self, event):
146
"""Start draw mode"""
147
self.mapWindow.mouse['use'] = "None"
148
self.mapWindow.mouse['box'] = "line"
149
self.mapWindow.pen = wx.Pen(colour=wx.RED, width=1,
151
self.mapWindow.SetNamedCursor('cross')
152
self.mapWindow.mouseLeftUp.connect(self._radiusDrawn)
154
def OnDigitizeRegion(self, event):
155
"""Start draw mode"""
156
self.mapWindow.mouse['use'] = "None"
157
self.mapWindow.mouse['box'] = "line"
158
self.mapWindow.pen = wx.Pen(colour=wx.RED, width=1,
160
self.mapWindow.SetNamedCursor('cross')
161
self.mapWindow.mouseLeftUp.connect(self._lineSegmentDrawn)
162
self.mapWindow.mouseDClick.connect(self._mouseDbClick)
164
self._registeredGraphics.GetItem(0).SetCoords([])
166
def OnDraw(self, event):
167
"""Start draw mode"""
168
self.mapWindow.mouse['use'] = "None"
169
self.mapWindow.mouse['box'] = "box"
170
self.mapWindow.pen = wx.Pen(colour=wx.RED, width=2,
172
self.mapWindow.SetNamedCursor('cross')
173
self.mapWindow.mouseLeftUp.connect(self._rectangleDrawn)
175
def _lineSegmentDrawn(self, x, y):
176
item = self._registeredGraphics.GetItem(0)
177
coords = item.GetCoords()
179
coords.extend([self.mapWindow.Pixel2Cell(self.mapWindow.mouse['begin'])])
180
coords.extend([[x, y]])
182
item.SetCoords(coords)
183
item.SetPropertyVal('hide', False)
184
self.mapWindow.ClearLines()
185
self._registeredGraphics.Draw(self.mapWindow.pdcTmp)
187
def _mouseDbClick(self, x, y):
188
item = self._registeredGraphics.GetItem(0)
189
coords = item.GetCoords()
190
coords.extend([[x, y]])
191
item.SetCoords(coords)
192
item.SetPropertyVal('hide', False)
193
self.mapWindow.ClearLines()
194
self._registeredGraphics.Draw(self.mapWindow.pdc)
197
def createRegion(self):
198
dlg = wx.TextEntryDialog(None, 'Name of sample region',
199
'Create region', 'region' + str(self.catId))
200
ret = dlg.ShowModal()
203
raster = dlg.GetValue()
204
if checkMapExists(raster):
205
GMessage(parent=self, message=_("The raster file %s already"
206
" exists, please change name") % raster)
207
ret = dlg.ShowModal()
210
marea = self.writeArea(self._registeredGraphics.GetItem(0).GetCoords(), raster)
211
self.nextRegion(next=True, area=marea)
214
self.nextRegion(next=False)
217
def nextRegion(self, next=True, area=None):
218
self.mapWindow.ClearLines()
219
item = self._registeredGraphics.GetItem(0)
221
item.SetPropertyVal('hide', True)
223
layers = self.map_.GetListOfLayers()
224
self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
226
self.afterRegionDrawn.emit(marea=area)
228
gcmd.GMessage(parent=self.parent,
229
message=_("Raster map not created. Please redraw region."))
231
def writeArea(self, coords, rasterName):
232
polyfile = tempfile.NamedTemporaryFile(delete=False)
233
polyfile.write("AREA\n")
236
point = " %s %s\n" % (east, north)
237
polyfile.write(point)
239
catbuf = "=%d a\n" % self.catId
240
polyfile.write(catbuf)
241
self.catId = self.catId + 1
244
region_settings = grass.parse_command('g.region', flags='p',
246
pname = polyfile.name.split('/')[-1]
247
tmpraster = "rast_" + pname
248
tmpvector = "vect_" + pname
251
RunCommand('r.in.poly', input=polyfile.name, output=tmpraster,
252
rows=region_settings['rows'], overwrite=True)
254
RunCommand('r.to.vect', input=tmpraster, output=tmpvector,
255
type='area', overwrite=True)
257
RunCommand('v.to.rast', input=tmpvector, output=rasterName,
260
grass.use_temp_region()
261
grass.run_command('g.region', vector=tmpvector)
262
region = grass.region()
264
marea = MaskedArea(region, rasterName)
266
RunCommand('g.remove', flags='f', type='raster', name=tmpraster)
267
RunCommand('g.remove', flags='f', type='vector', name=tmpvector)
269
os.unlink(polyfile.name)
272
def _onToolChanged(self):
273
"""Helper function to disconnect drawing"""
275
self.mapWindow.mouseLeftUp.disconnect(self._rectangleDrawn)
276
self.mapWindow.mouseLeftUp.disconnect(self._radiusDrawn)
277
self.mapWindow.mouseMoving.disconnect(self._mouseMoving)
278
self.mapWindow.mouseLeftDown.disconnect(self._mouseLeftDown)
279
self.mapWindow.mouseDClick.disconnect(self._mouseDbClick)
280
except DispatcherKeyError:
283
def _radiusDrawn(self, x, y):
284
"""When drawing finished, get region values"""
285
mouse = self.mapWindow.mouse
286
item = self._registeredGraphics.GetItem(0)
289
dist, (north, east) = self.mapWindow.Distance(p1, p2, False)
290
circle = Circle(p1, dist)
291
self.mapWindow.ClearLines()
292
self.mapWindow.pdcTmp.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
293
pen = wx.Pen(colour=wx.RED, width=2)
294
self.mapWindow.pdcTmp.SetPen(pen)
295
self.mapWindow.pdcTmp.DrawCircle(circle.point[0], circle.point[1],
297
self._registeredGraphics.Draw(self.mapWindow.pdcTmp)
298
self.createCricle(circle)
300
def createCricle(self, c):
301
dlg = wx.TextEntryDialog(None, 'Name of sample circle region',
302
'Create circle region', 'circle' + str(self.catId))
303
ret = dlg.ShowModal()
306
raster = dlg.GetValue()
307
if checkMapExists(raster):
308
GMessage(parent=self, message=_("The raster file %s already"
309
" exists, please change name") % raster)
310
ret = dlg.ShowModal()
313
circle = self.writeCircle(c, raster)
314
self.nextCircle(next=True, circle=circle)
317
self.nextCircle(next=False)
320
def nextCircle(self, next=True, circle=None):
321
self.mapWindow.ClearLines()
322
item = self._registeredGraphics.GetItem(0)
323
item.SetPropertyVal('hide', True)
324
layers = self.map_.GetListOfLayers()
325
self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
327
self.afterCircleDrawn.emit(region=circle)
329
gcmd.GMessage(parent=self.parent,
330
message=_("Raster map not created. redraw region again."))
332
def writeCircle(self, circle, rasterName):
333
coords = self.mapWindow.Pixel2Cell(circle.point)
334
RunCommand('r.circle', output=rasterName, max=circle.radius,
335
coordinate=coords, flags="b")
336
grass.use_temp_region()
337
grass.run_command('g.region', zoom=rasterName)
338
region = grass.region()
339
marea = MaskedArea(region, rasterName, circle.radius)
342
def _rectangleDrawn(self):
343
"""When drawing finished, get region values"""
344
mouse = self.mapWindow.mouse
345
item = self._registeredGraphics.GetItem(0)
346
p1 = self.mapWindow.Pixel2Cell(mouse['begin'])
347
p2 = self.mapWindow.Pixel2Cell(mouse['end'])
348
item.SetCoords([p1, p2])
349
region = {'n': max(p1[1], p2[1]),
350
's': min(p1[1], p2[1]),
351
'w': min(p1[0], p2[0]),
352
'e': max(p1[0], p2[0])}
353
item.SetPropertyVal('hide', False)
354
self.mapWindow.ClearLines()
355
self._registeredGraphics.Draw(self.mapWindow.pdcTmp)
356
if self.samplingtype in [SamplingType.MUNITSR, SamplingType.MMVWINR]:
357
dlg = wx.MessageDialog(self, "Is this area ok?",
358
"select sampling unit",
359
wx.YES_NO | wx.ICON_QUESTION)
360
ret = dlg.ShowModal()
362
grass.use_temp_region()
363
grass.run_command('g.region', n=region['n'], s=region['s'],
364
e=region['e'], w=region['w'])
365
tregion = grass.region()
366
self.sampleFrameChanged.emit(region=tregion)
367
self.mapWindow.ClearLines()
368
item = self._registeredGraphics.GetItem(0)
369
item.SetPropertyVal('hide', True)
370
layers = self.map_.GetListOfLayers()
371
self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False,
374
self.nextRegion(next=False)
377
elif self.samplingtype != SamplingType.WHOLE:
378
"""When drawing finished, get region values"""
379
self.sampleFrameChanged.emit(region=region)
381
icons = {'draw': MetaIcon(img='edit',
382
label=_('Draw sampling frame'),
383
desc=_('Draw sampling frame by clicking and dragging')),
384
'digitizeunit': MetaIcon(img='edit',
385
label=_('Draw sampling rectangle'),
386
desc=_('Draw sampling rectangle by clicking and dragging')),
387
'digitizeunitc': MetaIcon(img='line-create',
388
label=_('Draw sampling circle'),
389
desc=_('Draw sampling circle radius by clicking and dragging')),
390
'digitizeregion': MetaIcon(img='polygon-create',
391
label=_('Draw sampling region'),
392
desc=_('Draw sampling region by polygon. Right Double click to end drawing'))}
395
class RLiSetupToolbar(BaseToolbar):
398
def __init__(self, parent, toolSwitcher):
399
"""RLiSetup toolbar constructor
402
BaseToolbar.__init__(self, parent, toolSwitcher,
403
style=wx.NO_BORDER | wx.TB_VERTICAL)
405
self.InitToolbar(self._toolbarData())
407
if self.parent.samplingtype == SamplingType.REGIONS:
408
self._default = self.digitizeregion
409
elif self.parent.samplingtype in [SamplingType.MUNITSR,
410
SamplingType.MMVWINR]:
411
self._default = self.digitizeunit
412
elif self.parent.samplingtype in [SamplingType.MUNITSC,
413
SamplingType.MMVWINC]:
414
self._default = self.digitizeunitc
415
elif self.parent.samplingtype == SamplingType.VECT:
418
self._default = self.draw
420
for tool in (self._default, self.pan, self.zoomIn, self.zoomOut):
422
self.toolSwitcher.AddToolToGroup(group='mouseUse',
423
toolbar=self, tool=tool)
425
# realize the toolbar
428
def _toolbarData(self):
430
if self.parent.samplingtype == SamplingType.REGIONS:
431
drawTool = ('digitizeregion', icons['digitizeregion'],
432
self.parent.OnDigitizeRegion, wx.ITEM_CHECK)
433
elif self.parent.samplingtype in [SamplingType.MUNITSR,
434
SamplingType.MMVWINR]:
435
drawTool = ('digitizeunit', icons['digitizeunit'],
436
self.parent.OnDraw, wx.ITEM_CHECK)
437
elif self.parent.samplingtype in [SamplingType.MUNITSC,
438
SamplingType.MMVWINC]:
439
drawTool = ('digitizeunitc', icons['digitizeunitc'],
440
self.parent.OnDrawRadius, wx.ITEM_CHECK)
442
drawTool = ('draw', icons['draw'], self.parent.OnDraw,
444
if self.parent.samplingtype == SamplingType.VECT:
445
return self._getToolbarData((
446
('pan', BaseIcons['pan'], self.parent.OnPan,
448
('zoomIn', BaseIcons['zoomIn'], self.parent.OnZoomIn,
450
('zoomOut', BaseIcons['zoomOut'], self.parent.OnZoomOut,
452
('zoomExtent', BaseIcons['zoomExtent'],
453
self.parent.OnZoomToMap),))
455
return self._getToolbarData((drawTool, (None, ),
456
('pan', BaseIcons['pan'], self.parent.OnPan,
458
('zoomIn', BaseIcons['zoomIn'], self.parent.OnZoomIn,
460
('zoomOut', BaseIcons['zoomOut'], self.parent.OnZoomOut,
462
('zoomExtent', BaseIcons['zoomExtent'],
463
self.parent.OnZoomToMap),))