[GRASS-SVN] r58611 - in grass/trunk/gui: icons/grass wxpython/mapdisp wxpython/mapwin
svn_grass at osgeo.org
svn_grass at osgeo.org
Sat Jan 4 20:29:07 PST 2014
Author: annakrat
Date: 2014-01-04 20:29:07 -0800 (Sat, 04 Jan 2014)
New Revision: 58611
Added:
grass/trunk/gui/icons/grass/area-measure.png
Modified:
grass/trunk/gui/wxpython/mapdisp/frame.py
grass/trunk/gui/wxpython/mapdisp/toolbars.py
grass/trunk/gui/wxpython/mapwin/analysis.py
grass/trunk/gui/wxpython/mapwin/buffered.py
grass/trunk/gui/wxpython/mapwin/graphics.py
Log:
wxGUI: adds area measurement tool
Added: grass/trunk/gui/icons/grass/area-measure.png
===================================================================
(Binary files differ)
Property changes on: grass/trunk/gui/icons/grass/area-measure.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Modified: grass/trunk/gui/wxpython/mapdisp/frame.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/frame.py 2014-01-05 02:43:00 UTC (rev 58610)
+++ grass/trunk/gui/wxpython/mapdisp/frame.py 2014-01-05 04:29:07 UTC (rev 58611)
@@ -56,7 +56,8 @@
from wxplot.histogram import HistogramPlotFrame
from wxplot.profile import ProfileFrame
from wxplot.scatter import ScatterFrame
-from mapwin.analysis import ProfileController, MeasureDistanceController
+from mapwin.analysis import ProfileController, MeasureDistanceController, \
+ MeasureAreaController
from gui_core.forms import GUI
from core.giface import Notification
@@ -236,7 +237,7 @@
self.dialogs['vnet'] = None
self.dialogs['query'] = None
- self.measureDistController = None
+ self.measureController = None
def GetMapWindow(self):
return self.MapWindow
@@ -854,13 +855,22 @@
else:
return cmd
- def OnMeasure(self, event):
- if not self.measureDistController:
- self.measureDistController = MeasureDistanceController(self._giface,
- mapWindow=self.GetMapWindow())
- self._toolSwitcher.toggleToolChanged.connect(lambda: self.measureDistController.Stop())
- self.measureDistController.Start()
+ def OnMeasureDistance(self, event):
+ self._onMeasure(MeasureDistanceController)
+ def OnMeasureArea(self, event):
+ self._onMeasure(MeasureAreaController)
+
+ def _onMeasure(self, controller):
+ """!Starts measurement mode.
+
+ @param controller measurement class (MeasureDistanceController, MeasureAreaController)
+ """
+ self.measureController = controller(self._giface, mapWindow=self.GetMapWindow())
+ # assure that the mode is ended and lines are cleared whenever other tool is selected
+ self._toolSwitcher.toggleToolChanged.connect(lambda: self.measureController.Stop())
+ self.measureController.Start()
+
def OnProfile(self, event):
"""!Launch profile tool
"""
Modified: grass/trunk/gui/wxpython/mapdisp/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/mapdisp/toolbars.py 2014-01-05 02:43:00 UTC (rev 58610)
+++ grass/trunk/gui/wxpython/mapdisp/toolbars.py 2014-01-05 04:29:07 UTC (rev 58611)
@@ -37,8 +37,10 @@
'analyze' : MetaIcon(img = 'layer-raster-analyze',
label = _('Analyze map'),
desc = _('Measuring, profiling, histogramming, ...')),
- 'measure' : MetaIcon(img = 'measure-length',
- label = _('Measure distance')),
+ 'measureDistance': MetaIcon(img='measure-length',
+ label=_('Measure distance')),
+ 'measureArea' : MetaIcon(img='area-measure',
+ label=_('Measure area')),
'profile' : MetaIcon(img = 'layer-raster-profile',
label = _('Profile surface map')),
'scatter' : MetaIcon(img = 'layer-raster-profile',
@@ -236,7 +238,8 @@
def OnAnalyze(self, event):
"""!Analysis tools menu
"""
- self._onMenu(((MapIcons["measure"], self.parent.OnMeasure),
+ self._onMenu(((MapIcons["measureDistance"], self.parent.OnMeasureDistance),
+ (MapIcons["measureArea"], self.parent.OnMeasureArea),
(MapIcons["profile"], self.parent.OnProfile),
(MapIcons["scatter"], self.parent.OnScatterplot),
(MapIcons["histogram"], self.parent.OnHistogramPyPlot),
Modified: grass/trunk/gui/wxpython/mapwin/analysis.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/analysis.py 2014-01-05 02:43:00 UTC (rev 58610)
+++ grass/trunk/gui/wxpython/mapwin/analysis.py 2014-01-05 04:29:07 UTC (rev 58611)
@@ -23,9 +23,11 @@
from core.utils import _
import core.units as units
+from core.gcmd import RunCommand
from core.giface import Notification
from grass.pydispatch.signal import Signal
+import grass.script.core as gcore
class AnalysisControllerBase:
@@ -40,6 +42,7 @@
self._mapWindow = mapWindow
self._registeredGraphics = None
+ self._graphicsType = None
self._oldMouseUse = None
self._oldCursor = None
@@ -74,6 +77,7 @@
# draw
self._mapWindow.ClearLines()
self._registeredGraphics.Draw(pdc=self._mapWindow.pdcTmp)
+ self._mapWindow.Refresh()
wx.Yield()
self._doAnalysis(coords)
@@ -111,7 +115,7 @@
# unregister
self._mapWindow.UnregisterGraphicsToDraw(self._registeredGraphics)
self._registeredGraphics = None
- self._mapWindow.Refresh()
+ self._mapWindow.UpdateMap(render=False)
if restore:
# restore mouse['use'] and cursor to the state before measuring starts
@@ -125,8 +129,8 @@
self._oldMouseUse = self._mapWindow.mouse['use']
self._oldCursor = self._mapWindow.GetNamedCursor()
- self._registeredGraphics = self._mapWindow.RegisterGraphicsToDraw(graphicsType='line',
- mapCoords=False)
+ self._registeredGraphics = self._mapWindow.RegisterGraphicsToDraw(graphicsType=self._graphicsType,
+ mapCoords=True)
self._connectAll()
@@ -150,6 +154,7 @@
AnalysisControllerBase.__init__(self, giface=giface, mapWindow=mapWindow)
self.transectChanged = Signal('ProfileController.transectChanged')
+ self._graphicsType = 'line'
def _doAnalysis(self, coords):
"""!Informs profile dialog that profile changed.
@@ -183,6 +188,7 @@
self._projInfo = self._mapWindow.Map.projinfo
self._totaldist = 0.0 # total measured distance
self._useCtypes = False
+ self._graphicsType = 'line'
def _doAnalysis(self, coords):
"""!New point added.
@@ -226,12 +232,12 @@
# 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))
+ 'Double click with left button to clear.') %
+ (os.linesep))
if self._projInfo['proj'] != 'xy':
mapunits = self._projInfo['units']
self._giface.WriteCmdLog(_('Measuring distance') + ' ('
- + mapunits + '):')
+ + mapunits + '):')
else:
self._giface.WriteCmdLog(_('Measuring distance:'))
@@ -288,3 +294,72 @@
self._giface.WriteLog(mstring, notification=Notification.MAKE_VISIBLE)
return dist
+
+
+class MeasureAreaController(AnalysisControllerBase):
+ """!Class controls measuring area in map display."""
+ def __init__(self, giface, mapWindow):
+ AnalysisControllerBase.__init__(self, giface=giface, mapWindow=mapWindow)
+ self._graphicsType = 'polygon'
+
+ def _doAnalysis(self, coords):
+ """!New point added.
+
+ @param coords east north coordinates as a list
+ """
+ self.MeasureArea(coords)
+
+ def _disconnectAll(self):
+ self._mapWindow.mouseLeftDown.disconnect(self._start)
+ self._mapWindow.mouseLeftUp.disconnect(self._addPoint)
+ self._mapWindow.mouseDClick.disconnect(self.Stop)
+
+ def _connectAll(self):
+ self._mapWindow.mouseLeftDown.connect(self._start)
+ self._mapWindow.mouseLeftUp.connect(self._addPoint)
+ self._mapWindow.mouseDClick.connect(self.Stop)
+
+ def _getPen(self):
+ return wx.Pen(colour='green', width=2, style=wx.SOLID)
+
+ def Stop(self, restore=True):
+ if not self.IsActive():
+ return
+ AnalysisControllerBase.Stop(self, restore=restore)
+
+ self._giface.WriteCmdLog(_('Measuring finished'))
+
+ def Start(self):
+ """!Init measurement routine that calculates area of polygon
+ drawn on map display.
+ """
+ if self.IsActive():
+ return
+ AnalysisControllerBase.Start(self)
+
+ self._giface.WriteWarning(_('Click and drag with left mouse button '
+ 'to measure.%s'
+ 'Double click with left button to clear.') %
+ (os.linesep))
+ self._giface.WriteCmdLog(_('Measuring area:'))
+
+ def MeasureArea(self, coords):
+ """!Calculate area and print to output window.
+
+ @param coords list of E, N coordinates
+ """
+ # TODO: make sure appending first point is needed for m.measure
+ coordinates = coords + [coords[0]]
+ coordinates = ','.join([str(item) for sublist in coordinates for item in sublist])
+ result = RunCommand('m.measure', flags='g', coordinates=coordinates, read=True).strip()
+ result = gcore.parse_key_val(result)
+ if 'units' not in result:
+ self._giface.WriteWarning(_("Units not recognized, measurement failed."))
+ unit = ''
+ else:
+ unit = result['units'].split(',')[1]
+ if 'area' not in result:
+ text = _("Area: {area} {unit}\n").format(area=0, unit=unit)
+ else:
+ text = _("Area: {area} {unit}\n").format(area=result['area'], unit=unit)
+ self._giface.WriteLog(text, notification=Notification.MAKE_VISIBLE)
Modified: grass/trunk/gui/wxpython/mapwin/buffered.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/buffered.py 2014-01-05 02:43:00 UTC (rev 58610)
+++ grass/trunk/gui/wxpython/mapwin/buffered.py 2014-01-05 04:29:07 UTC (rev 58611)
@@ -323,6 +323,17 @@
pdc.SetIdBounds(drawid, wx.Rect(x1,y1,x2,y2))
# self.ovlcoords[drawid] = [x1,y1,x2,y2]
+ elif pdctype == 'polygon':
+ if pen:
+ pdc.SetPen(pen)
+ pdc.SetBrush(wx.TRANSPARENT_BRUSH)
+ pdc.DrawPolygon(points=coords)
+ x = min(coords, key=lambda x: x[0])[0]
+ y = min(coords, key=lambda x: x[1])[1]
+ w = max(coords, key=lambda x: x[0])[0] - x
+ h = max(coords, key=lambda x: x[1])[1] - y
+ pdc.SetIdBounds(drawid, wx.Rect(x, y, w, h))
+
elif pdctype == 'circle': # draw circle
if pen:
pdc.SetPen(pen)
@@ -944,8 +955,24 @@
return -1
+ def DrawPolylines(self, pdc, coords, pen, drawid=None):
+ """!Draw polyline in PseudoDC.
+
+ This is similar to DrawLines but this is used with GraphicsSet,
+ coordinates should be always in pixels.
+
+ @param pdc PseudoDC
+ @param coords list of coordinates (pixel coordinates)
+ @param pen pen to be used
+ @param drawid id of the drawn object (used by PseudoDC)
+ """
+ Debug.msg (4, "BufferedWindow.DrawPolylines(): coords=%s" % coords)
+ self.lineId = self.Draw(pdc, drawid=None, pdctype='polyline', coords=coords, pen=pen)
+
+ return self.lineid
+
def DrawCross(self, pdc, coords, size, rotation = 0, pen = None,
- text = None, textAlign = 'lr', textOffset = (5, 5)):
+ text = None, textAlign = 'lr', textOffset = (5, 5), drawid=None):
"""!Draw cross in PseudoDC
@todo implement rotation
@@ -956,19 +983,19 @@
@param text draw also text (text, font, color, rotation)
@param textAlign alignment (default 'lower-right')
@param textOffset offset for text (from center point)
+ @param drawid id of the drawn object (used by PseudoDC)
"""
Debug.msg(4, "BufferedWindow.DrawCross(): pdc=%s, coords=%s, size=%d" % \
(pdc, coords, size))
coordsCross = ((coords[0] - size, coords[1], coords[0] + size, coords[1]),
(coords[0], coords[1] - size, coords[0], coords[1] + size))
- self.lineid = wx.NewId()
for lineCoords in coordsCross:
- self.Draw(pdc, drawid = self.lineid, pdctype = 'line', coords = lineCoords, pen = pen)
-
+ self.lineid = self.Draw(pdc, drawid=drawid, pdctype='line', coords=lineCoords, pen=pen)
+
if not text:
return self.lineid
-
+
if textAlign == 'ul':
coord = [coords[0] - textOffset[0], coords[1] - textOffset[1], 0, 0]
elif textAlign == 'ur':
@@ -983,35 +1010,49 @@
return self.lineid
- def DrawRectangle(self, pdc, point1, point2, pen=None):
+ def DrawRectangle(self, pdc, point1, point2, pen, drawid=None):
"""!Draw rectangle (not filled) in PseudoDC
@param pdc PseudoDC
@param point1 top left corner (pixel coordinates)
@param point2 bottom right corner (pixel coordinates)
@param pen pen
+ @param drawid id of the drawn object (used by PseudoDC)
"""
Debug.msg(4, "BufferedWindow.DrawRectangle(): pdc=%s, point1=%s, point2=%s" % \
(pdc, point1, point2))
coords = [point1[0], point1[1], point2[0], point2[1]]
- self.lineid = self.Draw(pdc, drawid=None, pdctype='box', coords=coords, pen=pen)
+ self.lineid = self.Draw(pdc, drawid=drawid, pdctype='box', coords=coords, pen=pen)
return self.lineid
- def DrawCircle(self, pdc, coords, radius, pen=None):
+ def DrawCircle(self, pdc, coords, radius, pen, drawid=None):
"""!Draw circle (not filled) in PseudoDC
@param pdc PseudoDC
@param coords center (pixel coordinates)
@param radius radius
@param pen pen
+ @param drawid id of the drawn object (used by PseudoDC)
"""
Debug.msg(4, "BufferedWindow.DrawCircle(): pdc=%s, coords=%s, radius=%s" %
(pdc, coords, radius))
newcoords = [coords[0] - radius, coords[1] - radius,
coords[0] + radius, coords[1] + radius]
- self.lineid = self.Draw(pdc, drawid=None, pdctype='circle', coords=newcoords, pen=pen)
+ self.lineid = self.Draw(pdc, drawid=drawid, pdctype='circle', coords=newcoords, pen=pen)
return self.lineid
+ def DrawPolygon(self, pdc, coords, pen, drawid=None):
+ """!Draws polygon from a list of points (do not append the first point)
+
+ @param pdc PseudoDC
+ @param coords list of coordinates (pixel coordinates)
+ @param pen pen
+ @param drawid id of the drawn object (used by PseudoDC)
+ """
+ self.lineid = self.Draw(pdc, drawid=drawid, pdctype='polygon',
+ coords=coords, pen=pen)
+ return self.lineid
+
def _computeZoomToPointAndRecenter(self, position, zoomtype):
"""!Computes zoom parameters for recenter mode.
Modified: grass/trunk/gui/wxpython/mapwin/graphics.py
===================================================================
--- grass/trunk/gui/wxpython/mapwin/graphics.py 2014-01-05 02:43:00 UTC (rev 58610)
+++ grass/trunk/gui/wxpython/mapwin/graphics.py 2014-01-05 04:29:07 UTC (rev 58611)
@@ -63,11 +63,14 @@
self.drawFunc = self.parentMapWin.DrawCross
elif self.graphicsType == "line":
- self.drawFunc = self.parentMapWin.DrawLines
+ self.drawFunc = self.parentMapWin.DrawPolylines
elif self.graphicsType == "rectangle":
self.drawFunc = self.parentMapWin.DrawRectangle
+ elif self.graphicsType == "polygon":
+ self.drawFunc = self.parentMapWin.DrawPolygon
+
def Draw(self, pdc):
"""!Draws all containing items.
@@ -75,6 +78,7 @@
"""
itemOrderNum = 0
for item in self.itemsList:
+ self._clearId(pdc, item.GetId())
if self.setStatusFunc is not None:
self.setStatusFunc(item, itemOrderNum)
@@ -98,24 +102,24 @@
self.properties["text"]['color'] = self.parentMapWin.pen.GetColour()
self.properties["text"]['text'] = item.GetPropertyVal("label")
- self.drawFunc(pdc=pdc,
+ self.drawFunc(pdc=pdc, drawid=item.GetId(),
coords=coords,
text=self.properties["text"],
size=self.properties["size"])
elif self.graphicsType == "line":
if item.GetPropertyVal("penName"):
- self.parentMapWin.polypen = self.pens[item.GetPropertyVal("penName")]
+ pen = self.pens[item.GetPropertyVal("penName")]
else:
- self.parentMapWin.polypen = self.pens["default"]
+ pen = self.pens["default"]
if self.mapCoords:
coords = [self.parentMapWin.Cell2Pixel(coords) for coords in item.GetCoords()]
else:
coords = item.GetCoords()
- self.drawFunc(pdc=pdc,
- polycoords=coords)
+ self.drawFunc(pdc=pdc, pen=pen,
+ coords=coords, drawid=item.GetId())
elif self.graphicsType == "rectangle":
if item.GetPropertyVal("penName"):
@@ -127,9 +131,22 @@
else:
coords = item.GetCoords()
- self.drawFunc(pdc=pdc, pen=pen,
+ self.drawFunc(pdc=pdc, pen=pen, drawid=item.GetId(),
point1=coords[0],
point2=coords[1])
+
+ elif self.graphicsType == "polygon":
+ if item.GetPropertyVal("penName"):
+ pen = self.pens[item.GetPropertyVal("penName")]
+ else:
+ pen = self.pens["default"]
+ if self.mapCoords:
+ coords = [self.parentMapWin.Cell2Pixel(coords) for coords in item.GetCoords()]
+ else:
+ coords = item.GetCoords()
+
+ self.drawFunc(pdc=pdc, pen=pen,
+ coords=coords, drawid=item.GetId())
itemOrderNum += 1
def AddItem(self, coords, penName=None, label=None, hide=False):
@@ -282,7 +299,14 @@
except ValueError:
return None
+ def _clearId(self, pdc, drawid):
+ """!Clears old object before drawing new object."""
+ try:
+ pdc.ClearId(drawid)
+ except:
+ pass
+
class GraphicsSetItem:
def __init__(self, coords, penName=None, label=None, hide=False):
@@ -305,6 +329,7 @@
self.properties = {"penName": penName,
"hide": hide,
"label": label}
+ self.id = wx.NewId()
def SetPropertyVal(self, propName, propVal):
"""!Set property value
@@ -354,3 +379,8 @@
@returns coordinates
"""
return self.coords
+
+ def GetId(self):
+ """!Get item id (drawing id).
+ """
+ return self.id
More information about the grass-commit
mailing list