[GRASS-SVN] r57398 - grass/trunk/gui/wxpython/mapdisp
svn_grass at osgeo.org
svn_grass at osgeo.org
Sun Aug 4 09:47:23 PDT 2013
Author: annakrat
Date: 2013-08-04 09:47:23 -0700 (Sun, 04 Aug 2013)
New Revision: 57398
Modified:
grass/trunk/gui/wxpython/mapdisp/frame.py
grass/trunk/gui/wxpython/mapdisp/mapwindow.py
Log:
wxGUI: encapsulate measure functionality
Modified: grass/trunk/gui/wxpython/mapdisp/frame.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/frame.py 2013-08-04 16:37:56 UTC (rev 57397)
+++ grass/trunk/gui/wxpython/mapdisp/frame.py 2013-08-04 16:47:23 UTC (rev 57398)
@@ -63,7 +63,6 @@
import grass.script as grass
-haveCtypes = False
class MapFrame(SingleMapFrame):
"""!Main frame for map display window. Drawing takes place in
@@ -218,6 +217,8 @@
self.dialogs['query'] = None
self.decorationDialog = None # decoration/overlays
+
+ self.measureController = None
def GetMapWindow(self):
return self.MapWindow
@@ -864,90 +865,10 @@
return cmd
def OnMeasure(self, event):
- """!Init measurement routine that calculates map distance
- along transect drawn on map display
- """
- self.totaldist = 0.0 # total measured distance
-
- self.SwitchTool(self.toolbars['map'], event)
+ if not self.measureController:
+ self.measureController = MeasureController(self._giface)
+ self.measureController.StartMeasurement()
- # change mouse to draw line for measurement
- self.MapWindow.mouse['use'] = "measure"
- self.MapWindow.mouse['box'] = "line"
- self.MapWindow.zoomtype = 0
- self.MapWindow.pen = wx.Pen(colour = 'red', width = 2, style = wx.SHORT_DASH)
- self.MapWindow.polypen = wx.Pen(colour = 'green', width = 2, style = wx.SHORT_DASH)
-
- # change the cursor
- self.MapWindow.SetNamedCursor('pencil')
-
- # initiating output (and write a message)
- # e.g., in Layer Manager switch to output console
- # TODO: this should be something like: write important message or write tip
- # TODO: mixed 'switching' and message? no, measuring handles 'swithing' on its own
- self._giface.WriteWarning(_('Click and drag with left mouse button '
- 'to measure.%s'
- 'Double click with left button to clear.') % \
- (os.linesep))
- if self.Map.projinfo['proj'] != 'xy':
- units = self.Map.projinfo['units']
- self._giface.WriteCmdLog(_('Measuring distance') + ' ('
- + units + '):')
- else:
- self._giface.WriteCmdLog(_('Measuring distance:'))
-
- if self.Map.projinfo['proj'] == 'll':
- try:
- import grass.lib.gis as gislib
- global haveCtypes
- haveCtypes = True
-
- gislib.G_begin_distance_calculations()
- except ImportError, e:
- self._giface.WriteWarning(_('Geodesic distance is not yet '
- 'supported by this tool.\n'
- 'Reason: %s' % e))
-
- def MeasureDist(self, beginpt, endpt):
- """!Calculate map distance from screen distance
- and print to output window
- """
-
- dist, (north, east) = self.MapWindow.Distance(beginpt, endpt)
-
- dist = round(dist, 3)
- d, dunits = units.formatDist(dist, self.Map.projinfo['units'])
-
- self.totaldist += dist
- td, tdunits = units.formatDist(self.totaldist,
- self.Map.projinfo['units'])
-
- strdist = str(d)
- strtotdist = str(td)
-
- if self.Map.projinfo['proj'] == 'xy' or 'degree' not in self.Map.projinfo['unit']:
- angle = int(math.degrees(math.atan2(north,east)) + 0.5)
- # uncomment below (or flip order of atan2(y,x) above) to use
- # the mathematical theta convention (CCW from +x axis)
- #angle = 90 - angle
- if angle < 0:
- angle = 360 + angle
-
- mstring = '%s = %s %s\n%s = %s %s\n%s = %d %s\n%s' \
- % (_('segment'), strdist, dunits,
- _('total distance'), strtotdist, tdunits,
- _('bearing'), angle, _('degrees (clockwise from grid-north)'),
- '-' * 60)
- else:
- mstring = '%s = %s %s\n%s = %s %s\n%s' \
- % (_('segment'), strdist, dunits,
- _('total distance'), strtotdist, tdunits,
- '-' * 60)
-
- self._giface.WriteLog(mstring, priority=2)
-
- return dist
-
def OnProfile(self, event):
"""!Launch profile tool
"""
@@ -1281,6 +1202,8 @@
if btn.GetValue():
btn.SetValue(0)
self.dialogs['legend'].DisconnectResizing()
+ if self.measureController and self.measureController.IsMeasuring():
+ self.measureController.StopMeasurement(restore=False)
def ResetPointer(self):
"""Sets pointer mode.
@@ -1294,3 +1217,160 @@
toolbar.action['id'] = vars(toolbar)["pointer"]
toolbar.OnTool(None)
self.OnPointer(event=None)
+
+
+class MeasureController:
+ """!Class controls measuring in map display."""
+ def __init__(self, giface):
+ self._giface = giface
+ self._mapWindow = self._giface.GetMapWindow()
+ self._projInfo = self._mapWindow.Map.projinfo
+ self._measureGraphics = None
+
+ self._totaldist = 0.0 # total measured distance
+
+ self._oldMouseUse = None
+ self._oldCursor = None
+
+ def IsMeasuring(self):
+ """!Returns True if measuring mode is enabled, otherwise False"""
+ return bool(self._measureGraphics)
+
+ def _startMeasurement(self, x, y):
+ """!Handles the actual start of measuring
+ and adding each new point.
+
+ @param x,y east north coordinates
+ """
+ if not self._measureGraphics.GetAllItems():
+ item = self._measureGraphics.AddItem(coords=[[x, y]])
+ item.SetPropertyVal('penName', 'measure')
+ else:
+ # needed to switch mouse begin and end to draw intermediate line properly
+ coords = self._measureGraphics.GetItem(0).GetCoords()[-1]
+ self._mapWindow.mouse['begin'] = self._mapWindow.Cell2Pixel(coords)
+
+ def _addMeasurement(self, x, y):
+ """!New point added.
+
+ @param x,y east north coordinates
+ """
+ # add new point and calculate distance
+ item = self._measureGraphics.GetItem(0)
+ coords = item.GetCoords() + [[x, y]]
+ item.SetCoords(coords)
+ self.MeasureDist(coords[-2], coords[-1])
+ # draw
+ self._mapWindow.ClearLines()
+ self._measureGraphics.Draw(pdc=self._mapWindow.pdcTmp)
+
+ def StopMeasurement(self, restore=True):
+ """!Measure mode is stopped."""
+ self._mapWindow.ClearLines(pdc=self._mapWindow.pdcTmp)
+ self._mapWindow.mouse['end'] = self._mapWindow.mouse['begin']
+ # disconnect mouse events
+ self._mapWindow.mouseLeftUp.disconnect(self._addMeasurement)
+ self._mapWindow.mouseDClick.disconnect(self.StopMeasurement)
+ self._mapWindow.mouseLeftDown.disconnect(self._startMeasurement)
+ # unregister
+ self._mapWindow.UnregisterGraphicsToDraw(self._measureGraphics)
+ self._measureGraphics = None
+ self._mapWindow.Refresh()
+
+ if restore:
+ # restore mouse['use'] and cursor to the state before measuring starts
+ self._mapWindow.SetNamedCursor(self._oldCursor)
+ self._mapWindow.mouse['use'] = self._oldMouseUse
+
+ self._giface.WriteCmdLog(_('Measuring finished'))
+
+ def StartMeasurement(self):
+ """!Init measurement routine that calculates map distance
+ along transect drawn on map display
+ """
+ self._totaldist = 0.0 # total measured distance
+
+ self._oldMouseUse = self._mapWindow.mouse['use']
+ self._oldCursor = self._mapWindow.GetNamedCursor()
+
+ self._measureGraphics = self._mapWindow.RegisterGraphicsToDraw(graphicsType='line')
+
+ self._mapWindow.mouseLeftDown.connect(self._startMeasurement)
+ self._mapWindow.mouseDClick.connect(self.StopMeasurement)
+ self._mapWindow.mouseLeftUp.connect(self._addMeasurement)
+
+ # change mouse['box'] and pen to draw line during dragging
+ # TODO: better soluyion for drawing this line
+ self._mapWindow.mouse['use'] = None
+ self._mapWindow.mouse['box'] = "line"
+ self._mapWindow.pen = wx.Pen(colour='red', width=2, style=wx.SHORT_DASH)
+
+ self._measureGraphics.AddPen('measure', wx.Pen(colour='green', width=2, style=wx.SHORT_DASH) )
+
+ # change the cursor
+ self._mapWindow.SetNamedCursor('pencil')
+
+ # initiating output (and write a message)
+ # e.g., in Layer Manager switch to output console
+ # TODO: this should be something like: write important message or write tip
+ # TODO: mixed 'switching' and message? no, measuring handles 'swithing' on its own
+ self._giface.WriteWarning(_('Click and drag with left mouse button '
+ 'to measure.%s'
+ 'Double click with left button to clear.') % \
+ (os.linesep))
+ if self._projInfo['proj'] != 'xy':
+ mapunits = self._projInfo['units']
+ self._giface.WriteCmdLog(_('Measuring distance') + ' ('
+ + mapunits + '):')
+ else:
+ self._giface.WriteCmdLog(_('Measuring distance:'))
+
+ if self._projInfo['proj'] == 'll':
+ try:
+ import grass.lib.gis as gislib
+ gislib.G_begin_distance_calculations()
+ except ImportError, e:
+ self._giface.WriteWarning(_('Geodesic distance is not yet '
+ 'supported by this tool.\n'
+ 'Reason: %s' % e))
+
+ def MeasureDist(self, beginpt, endpt):
+ """!Calculate distance and print to output window.
+
+ @param beginpt,endpt EN coordinates
+ """
+ # move also Distance method?
+ dist, (north, east) = self._mapWindow.Distance(beginpt, endpt, screen=False)
+
+ dist = round(dist, 3)
+ d, dunits = units.formatDist(dist, self._projInfo['units'])
+
+ self._totaldist += dist
+ td, tdunits = units.formatDist(self._totaldist,
+ self._projInfo['units'])
+
+ strdist = str(d)
+ strtotdist = str(td)
+
+ if self._projInfo['proj'] == 'xy' or 'degree' not in self._projInfo['unit']:
+ angle = int(math.degrees(math.atan2(north,east)) + 0.5)
+ # uncomment below (or flip order of atan2(y,x) above) to use
+ # the mathematical theta convention (CCW from +x axis)
+ #angle = 90 - angle
+ if angle < 0:
+ angle = 360 + angle
+
+ mstring = '%s = %s %s\n%s = %s %s\n%s = %d %s\n%s' \
+ % (_('segment'), strdist, dunits,
+ _('total distance'), strtotdist, tdunits,
+ _('bearing'), angle, _('degrees (clockwise from grid-north)'),
+ '-' * 60)
+ else:
+ mstring = '%s = %s %s\n%s = %s %s\n%s' \
+ % (_('segment'), strdist, dunits,
+ _('total distance'), strtotdist, tdunits,
+ '-' * 60)
+
+ self._giface.WriteLog(mstring, priority=2)
+
+ return dist
Modified: grass/trunk/gui/wxpython/mapdisp/mapwindow.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/mapwindow.py 2013-08-04 16:37:56 UTC (rev 57397)
+++ grass/trunk/gui/wxpython/mapdisp/mapwindow.py 2013-08-04 16:47:23 UTC (rev 57398)
@@ -112,6 +112,10 @@
self.mouseLeftUpPointer = Signal('BufferedWindow.mouseLeftUpPointer')
# Emitted when left mouse button is released
self.mouseLeftUp = Signal('BufferedWindow.mouseLeftUp')
+ # Emitted when left mouse button was pressed
+ self.mouseLeftDown = Signal('BufferedWindow.mouseLeftDown')
+ # Emitted after double-click
+ self.mouseDClick = Signal('BufferedWindow.mouseDClick')
# Emitted when mouse us moving (mouse motion event)
# Parametres are x and y of the mouse position in map (cell) units
self.mouseMoving = Signal('BufferedWindow.mouseMoving')
@@ -734,17 +738,6 @@
if len(self.polycoords) > 0:
self.DrawLines(self.pdcTmp)
-
- #
- # clear measurement
- #
- if self.mouse["use"] == "measure":
- self.ClearLines(pdc = self.pdcTmp)
- self.polycoords = []
- self.mouse['use'] = 'pointer'
- self.mouse['box'] = 'point'
- self.mouse['end'] = [0, 0]
- self.SetNamedCursor('default')
stop = time.clock()
@@ -1121,8 +1114,7 @@
self.mouse['begin'] = event.GetPositionTuple()[:]
- if self.mouse["use"] in ["measure", "profile"]:
- # measure or profile
+ if self.mouse["use"] in ["profile"]:
if len(self.polycoords) == 0:
self.mouse['end'] = self.mouse['begin']
self.polycoords.append(self.Pixel2Cell(self.mouse['begin']))
@@ -1151,6 +1143,8 @@
self.dragid = idlist[0] #drag whatever is on top
else:
pass
+ coords = self.Pixel2Cell(self.mouse['begin'])
+ self.mouseLeftDown.emit(x=coords[0], y=coords[1])
event.Skip()
@@ -1183,11 +1177,7 @@
elif self.mouse["use"] == "query":
self.mapQueried.emit(x=self.mouse['end'][0], y=self.mouse['end'][1])
- elif self.mouse["use"] in ["measure", "profile"]:
- # measure or profile
- if self.mouse["use"] == "measure":
- self.frame.MeasureDist(self.mouse['begin'], self.mouse['end'])
-
+ elif self.mouse["use"] in ["profile"]:
self.polycoords.append(self.Pixel2Cell(self.mouse['end']))
self.ClearLines(pdc = self.pdcTmp)
self.DrawLines(pdc = self.pdcTmp)
@@ -1220,35 +1210,28 @@
Debug.msg (5, "BufferedWindow.OnButtonDClick(): use=%s" % \
self.mouse["use"])
- if self.mouse["use"] == "measure":
- # measure
- self.ClearLines(pdc=self.pdcTmp)
- self.polycoords = []
- self.mouse['use'] = 'pointer'
- self.mouse['box'] = 'point'
- self.mouse['end'] = [0, 0]
- self.Refresh()
- self.SetNamedCursor('default')
-
- elif self.mouse["use"] != "profile" or \
+ screenCoords = event.GetPosition()
+
+ if self.mouse["use"] != "profile" or \
(self.mouse['use'] != 'pointer' and \
hasattr(self, "digit")):
# select overlay decoration options dialog
- clickposition = event.GetPositionTuple()[:]
- idlist = self.pdc.FindObjects(clickposition[0], clickposition[1], self.hitradius)
- if idlist == []:
- return
- self.dragid = idlist[0]
+ idlist = self.pdc.FindObjects(screenCoords[0], screenCoords[1], self.hitradius)
+ if idlist:
+ self.dragid = idlist[0]
+
+ # self.ovlcoords[self.dragid] = self.pdc.GetIdBounds(self.dragid)
+ if self.dragid > 100:
+ self.currtxtid = self.dragid
+ self.frame.OnAddText(None)
+ elif self.dragid == 0:
+ self.frame.AddBarscale()
+ elif self.dragid == 1:
+ self.frame.AddLegend()
+
+ coords = self.Pixel2Cell(screenCoords)
+ self.mouseDClick.emit(x=coords[0], y=coords[1])
- # self.ovlcoords[self.dragid] = self.pdc.GetIdBounds(self.dragid)
- if self.dragid > 100:
- self.currtxtid = self.dragid
- self.frame.OnAddText(None)
- elif self.dragid == 0:
- self.frame.AddBarscale()
- elif self.dragid == 1:
- self.frame.AddLegend()
-
def OnRightDown(self, event):
"""!Right mouse button pressed
"""
@@ -1904,10 +1887,12 @@
size = self.properties["size"])
elif self.graphicsType == "line":
- if item.GetPropertyVal("pen"):
- self.parentMapWin.polypen = self.pens[item.GetPropertyVal("pen")]
+ if item.GetPropertyVal("penName"):
+ self.parentMapWin.polypen = self.pens[item.GetPropertyVal("penName")]
else:
self.parentMapWin.polypen = self.pens["default"]
+ coords = item.GetCoords()
+
self.drawFunc(pdc = pdc,
polycoords = coords)
itemOrderNum += 1
More information about the grass-commit
mailing list