~ubuntu-branches/ubuntu/vivid/grass/vivid-proposed

« back to all changes in this revision

Viewing changes to gui/wxpython/rlisetup/sampling_frame.py

  • Committer: Package Import Robot
  • Author(s): Bas Couwenberg
  • Date: 2015-02-20 23:12:08 UTC
  • mfrom: (8.2.6 experimental)
  • Revision ID: package-import@ubuntu.com-20150220231208-1u6qvqm84v430b10
Tags: 7.0.0-1~exp1
* New upstream release.
* Update python-ctypes-ternary.patch to use if/else instead of and/or.
* Drop check4dev patch, rely on upstream check.
* Add build dependency on libpq-dev to grass-dev for libpq-fe.h.
* Drop patches applied upstream, refresh remaining patches.
* Update symlinks for images switched from jpg to png.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
"""
 
3
@package rlisetup.sampling_frame
 
4
 
 
5
@brief r.li.setup - draw sample frame
 
6
 
 
7
Classes:
 
8
 - sampling_frame::RLiSetupMapPanel
 
9
 - sampling_frame::RLiSetupToolbar
 
10
 - sampling_frame::GraphicsSetItem
 
11
 
 
12
(C) 2013 by the GRASS Development Team
 
13
 
 
14
This program is free software under the GNU General Public License
 
15
(>=v2). Read the file COPYING that comes with GRASS for details.
 
16
 
 
17
@author Anna Petrasova <kratochanna gmail.com>
 
18
"""
 
19
 
 
20
import os
 
21
 
 
22
import wx
 
23
import wx.aui
 
24
 
 
25
 
 
26
#start new import
 
27
import tempfile
 
28
from core.gcmd import RunCommand
 
29
import grass.script.core as grass
 
30
from core import gcmd
 
31
 
 
32
try:
 
33
    from grass.lib.gis    import *
 
34
    from grass.lib.vector import *
 
35
    from grass.lib.raster import *
 
36
except ImportError:
 
37
    pass
 
38
 
 
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
 
49
 
 
50
from functions import SamplingType, checkMapExists
 
51
 
 
52
 
 
53
class Circle:
 
54
    def __init__(self, pt, r):
 
55
        self.point = pt
 
56
        self.radius = r
 
57
 
 
58
 
 
59
class MaskedArea(object):
 
60
    def __init__(self, region, raster, radius):
 
61
        self.region = region
 
62
        self.raster = raster
 
63
        self.radius = radius
 
64
 
 
65
 
 
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)
 
70
 
 
71
        self.mapWindowProperties = MapWindowProperties()
 
72
        self.mapWindowProperties.setValuesFromUserSettings()
 
73
        giface = StandaloneGrassInterface()
 
74
        self.samplingtype = samplingType
 
75
        self.parent = parent
 
76
 
 
77
        if map_:
 
78
            self.map_ = map_
 
79
        else:
 
80
            self.map_ = Map()
 
81
        self.map_.region = self.map_.GetRegion()
 
82
 
 
83
        self._mgr = wx.aui.AuiManager(self)
 
84
        self.mapWindow = BufferedMapWindow(parent=self, giface=giface,
 
85
                                           Map=self.map_,
 
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).
 
90
                          Layer(0))
 
91
        self._toolSwitcher = ToolSwitcher()
 
92
        self._toolSwitcher.toggleToolChanged.connect(self._onToolChanged)
 
93
        self.toolbar = RLiSetupToolbar(self, self._toolSwitcher)
 
94
 
 
95
        self.catId = 1
 
96
 
 
97
        self._mgr.AddPane(self.toolbar,
 
98
                          wx.aui.AuiPaneInfo().
 
99
                          Name("maptoolbar").Caption(_("Map Toolbar")).
 
100
                          ToolbarPane().Left().Name('mapToolbar').
 
101
                          CloseButton(False).Layer(1).Gripper(False).
 
102
                          BestSize((self.toolbar.GetBestSize())))
 
103
        self._mgr.Update()
 
104
 
 
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')
 
114
        else:
 
115
            self.sampleFrameChanged = Signal('RLiSetupMapPanel.sampleFrameChanged')
 
116
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='rectangle')
 
117
 
 
118
        self._registeredGraphics.AddPen('rlisetup', wx.Pen(wx.GREEN, width=2,
 
119
                                                           style=wx.SOLID))
 
120
        self._registeredGraphics.AddItem(coords=[[0, 0], [0, 0]],
 
121
                                         penName='rlisetup', hide=True)
 
122
 
 
123
        if self.samplingtype != SamplingType.VECT:
 
124
            self.toolbar.SelectDefault()
 
125
 
 
126
    def GetMap(self):
 
127
        return self.map_
 
128
 
 
129
    def OnPan(self, event):
 
130
        """Panning, set mouse to drag."""
 
