[GRASS-SVN] r57593 - grass/trunk/gui/wxpython/animation
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Sep 4 18:41:36 PDT 2013
Author: annakrat
Date: 2013-09-04 18:41:36 -0700 (Wed, 04 Sep 2013)
New Revision: 57593
Modified:
grass/trunk/gui/wxpython/animation/controller.py
grass/trunk/gui/wxpython/animation/dialogs.py
grass/trunk/gui/wxpython/animation/mapwindow.py
grass/trunk/gui/wxpython/animation/utils.py
Log:
wxGUI/animations: possibility to add raster legend
Modified: grass/trunk/gui/wxpython/animation/controller.py
===================================================================
--- grass/trunk/gui/wxpython/animation/controller.py 2013-09-04 01:12:37 UTC (rev 57592)
+++ grass/trunk/gui/wxpython/animation/controller.py 2013-09-05 01:41:36 UTC (rev 57593)
@@ -379,7 +379,13 @@
prov = self.bitmapProviders[animationData.windowIndex]
prov.SetData(datasource = animationData.mapData, dataType=animationData.inputMapType)
- self.bitmapProviders[animationData.windowIndex].Load()
+ prov.Load()
+ if animationData.legendCmd:
+ try:
+ bitmap = prov.LoadOverlay(animationData.legendCmd)
+ self.mapwindows[animationData.windowIndex].SetOverlay(bitmap)
+ except GException:
+ GError(message=_("Failed to display legend."))
def _load3DData(self, animationData):
prov = self.bitmapProviders[animationData.windowIndex]
Modified: grass/trunk/gui/wxpython/animation/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/animation/dialogs.py 2013-09-04 01:12:37 UTC (rev 57592)
+++ grass/trunk/gui/wxpython/animation/dialogs.py 2013-09-05 01:41:36 UTC (rev 57593)
@@ -23,22 +23,20 @@
import wx
import copy
import datetime
-from wx.lib.newevent import NewEvent
import wx.lib.filebrowsebutton as filebrowse
if __name__ == '__main__':
sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "gui", "wxpython"))
-import grass.temporal as tgis
-
from core.gcmd import GMessage, GError, GException
from core import globalvar
from gui_core import gselect
from gui_core.dialogs import MapLayersDialog, GetImageHandlers
+from gui_core.forms import GUI
from core.settings import UserSettings
from core.utils import _
-from utils import TemporalMode, validateTimeseriesName, validateMapNames
+from utils import TemporalMode, getRegisteredMaps, validateTimeseriesName, validateMapNames
from nviztask import NvizTask
from grass.pydispatch.signal import Signal
@@ -271,6 +269,7 @@
self.SetTitle(_("Edit animation"))
self.animationData = animationData
+ self._tmpLegendCmd = None
self._layout()
self.OnViewMode(event = None)
@@ -357,6 +356,15 @@
self.addManyMapsButton = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bitmap)
self.addManyMapsButton.Bind(wx.EVT_BUTTON, self.OnAddMaps)
+ self.legend = wx.CheckBox(panel, label=_("Show raster legend"))
+ self.legend.SetValue(bool(self.animationData.legendCmd))
+ self.legendBtn = wx.Button(panel, label=_("Set options"))
+ self.legendBtn.Bind(wx.EVT_BUTTON, self.OnLegend)
+ tooltip = _("By default, legend is created for the first raster map in case of multiple maps "
+ "and for the first raster map of space time raster dataset.")
+ self.legend.SetToolTipString(tooltip)
+ self.legendBtn.SetToolTipString(tooltip)
+
self.OnDataType(None)
if self.animationData.inputData is None:
self.dataSelect.SetValue('')
@@ -375,7 +383,12 @@
hbox.Add(item = self.dataSelect, proportion = 1, flag = wx.ALIGN_CENTER)
hbox.Add(item = self.addManyMapsButton, proportion = 0, flag = wx.LEFT, border = 5)
dataBoxSizer.Add(item = hbox, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 3)
-
+
+ hbox = wx.BoxSizer(wx.HORIZONTAL)
+ hbox.Add(item=self.legend, proportion=1, flag=wx.ALIGN_CENTER_VERTICAL)
+ hbox.Add(item=self.legendBtn, proportion=0, flag=wx.LEFT, border=5)
+ dataBoxSizer.Add(item=hbox, proportion=0, flag=wx.EXPAND | wx.ALL, border=3)
+
panel.SetSizerAndFit(dataBoxSizer)
panel.SetAutoLayout(True)
@@ -446,6 +459,9 @@
self.dataSelect.SetType(etype = etype, multiple = False)
self.addManyMapsButton.Enable(False)
+ self.legend.Enable(etype in ('rast', 'strds'))
+ self.legendBtn.Enable(etype in ('rast', 'strds'))
+
self.dataSelect.SetValue('')
def OnAddMaps(self, event):
@@ -466,6 +482,45 @@
dlg.Destroy()
+ def OnLegend(self, event):
+ """!Set options for legend"""
+ if self._tmpLegendCmd:
+ cmd = self._tmpLegendCmd
+ elif self.animationData.legendCmd:
+ cmd = self.animationData.legendCmd
+ else:
+ cmd = ['d.legend', 'at=5,50,2,5']
+
+ mapName = self._getLegendMapHint()
+ if mapName:
+ cmd.append("map=%s" % mapName)
+
+ GUI(parent=self, modal=True).ParseCommand(cmd=cmd,
+ completed=(self.GetOptData, '', ''))
+
+ def _getLegendMapHint(self):
+ """!Determine probable map"""
+ inputData = self.dataSelect.GetValue()
+ etype = self.dataChoice.GetClientData(self.dataChoice.GetSelection())
+ if etype == 'strds':
+ timeseries = validateTimeseriesName(inputData, etype=etype)
+ timeseriesMaps = getRegisteredMaps(timeseries, etype)
+ if len(timeseriesMaps):
+ return timeseriesMaps[0]
+ else: # multiple raster
+ maps = inputData.split(',')
+ if len(maps):
+ return maps[0]
+
+ return None
+
+ def GetOptData(self, dcmd, layer, params, propwin):
+ """!Process decoration layer data"""
+ self._tmpLegendCmd = dcmd
+
+ if dcmd and not self.legend.IsChecked():
+ self.legend.SetValue(True)
+
def _update(self):
self.animationData.name = self.nameCtrl.GetValue()
self.animationData.windowIndex = self.windowChoice.GetSelection()
@@ -475,6 +530,13 @@
self.animationData.inputData = self.dataSelect.GetValue()
sel = self.nDChoice.GetSelection()
self.animationData.viewMode = self.nDChoice.GetClientData(sel)
+ if self._tmpLegendCmd:
+ if self.legend.IsChecked():
+ self.animationData.legendCmd = self._tmpLegendCmd
+ else:
+ if self.legend.IsChecked():
+ self.animationData.legendCmd = ['d.legend', 'at=5,50,2,5',
+ 'map=%s' % self._getLegendMapHint()]
if self.threeDPanel.IsShown():
self.animationData.workspaceFile = self.fileSelector.GetValue()
@@ -639,6 +701,7 @@
self.nvizParameter = self._nvizParameters[0]
self.workspaceFile = None
+ self.legendCmd = None
def GetName(self):
return self._name
@@ -691,21 +754,8 @@
self.mapData = newNames
elif self.inputMapType in ('strds', 'stvds'):
- timeseries = validateTimeseriesName(data, etype = self.inputMapType)
- if self.inputMapType == 'strds':
- sp = tgis.SpaceTimeRasterDataset(ident = timeseries)
- elif self.inputMapType == 'stvds':
- sp = tgis.SpaceTimeVectorDataset(ident = timeseries)
-
- if sp.is_in_db() == False:
- raise GException(_("Space time dataset <%s> not found.") % timeseries)
-
- sp.select()
- rows = sp.get_registered_maps(columns = "id", where = None, order = "start_time", dbif = None)
- timeseriesMaps = []
- if rows:
- for row in rows:
- timeseriesMaps.append(row["id"])
+ timeseries = validateTimeseriesName(data, etype=self.inputMapType)
+ timeseriesMaps = getRegisteredMaps(timeseries, self.inputMapType)
self._inputData = timeseries
self.mapData = timeseriesMaps
else:
@@ -769,7 +819,15 @@
return self._viewModes
viewModes = property(fget = GetViewModes)
+
+ def SetLegendCmd(self, cmd):
+ self._legendCmd = cmd
+ def GetLegendCmd(self):
+ return self._legendCmd
+
+ legendCmd = property(fget=GetLegendCmd, fset=SetLegendCmd)
+
def GetNvizCommands(self):
if not self.workspaceFile or not self.mapData:
return []
Modified: grass/trunk/gui/wxpython/animation/mapwindow.py
===================================================================
--- grass/trunk/gui/wxpython/animation/mapwindow.py 2013-09-04 01:12:37 UTC (rev 57592)
+++ grass/trunk/gui/wxpython/animation/mapwindow.py 2013-09-05 01:41:36 UTC (rev 57593)
@@ -21,10 +21,10 @@
from multiprocessing import Process, Queue
import tempfile
import grass.script as grass
-from core.gcmd import RunCommand
+from core.gcmd import RunCommand, GException
from core.debug import Debug
from core.settings import UserSettings
-from core.utils import _
+from core.utils import _, CmdToTuple
from grass.pydispatch.signal import Signal
@@ -71,7 +71,7 @@
# The Buffer init is done here, to make sure the buffer is always
# the same size as the Window
#Size = self.GetClientSizeTuple()
- size = self.ClientSize
+ size = self.GetClientSize()
# Make new offscreen bitmap: this bitmap will always have the
# current drawing in it, so it can be used to save the image to
@@ -112,6 +112,8 @@
self.bitmap = wx.EmptyBitmap(1, 1)
self.text = ''
self.parent = parent
+ self._pdc = wx.PseudoDC()
+ self._overlay = None
BufferedWindow.__init__(self, parent=parent, id=id, style=style)
self.SetBackgroundColour(wx.BLACK)
@@ -147,6 +149,33 @@
self.text = text
self.UpdateDrawing()
+ def DrawOverlay(self):
+ self._pdc.BeginDrawing()
+ self._pdc.DrawBitmap(bmp=self._overlay, x=0, y=0)
+ self._pdc.EndDrawing()
+
+ def SetOverlay(self, bitmap):
+ """!Sets overlay bitmap (legend)"""
+ Debug.msg(3, "AnimationWindow.SetOverlay()")
+ if bitmap:
+ if self._overlay:
+ self._pdc.RemoveAll()
+ self._overlay = bitmap
+ self._pdc.BeginDrawing()
+ self._pdc.DrawBitmap(bmp=bitmap, x=0, y=0)
+ self._pdc.EndDrawing()
+ else:
+ self._overlay = None
+ self._pdc.RemoveAll()
+ self.UpdateDrawing()
+
+ def OnPaint(self, event):
+ Debug.msg(5, "AnimationWindow.OnPaint()")
+ # All that is needed here is to draw the buffer to screen
+ dc = wx.BufferedPaintDC(self, self._Buffer)
+ if self._overlay:
+ self._pdc.DrawToDC(dc)
+
class BitmapProvider(object):
"""!Class responsible for loading data and providing bitmaps"""
def __init__(self, frame, bitmapPool, imageWidth=640, imageHeight=480, nprocs=4):
@@ -405,6 +434,30 @@
grass.try_remove(tempFileFormat)
os.environ.pop('GRASS_REGION')
+ def LoadOverlay(self, cmd):
+ """!Creates raster legend with d.legend
+
+ @param cmd d.legend command as a list
+
+ @return bitmap with legend
+ """
+ fileHandler, filename = tempfile.mkstemp(suffix=".png")
+ os.close(fileHandler)
+ # Set the environment variables for this process
+ _setEnvironment(self.imageWidth, self.imageHeight, filename, transparent=True)
+
+ Debug.msg(1, "Render raster legend " + str(filename))
+ cmdTuple = CmdToTuple(cmd)
+ returncode, stdout, messages = read2_command(cmdTuple[0], **cmdTuple[1])
+
+ if returncode == 0:
+ bitmap = wx.Bitmap(filename, wx.BITMAP_TYPE_PNG)
+ return bitmap
+ else:
+ os.remove(filename)
+ raise GException(messages)
+
+
def mapRenderProcess(mapType, mapname, width, height, fileQueue):
"""!Render raster or vector files as png image and write the
resulting png filename in the provided file queue
@@ -421,13 +474,7 @@
os.close(fileHandler)
# Set the environment variables for this process
- os.environ['GRASS_WIDTH'] = str(width)
- os.environ['GRASS_HEIGHT'] = str(height)
- driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
- os.environ['GRASS_RENDER_IMMEDIATE'] = driver
- os.environ['GRASS_TRUECOLOR'] = "1"
- os.environ['GRASS_TRANSPARENT'] = "1"
- os.environ['GRASS_PNGFILE'] = str(filename)
+ _setEnvironment(width, height, filename, transparent=False)
if mapType in ('rast', 'strds'):
Debug.msg(1, "Render raster image " + str(filename))
@@ -446,6 +493,21 @@
fileQueue.put(filename)
+
+def _setEnvironment(width, height, filename, transparent):
+ os.environ['GRASS_WIDTH'] = str(width)
+ os.environ['GRASS_HEIGHT'] = str(height)
+ driver = UserSettings.Get(group='display', key='driver', subkey='type')
+ os.environ['GRASS_RENDER_IMMEDIATE'] = driver
+ os.environ['GRASS_BACKGROUNDCOLOR'] = 'ffffff'
+ os.environ['GRASS_TRUECOLOR'] = "TRUE"
+ if transparent:
+ os.environ['GRASS_TRANSPARENT'] = "TRUE"
+ else:
+ os.environ['GRASS_TRANSPARENT'] = "FALSE"
+ os.environ['GRASS_PNGFILE'] = str(filename)
+
+
class BitmapPool():
"""!Class storing bitmaps (emulates dictionary)"""
def __init__(self):
Modified: grass/trunk/gui/wxpython/animation/utils.py
===================================================================
--- grass/trunk/gui/wxpython/animation/utils.py 2013-09-04 01:12:37 UTC (rev 57592)
+++ grass/trunk/gui/wxpython/animation/utils.py 2013-09-05 01:41:36 UTC (rev 57593)
@@ -93,6 +93,27 @@
raise GException(_("Map <%s> not found.") % name)
return newNames
+
+def getRegisteredMaps(timeseries, etype):
+ """!Returns list of maps registered in dataset"""
+ timeseriesMaps = []
+ if etype == 'strds':
+ sp = tgis.SpaceTimeRasterDataset(ident=timeseries)
+ elif etype == 'stvds':
+ sp = tgis.SpaceTimeVectorDataset(ident=timeseries)
+
+ if sp.is_in_db() == False:
+ raise GException(_("Space time dataset <%s> not found.") % timeseries)
+
+ sp.select()
+ rows = sp.get_registered_maps(columns="id", where=None, order="start_time", dbif=None)
+ timeseriesMaps = []
+ if rows:
+ for row in rows:
+ timeseriesMaps.append(row["id"])
+ return timeseriesMaps
+
+
def ComputeScaledRect(sourceSize, destSize):
"""!Fits source rectangle into destination rectangle
by scaling and centering.
More information about the grass-commit
mailing list