131
        self.mapWindow.SetModePan()
 
132
 
 
133
    def OnZoomIn(self, event):
 
134
        """Zoom in the map."""
 
135
        self.mapWindow.SetModeZoomIn()
 
136
 
 
137
    def OnZoomOut(self, event):
 
138
        """Zoom out the map."""
 
139
        self.mapWindow.SetModeZoomOut()
 
140
 
 
141
    def OnZoomToMap(self, event):
 
142
        layers = self.map_.GetListOfLayers()
 
143
        self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
 
144
 
 
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,
 
150
                                    style=wx.SHORT_DASH)
 
151
        self.mapWindow.SetNamedCursor('cross')
 
152
        self.mapWindow.mouseLeftUp.connect(self._radiusDrawn)
 
153
 
 
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,
 
159
                                    style=wx.SHORT_DASH)
 
160
        self.mapWindow.SetNamedCursor('cross')
 
161
        self.mapWindow.mouseLeftUp.connect(self._lineSegmentDrawn)
 
162
        self.mapWindow.mouseDClick.connect(self._mouseDbClick)
 
163
 
 
164
        self._registeredGraphics.GetItem(0).SetCoords([])
 
165
 
 
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,
 
171
                                    style=wx.SHORT_DASH)
 
172
        self.mapWindow.SetNamedCursor('cross')
 
173
        self.mapWindow.mouseLeftUp.connect(self._rectangleDrawn)
 
174
 
 
175
    def _lineSegmentDrawn(self, x, y):
 
176
        item = self._registeredGraphics.GetItem(0)
 
177
        coords = item.GetCoords()
 
178
        if len(coords) == 0:
 
179
            coords.extend([self.mapWindow.Pixel2Cell(self.mapWindow.mouse['begin'])])
 
180
        coords.extend([[x, y]])
 
181
 
 
182
        item.SetCoords(coords)
 
183
        item.SetPropertyVal('hide', False)
 
184
        self.mapWindow.ClearLines()
 
185
        self._registeredGraphics.Draw(self.mapWindow.pdcTmp)
 
186
 
 
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)
 
195
        self.createRegion()
 
196
 
 
197
    def createRegion(self):
 
198
        dlg = wx.TextEntryDialog(None, 'Name of sample region',
 
199
                                 'Create region', 'region' + str(self.catId))
 
200
        ret = dlg.ShowModal()
 
201
        while True:
 
202
            if ret == wx.ID_OK:
 
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()
 
208
                else:
 
209
                    dlg.Destroy()
 
210
                    marea = self.writeArea(self._registeredGraphics.GetItem(0).GetCoords(), raster)
 
211
                    self.nextRegion(next=True, area=marea)
 
212
                    break
 
213
            else:
 
214
                self.nextRegion(next=False)
 
215
                break
 
216
 
 
217
    def nextRegion(self, next=True, area=None):
 
218
        self.mapWindow.ClearLines()
 
219
        item = self._registeredGraphics.GetItem(0)
 
220
        item.SetCoords([])
 
221
        item.SetPropertyVal('hide', True)
 
222
 
 
223
        layers = self.map_.GetListOfLayers()
 
224
        self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
 
225
        if next is True:
 
226
            self.afterRegionDrawn.emit(marea=area)
 
227
        else:
 
228
            gcmd.GMessage(parent=self.parent,
 
229
                          message=_("Raster map not created. Please redraw region."))
 
230
 
 
231
    def writeArea(self, coords, rasterName):
 
232
        polyfile = tempfile.NamedTemporaryFile(delete=False)
 
233
        polyfile.write("AREA\n")
 
234
        for coor in coords:
 
235
            east, north = coor
 
236
            point = " %s %s\n" % (east, north)
 
237
            polyfile.write(point)
 
238
 
 
239
        catbuf = "=%d a\n" % self.catId
 
240
        polyfile.write(catbuf)
 
241
        self.catId = self.catId + 1
 
242
 
 
243
        polyfile.close()
 
244
        region_settings = grass.parse_command('g.region', flags='p',
 
245
                                              delimiter=':')
 
246
        pname = polyfile.name.split('/')[-1]
 
247
        tmpraster = "rast_" + pname
 
248
        tmpvector = "vect_" + pname
 
249
        wx.BeginBusyCursor()
 
250
        wx.Yield()
 
251
        RunCommand('r.in.poly', input=polyfile.name, output=tmpraster,
 
252
                   rows=region_settings['rows'], overwrite=True)
 
253
 
 
254
        RunCommand('r.to.vect', input=tmpraster, output=tmpvector,
 
255
                   type='area', overwrite=True)
 
256
 
 
257
        RunCommand('v.to.rast', input=tmpvector, output=rasterName,
 
258
                   value=1, use='val')
 
259
        wx.EndBusyCursor()
 
260
        grass.use_temp_region()
 
261
        grass.run_command('g.region', vector=tmpvector)
 
262
        region = grass.region()
 
263
 
 
264
        marea = MaskedArea(region, rasterName)
 
265
 
 
266
        RunCommand('g.remove', flags='f', type='raster', name=tmpraster)
 
267
        RunCommand('g.remove', flags='f', type='vector', name=tmpvector)
 
268
 
 
269
        os.unlink(polyfile.name)
 
270
        return marea
 
271
 
 
272
    def _onToolChanged(self):
 
273
        """Helper function to disconnect drawing"""
 
274
        try:
 
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:
 
281
            pass
 
282
 
 
283
    def _radiusDrawn(self, x, y):
 
284
        """When drawing finished, get region values"""
 
285
        mouse = self.mapWindow.mouse
 
286
        item = self._registeredGraphics.GetItem(0)
 
287
        p1 = mouse['begin']
 
288
        p2 = mouse['end']
 
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],
 
296
                                         circle.radius)
 
297
        self._registeredGraphics.Draw(self.mapWindow.pdcTmp)
 
298
        self.createCricle(circle)
 
299
 
 
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()
 
304
        while True:        
 
305
            if ret == wx.ID_OK:
 
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()
 
311
                else:
 
312
                    dlg.Destroy()
 
313
                    circle = self.writeCircle(c, raster)
 
314
                    self.nextCircle(next=True, circle=circle)
 
315
                    break
 
316
            else:
 
317
                self.nextCircle(next=False)
 
318
                break
 
319
 
 
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)
 
326
        if next is True:
 
327
            self.afterCircleDrawn.emit(region=circle)
 
328
        else:
 
329
            gcmd.GMessage(parent=self.parent,
 
330
                          message=_("Raster map not created. redraw region again."))
 
331
 
 
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)
 
340
        return marea
 
341
 
 
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()
 
361
            if ret == wx.ID_YES:
 
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,
 
372
                                         render=True)
 
373
            else:
 
374
                self.nextRegion(next=False)
 
375
            dlg.Destroy()
 
376
 
 
377
        elif self.samplingtype != SamplingType.WHOLE:
 
378
            """When drawing finished, get region values"""
 
379
            self.sampleFrameChanged.emit(region=region)
 
380
 
 
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'))}
 
393
 
 
394
 
 
395
class RLiSetupToolbar(BaseToolbar):
 
396
    """IClass toolbar
 
397
    """
 
398
    def __init__(self, parent, toolSwitcher):
 
399
        """RLiSetup toolbar constructor
 
400
        """
 
401
 
 
402
        BaseToolbar.__init__(self, parent, toolSwitcher,
 
403
                             style=wx.NO_BORDER | wx.TB_VERTICAL)
 
404
 
 
405
        self.InitToolbar(self._toolbarData())
 
406
 
 
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:
 
416
            self._default = None
 
417
        else:
 
418
            self._default = self.draw
 
419
 
 
420
        for tool in (self._default, self.pan, self.zoomIn, self.zoomOut):
 
421
            if tool:
 
422
                self.toolSwitcher.AddToolToGroup(group='mouseUse',
 
423
                                                 toolbar=self, tool=tool)
 
424
 
 
425
        # realize the toolbar
 
426
        self.Realize()
 
427
 
 
428
    def _toolbarData(self):
 
429
        """Toolbar data"""
 
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)
 
441
        else:
 
442
            drawTool = ('draw', icons['draw'], self.parent.OnDraw,
 
443
                        wx.ITEM_CHECK)
 
444
        if self.parent.samplingtype == SamplingType.VECT:
 
445
            return self._getToolbarData((
 
446
                       ('pan', BaseIcons['pan'], self.parent.OnPan,
 
447
                        wx.ITEM_CHECK),
 
448
                       ('zoomIn', BaseIcons['zoomIn'], self.parent.OnZoomIn,
 
449
                        wx.ITEM_CHECK),
 
450
                       ('zoomOut', BaseIcons['zoomOut'], self.parent.OnZoomOut,
 
451
                        wx.ITEM_CHECK),
 
452
                       ('zoomExtent', BaseIcons['zoomExtent'],
 
453
                        self.parent.OnZoomToMap),))
 
454
        else:
 
455
            return self._getToolbarData((drawTool, (None, ),
 
456
                       ('pan', BaseIcons['pan'], self.parent.OnPan,
 
457
                        wx.ITEM_CHECK),
 
458
                       ('zoomIn', BaseIcons['zoomIn'], self.parent.OnZoomIn,
 
459
                        wx.ITEM_CHECK),
 
460
                       ('zoomOut', BaseIcons['zoomOut'], self.parent.OnZoomOut,
 
461
                        wx.ITEM_CHECK),
 
462
                       ('zoomExtent', BaseIcons['zoomExtent'],
 
463
                        self.parent.OnZoomToMap),))