[GRASS-SVN] r58576 - grass/trunk/gui/wxpython/animation
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Jan 1 12:57:48 PST 2014
Author: annakrat
Date: 2014-01-01 12:57:48 -0800 (Wed, 01 Jan 2014)
New Revision: 58576
Modified:
grass/trunk/gui/wxpython/animation/controller.py
grass/trunk/gui/wxpython/animation/data.py
grass/trunk/gui/wxpython/animation/dialogs.py
grass/trunk/gui/wxpython/animation/provider.py
grass/trunk/gui/wxpython/animation/utils.py
Log:
wxGUI/animation: add option to change region during animation (suggested by lucadelu and neteler)
Modified: grass/trunk/gui/wxpython/animation/controller.py
===================================================================
--- grass/trunk/gui/wxpython/animation/controller.py 2014-01-01 19:54:09 UTC (rev 58575)
+++ grass/trunk/gui/wxpython/animation/controller.py 2014-01-01 20:57:48 UTC (rev 58576)
@@ -327,7 +327,9 @@
self.animations[i].SetActive(False)
continue
anim = [anim for anim in self.animationData if anim.windowIndex == i][0]
- self.animations[i].SetFrames([HashCmds(cmdList) for cmdList in anim.cmdMatrix])
+ regions = anim.GetRegions()
+ self.animations[i].SetFrames([HashCmds(cmdList, region)
+ for cmdList, region in zip(anim.cmdMatrix, regions)])
self.animations[i].SetActive(True)
else:
for i in range(len(self.animations)):
@@ -335,8 +337,10 @@
self.animations[i].SetActive(False)
continue
anim = [anim for anim in self.animationData if anim.windowIndex == i][0]
+ regions = anim.GetRegions()
identifiers = sampleCmdMatrixAndCreateNames(anim.cmdMatrix,
- mapNamesDict[anim.firstStdsNameType[0]])
+ mapNamesDict[anim.firstStdsNameType[0]],
+ regions)
self.animations[i].SetFrames(identifiers)
self.animations[i].SetActive(True)
@@ -367,7 +371,8 @@
def _set2DData(self, animationData):
opacities = [layer.opacity for layer in animationData.layerList if layer.active]
- self.bitmapProvider.SetCmds(animationData.cmdMatrix, opacities)
+ regions = animationData.GetRegions()
+ self.bitmapProvider.SetCmds(animationData.cmdMatrix, opacities, regions)
def _load3DData(self, animationData):
nviz = animationData.GetNvizCommands()
Modified: grass/trunk/gui/wxpython/animation/data.py
===================================================================
--- grass/trunk/gui/wxpython/animation/data.py 2014-01-01 19:54:09 UTC (rev 58575)
+++ grass/trunk/gui/wxpython/animation/data.py 2014-01-01 20:57:48 UTC (rev 58576)
@@ -17,6 +17,7 @@
@author Anna Petrasova <kratochanna gmail.com>
"""
import os
+import copy
from grass.script import core as gcore
@@ -24,7 +25,7 @@
from core.gcmd import GException
from animation.nviztask import NvizTask
from animation.utils import validateMapNames, getRegisteredMaps, \
- checkSeriesCompatibility, validateTimeseriesName
+ checkSeriesCompatibility, validateTimeseriesName, interpolate
from core.layerlist import LayerList, Layer
import grass.temporal as tgis
@@ -50,6 +51,11 @@
self.workspaceFile = None
self.legendCmd = None
+ self._startRegion = None
+ self._endRegion = None
+ self._zoomRegionValue = None
+ self._regions = None
+
def GetName(self):
return self._name
@@ -180,6 +186,77 @@
return {'commands': cmds, 'region': region}
+ def SetStartRegion(self, region):
+ self._startRegion = region
+
+ def GetStartRegion(self):
+ return self._startRegion
+
+ startRegion = property(fset=SetStartRegion, fget=GetStartRegion)
+
+ def SetEndRegion(self, region):
+ self._endRegion = region
+
+ def GetEndRegion(self):
+ return self._endRegion
+
+ endRegion = property(fset=SetEndRegion, fget=GetEndRegion)
+
+ def SetZoomRegionValue(self, value):
+ self._zoomRegionValue = value
+
+ def GetZoomRegionValue(self):
+ return self._zoomRegionValue
+
+ zoomRegionValue = property(fset=SetZoomRegionValue, fget=GetZoomRegionValue)
+
+ def GetRegions(self):
+ self._computeRegions(self._mapCount, self._startRegion,
+ self._endRegion, self._zoomRegionValue)
+ return self._regions
+
+ def _computeRegions(self, count, startRegion, endRegion=None, zoomValue=None):
+ """Computes regions based on start region and end region or zoom value
+ for each of the animation frames."""
+ currRegion = dict(gcore.region()) # cast to dict, otherwise deepcopy error
+ del currRegion['cells']
+ del currRegion['cols']
+ del currRegion['rows']
+ regions = []
+ for i in range(self._mapCount):
+ if endRegion or zoomValue:
+ regions.append(copy.copy(currRegion))
+ else:
+ regions.append(None)
+ if not startRegion:
+ self._regions = regions
+ return
+
+ startRegionDict = gcore.parse_key_val(gcore.read_command('g.region', flags='gu',
+ region=startRegion),
+ val_type=float)
+ if endRegion:
+ endRegionDict = gcore.parse_key_val(gcore.read_command('g.region', flags='gu',
+ region=endRegion),
+ val_type=float)
+ for key in ('n', 's', 'e', 'w'):
+ values = interpolate(startRegionDict[key], endRegionDict[key], self._mapCount)
+ for value, region in zip(values, regions):
+ region[key] = value
+
+ elif zoomValue:
+ for i in range(self._mapCount):
+ regions[i]['n'] -= zoomValue[0] * i
+ regions[i]['e'] -= zoomValue[1] * i
+ regions[i]['s'] += zoomValue[0] * i
+ regions[i]['w'] += zoomValue[1] * i
+
+ # handle cases when north < south and similarly EW
+ if regions[i]['n'] < regions[i]['s'] or \
+ regions[i]['e'] < regions[i]['w']:
+ regions[i] = regions[i - 1]
+ self._regions = regions
+
def __repr__(self):
return "%s(%r)" % (self.__class__, self.__dict__)
Modified: grass/trunk/gui/wxpython/animation/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/animation/dialogs.py 2014-01-01 19:54:09 UTC (rev 58575)
+++ grass/trunk/gui/wxpython/animation/dialogs.py 2014-01-01 20:57:48 UTC (rev 58576)
@@ -39,6 +39,7 @@
from core.settings import UserSettings
from core.utils import _
from gui_core.gselect import Select
+from gui_core.widgets import FloatValidator
from animation.utils import TemporalMode, getRegisteredMaps
from animation.data import AnimationData, AnimLayer
@@ -283,16 +284,40 @@
self.OnViewMode(event=None)
def _layout(self):
+ self.notebook = wx.Notebook(parent=self, style=wx.BK_DEFAULT)
+ sizer = wx.BoxSizer(wx.VERTICAL)
+ self.notebook.AddPage(self._createGeneralPage(self.notebook), _("General"))
+ self.notebook.AddPage(self._createAdvancedPage(self.notebook), _("Advanced"))
+ sizer.Add(self.notebook, proportion=1, flag=wx.ALL | wx.EXPAND, border=3)
+
+ # buttons
+ self.btnOk = wx.Button(self, wx.ID_OK)
+ self.btnCancel = wx.Button(self, wx.ID_CANCEL)
+ self.btnOk.SetDefault()
+ self.btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
+ # button sizer
+ btnStdSizer = wx.StdDialogButtonSizer()
+ btnStdSizer.AddButton(self.btnOk)
+ btnStdSizer.AddButton(self.btnCancel)
+ btnStdSizer.Realize()
+
+ sizer.Add(item=btnStdSizer, proportion=0,
+ flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=5)
+ self.SetSizer(sizer)
+ sizer.Fit(self)
+
+ def _createGeneralPage(self, parent):
+ panel = wx.Panel(parent=parent)
mainSizer = wx.BoxSizer(wx.VERTICAL)
- self.windowChoice = wx.Choice(self, id=wx.ID_ANY,
+ self.windowChoice = wx.Choice(panel, id=wx.ID_ANY,
choices=[_("top left"), _("top right"),
_("bottom left"), _("bottom right")])
self.windowChoice.SetSelection(self.animationData.windowIndex)
- self.nameCtrl = wx.TextCtrl(self, id=wx.ID_ANY, value=self.animationData.name)
+ self.nameCtrl = wx.TextCtrl(panel, id=wx.ID_ANY, value=self.animationData.name)
- self.nDChoice = wx.Choice(self, id=wx.ID_ANY)
+ self.nDChoice = wx.Choice(panel, id=wx.ID_ANY)
mode = self.animationData.viewMode
index = 0
for i, (viewMode, viewModeName) in enumerate(self.animationData.viewModes):
@@ -305,13 +330,13 @@
self.nDChoice.Bind(wx.EVT_CHOICE, self.OnViewMode)
gridSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
- gridSizer.Add(item=wx.StaticText(self, id=wx.ID_ANY, label=_("Name:")),
+ gridSizer.Add(item=wx.StaticText(panel, id=wx.ID_ANY, label=_("Name:")),
flag=wx.ALIGN_CENTER_VERTICAL)
gridSizer.Add(item=self.nameCtrl, proportion=1, flag=wx.EXPAND)
- gridSizer.Add(item=wx.StaticText(self, id=wx.ID_ANY, label=_("Window position:")),
+ gridSizer.Add(item=wx.StaticText(panel, id=wx.ID_ANY, label=_("Window position:")),
flag=wx.ALIGN_CENTER_VERTICAL)
gridSizer.Add(item=self.windowChoice, proportion=1, flag=wx.ALIGN_RIGHT)
- gridSizer.Add(item=wx.StaticText(self, id=wx.ID_ANY, label=_("View mode:")),
+ gridSizer.Add(item=wx.StaticText(panel, id=wx.ID_ANY, label=_("View mode:")),
flag=wx.ALIGN_CENTER_VERTICAL)
gridSizer.Add(item=self.nDChoice, proportion=1, flag=wx.ALIGN_RIGHT)
gridSizer.AddGrowableCol(0, 1)
@@ -319,40 +344,28 @@
mainSizer.Add(item=gridSizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=5)
label = _("For 3D animation, please select only one space-time dataset\n"
"or one series of map layers.")
- self.warning3DLayers = wx.StaticText(self, label=label)
+ self.warning3DLayers = wx.StaticText(panel, label=label)
self.warning3DLayers.SetForegroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT))
mainSizer.Add(item=self.warning3DLayers, proportion=0, flag=wx.EXPAND | wx.LEFT, border=5)
- self.dataPanel = self._createDataPanel()
- self.threeDPanel = self._create3DPanel()
+ self.dataPanel = self._createDataPanel(panel)
+ self.threeDPanel = self._create3DPanel(panel)
mainSizer.Add(item=self.dataPanel, proportion=1, flag=wx.EXPAND | wx.ALL, border=3)
mainSizer.Add(item=self.threeDPanel, proportion=0, flag=wx.EXPAND | wx.ALL, border=3)
- # buttons
- self.btnOk = wx.Button(self, wx.ID_OK)
- self.btnCancel = wx.Button(self, wx.ID_CANCEL)
- self.btnOk.SetDefault()
- self.btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
- # button sizer
- btnStdSizer = wx.StdDialogButtonSizer()
- btnStdSizer.AddButton(self.btnOk)
- btnStdSizer.AddButton(self.btnCancel)
- btnStdSizer.Realize()
+ panel.SetSizer(mainSizer)
+ mainSizer.Fit(panel)
- mainSizer.Add(item=btnStdSizer, proportion=0,
- flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=5)
+ return panel
- self.SetSizer(mainSizer)
- mainSizer.Fit(self)
-
- def _createDataPanel(self):
- panel = wx.Panel(self)
+ def _createDataPanel(self, parent):
+ panel = wx.Panel(parent)
slmgrSizer = wx.BoxSizer(wx.VERTICAL)
self._layerList = copy.deepcopy(self.animationData.layerList)
self.simpleLmgr = AnimSimpleLayerManager(parent=panel,
layerList=self._layerList,
modal=True)
- self.simpleLmgr.SetMinSize((globalvar.DIALOG_GSELECT_SIZE[0], 120))
+ self.simpleLmgr.SetMinSize((globalvar.DIALOG_GSELECT_SIZE[0], 80))
slmgrSizer.Add(self.simpleLmgr, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
self.legend = wx.CheckBox(panel, label=_("Show raster legend"))
@@ -371,8 +384,8 @@
return panel
- def _create3DPanel(self):
- panel = wx.Panel(self, id=wx.ID_ANY)
+ def _create3DPanel(self, parent):
+ panel = wx.Panel(parent, id=wx.ID_ANY)
dataStBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
label=' %s ' % _("3D view parameters"))
dataBoxSizer = wx.StaticBoxSizer(dataStBox, wx.VERTICAL)
@@ -407,16 +420,92 @@
return panel
+ def _createAdvancedPage(self, parent):
+ panel = wx.Panel(parent=parent)
+
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ box = wx.StaticBox(parent=panel, label=" %s " % _("Animate region change (2D view only)"))
+ sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
+
+ gridSizer = wx.GridBagSizer(hgap=3, vgap=3)
+ gridSizer.Add(wx.StaticText(panel, label=_("Start region:")),
+ pos=(0, 0), flag=wx.ALIGN_CENTER_VERTICAL)
+ self.stRegion = Select(parent=panel, type='region', size=(200, -1))
+ if self.animationData.startRegion:
+ self.stRegion.SetValue(self.animationData.startRegion)
+ gridSizer.Add(self.stRegion, pos=(0, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
+
+ self.endRegRadio = wx.RadioButton(panel, label=_("End region:"), style=wx.RB_GROUP)
+ gridSizer.Add(self.endRegRadio, pos=(1, 0), flag=wx.EXPAND)
+ self.endRegion = Select(parent=panel, type='region', size=(200, -1))
+ gridSizer.Add(self.endRegion, pos=(1, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
+ self.zoomRadio = wx.RadioButton(panel, label=_("Zoom value:"))
+ self.zoomRadio.SetToolTipString(_("N-S/E-W distances in map units used to "
+ "gradually reduce region."))
+ gridSizer.Add(self.zoomRadio, pos=(2, 0), flag=wx.EXPAND)
+
+ zoomSizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.zoomNS = wx.TextCtrl(panel, validator=FloatValidator())
+ self.zoomEW = wx.TextCtrl(panel, validator=FloatValidator())
+ zoomSizer.Add(wx.StaticText(panel, label=_("N-S:")), proportion=0,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=3)
+ zoomSizer.Add(self.zoomNS, proportion=1, flag=wx.LEFT, border=3)
+ zoomSizer.Add(wx.StaticText(panel, label=_("E-W:")), proportion=0,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=3)
+ zoomSizer.Add(self.zoomEW, proportion=1, flag=wx.LEFT, border=3)
+ gridSizer.Add(zoomSizer, pos=(2, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
+ if self.animationData.endRegion:
+ self.endRegRadio.SetValue(True)
+ self.zoomRadio.SetValue(False)
+ self.endRegion.SetValue(self.animationData.endRegion)
+ if self.animationData.zoomRegionValue:
+ self.endRegRadio.SetValue(False)
+ self.zoomRadio.SetValue(True)
+ zoom = self.animationData.zoomRegionValue
+ self.zoomNS.SetValue(str(zoom[0]))
+ self.zoomEW.SetValue(str(zoom[1]))
+
+ self.endRegRadio.Bind(wx.EVT_RADIOBUTTON, lambda evt: self._enableRegionWidgets())
+ self.zoomRadio.Bind(wx.EVT_RADIOBUTTON, lambda evt: self._enableRegionWidgets())
+ self._enableRegionWidgets()
+
+ gridSizer.AddGrowableCol(1)
+ sizer.Add(gridSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=3)
+ mainSizer.Add(sizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=3)
+
+ panel.SetSizer(mainSizer)
+ mainSizer.Fit(panel)
+
+ return panel
+
+ def _enableRegionWidgets(self):
+ """!Enables/disables region widgets
+ according to which radiobutton is active."""
+ endReg = self.endRegRadio.GetValue()
+ self.endRegion.Enable(endReg)
+ self.zoomNS.Enable(not endReg)
+ self.zoomEW.Enable(not endReg)
+
def OnViewMode(self, event):
mode = self.nDChoice.GetSelection()
self.Freeze()
self.simpleLmgr.Activate3D(mode == 1)
self.warning3DLayers.Show(mode == 1)
+
+ # disable region widgets for 3d
+ regSizer = self.stRegion.GetContainingSizer()
+ for child in regSizer.GetChildren():
+ if child.IsSizer():
+ for child_ in child.GetSizer().GetChildren():
+ child_.GetWindow().Enable(mode != 1)
+ elif child.IsWindow():
+ child.GetWindow().Enable(mode != 1)
+ self._enableRegionWidgets()
+
+ # update layout
sizer = self.threeDPanel.GetContainingSizer()
sizer.Show(self.threeDPanel, mode == 1, True)
sizer.Layout()
- self.Layout()
- self.Fit()
self.Thaw()
def OnLegend(self, event):
@@ -478,6 +567,31 @@
self.animationData.workspaceFile = self.fileSelector.GetValue()
if self.threeDPanel.IsShown():
self.animationData.nvizParameter = self.paramChoice.GetStringSelection()
+ # region (2d only)
+ if self.animationData.viewMode == '3d':
+ self.animationData.startRegion = None
+ self.animationData.endRegion = None
+ self.animationData.zoomRegionValue = None
+ return
+ isEnd = self.endRegRadio.GetValue() and self.endRegion.GetValue()
+ isZoom = self.zoomRadio.GetValue() and self.zoomNS.GetValue() and self.zoomEW.GetValue()
+ isStart = self.stRegion.GetValue()
+ condition = bool(isStart) + bool(isZoom) + bool(isEnd)
+ if condition == 1:
+ raise GException(_("Region information is not complete"))
+ elif condition == 2:
+ self.animationData.startRegion = isStart
+ if isEnd:
+ self.animationData.endRegion = self.endRegion.GetValue()
+ self.animationData.zoomRegionValue = None
+ else:
+ self.animationData.zoomRegionValue = (float(self.zoomNS.GetValue()),
+ float(self.zoomEW.GetValue()))
+ self.animationData.endRegion = None
+ else:
+ self.animationData.startRegion = None
+ self.animationData.endRegion = None
+ self.animationData.zoomRegionValue = None
def OnOk(self, event):
try:
Modified: grass/trunk/gui/wxpython/animation/provider.py
===================================================================
--- grass/trunk/gui/wxpython/animation/provider.py 2014-01-01 19:54:09 UTC (rev 58575)
+++ grass/trunk/gui/wxpython/animation/provider.py 2014-01-01 20:57:48 UTC (rev 58576)
@@ -60,6 +60,8 @@
self._cmds3D = []
self._regionFor3D = None
+ self._regions = []
+ self._regionsForUniqueCmds = []
self._renderer = BitmapRenderer(self._mapFilesPool, self._tempDir,
self.imageWidth, self.imageHeight)
@@ -77,7 +79,7 @@
self._renderer.renderingContinues.connect(self.renderingContinues)
self._composer.compositionContinues.connect(self.compositionContinues)
- def SetCmds(self, cmdsForComposition, opacities):
+ def SetCmds(self, cmdsForComposition, opacities, regions=None):
"""!Sets commands to be rendered with opacity levels.
Applies to 2D mode.
@@ -86,12 +88,15 @@
[['d.rast', 'map=elev_2002'], ['d.vect', 'map=points']],
...]
@param opacities list of opacity values
+ @param regions list of regions
"""
Debug.msg(2, "BitmapProvider.SetCmds: {} lists".format(len(cmdsForComposition)))
self._cmdsForComposition.extend(cmdsForComposition)
- self._uniqueCmds = self._getUniqueCmds()
self._opacities.extend(opacities)
+ self._regions.extend(regions)
+ self._getUniqueCmds()
+
def SetCmds3D(self, cmds, region):
"""!Sets commands for 3D rendering.
@@ -103,12 +108,19 @@
self._regionFor3D = region
def _getUniqueCmds(self):
- """!Returns list of unique commands."""
- unique = set()
- for cmdList in self._cmdsForComposition:
+ """!Returns list of unique commands.
+ Takes into account the region assigned."""
+ unique = list()
+ for cmdList, region in zip(self._cmdsForComposition, self._regions):
for cmd in cmdList:
- unique.add(tuple(cmd))
- return list(unique)
+ if region:
+ unique.append((tuple(cmd), tuple(sorted(region.items()))))
+ else:
+ unique.append((tuple(cmd), None))
+ unique = list(set(unique))
+ self._uniqueCmds = [cmdAndRegion[0] for cmdAndRegion in unique]
+ self._regionsForUniqueCmds.extend([dict(cmdAndRegion[1]) if cmdAndRegion[1] else None
+ for cmdAndRegion in unique])
def Unload(self):
"""!Unloads currently loaded data.
@@ -116,29 +128,32 @@
"""
Debug.msg(2, "BitmapProvider.Unload")
if self._cmdsForComposition:
- for cmd in self._uniqueCmds:
- del self._mapFilesPool[HashCmd(cmd)]
+ for cmd, region in zip(self._uniqueCmds, self._regionsForUniqueCmds):
+ del self._mapFilesPool[HashCmd(cmd, region)]
- for cmdList in self._cmdsForComposition:
- del self._bitmapPool[HashCmds(cmdList)]
+ for cmdList, region in zip(self._cmdsForComposition, self._regions):
+ del self._bitmapPool[HashCmds(cmdList, region)]
self._uniqueCmds = []
self._cmdsForComposition = []
self._opacities = []
+ self._regions = []
+ self._regionsForUniqueCmds = []
if self._cmds3D:
self._cmds3D = []
self._regionFor3D = None
- def _dryRender(self, uniqueCmds, force):
+ def _dryRender(self, uniqueCmds, regions, force):
"""!Determines how many files will be rendered.
@param uniqueCmds list of commands which are to be rendered
@param force if forced rerendering
+ @param regions list of regions assigned to the commands
"""
count = 0
- for cmd in uniqueCmds:
- filename = GetFileFromCmd(self._tempDir, cmd)
+ for cmd, region in zip(uniqueCmds, regions):
+ filename = GetFileFromCmd(self._tempDir, cmd, region)
if not force and os.path.exists(filename) and \
- self._mapFilesPool.GetSize(HashCmd(cmd)) == (self.imageWidth, self.imageHeight):
+ self._mapFilesPool.GetSize(HashCmd(cmd, region)) == (self.imageWidth, self.imageHeight):
continue
count += 1
@@ -146,18 +161,19 @@
return count
- def _dryCompose(self, cmdLists, force):
+ def _dryCompose(self, cmdLists, regions, force):
"""!Determines how many lists of (commands) files
will be composed (with g.pnmcomp).
@param cmdLists list of commands lists which are to be composed
+ @param regions list of regions assigned to the commands
@param force if forced rerendering
"""
count = 0
- for cmdList in cmdLists:
- if not force and HashCmds(cmdList) in self._bitmapPool and \
- self._bitmapPool[HashCmds(cmdList)].GetSize() == (self.imageWidth,
- self.imageHeight):
+ for cmdList, region in zip(cmdLists, regions):
+ if not force and HashCmds(cmdList, region) in self._bitmapPool and \
+ self._bitmapPool[HashCmds(cmdList, region)].GetSize() == (self.imageWidth,
+ self.imageHeight):
continue
count += 1
@@ -176,34 +192,37 @@
Debug.msg(2, "BitmapProvider.Load: "
"force={}, bgcolor={}, nprocs={}".format(force, bgcolor, nprocs))
cmds = []
+ regions = []
if self._uniqueCmds:
cmds.extend(self._uniqueCmds)
+ regions.extend(self._regionsForUniqueCmds)
if self._cmds3D:
cmds.extend(self._cmds3D)
+ regions.extend([None] * len(self._cmds3D))
- count = self._dryRender(cmds, force=force)
+ count = self._dryRender(cmds, regions, force=force)
self.renderingStarted.emit(count=count)
# create no data bitmap
if None not in self._bitmapPool or force:
self._bitmapPool[None] = createNoDataBitmap(self.imageWidth, self.imageHeight)
- ok = self._renderer.Render(cmds, regionFor3D=self._regionFor3D,
+ ok = self._renderer.Render(cmds, regions, regionFor3D=self._regionFor3D,
bgcolor=bgcolor, force=force, nprocs=nprocs)
self.renderingFinished.emit()
if not ok:
self.mapsLoaded.emit() # what to do here?
return
if self._cmdsForComposition:
- count = self._dryCompose(self._cmdsForComposition, force=force)
+ count = self._dryCompose(self._cmdsForComposition, self._regions, force=force)
self.compositionStarted.emit(count=count)
- self._composer.Compose(self._cmdsForComposition, self._opacities,
+ self._composer.Compose(self._cmdsForComposition, self._regions, self._opacities,
bgcolor=bgcolor, force=force, nprocs=nprocs)
self.compositionFinished.emit()
if self._cmds3D:
for cmd in self._cmds3D:
- self._bitmapPool[HashCmds([cmd])] = \
- wx.Bitmap(GetFileFromCmd(self._tempDir, cmd))
+ self._bitmapPool[HashCmds([cmd], None)] = \
+ wx.Bitmap(GetFileFromCmd(self._tempDir, cmd, None))
self.mapsLoaded.emit()
@@ -273,10 +292,11 @@
self._stopRendering = False
self._isRendering = False
- def Render(self, cmdList, regionFor3D, bgcolor, force, nprocs):
+ def Render(self, cmdList, regions, regionFor3D, bgcolor, force, nprocs):
"""!Renders all maps and stores files.
@param cmdList list of rendering commands to run
+ @param regions regions for 2D rendering assigned to commands
@param regionFor3D region for setting 3D view
@param bgcolor background color as a tuple of 3 values 0 to 255
@param force if True reload all data, otherwise only missing data
@@ -292,19 +312,19 @@
cmd_list = []
filteredCmdList = []
- for cmd in cmdList:
- filename = GetFileFromCmd(self._tempDir, cmd)
+ for cmd, region in zip(cmdList, regions):
+ filename = GetFileFromCmd(self._tempDir, cmd, region)
if not force and os.path.exists(filename) and \
- self._mapFilesPool.GetSize(HashCmd(cmd)) == (self.imageWidth, self.imageHeight):
+ self._mapFilesPool.GetSize(HashCmd(cmd, region)) == (self.imageWidth, self.imageHeight):
# for reference counting
- self._mapFilesPool[HashCmd(cmd)] = filename
+ self._mapFilesPool[HashCmd(cmd, region)] = filename
continue
- filteredCmdList.append(cmd)
+ filteredCmdList.append((cmd, region))
mapNum = len(filteredCmdList)
stopped = False
self._isRendering = True
- for cmd in filteredCmdList:
+ for cmd, region in filteredCmdList:
count += 1
# Queue object for interprocess communication
@@ -316,12 +336,13 @@
cmd, regionFor3D, bgcolor, q))
else:
p = Process(target=RenderProcess2D,
- args=(self.imageWidth, self.imageHeight, self._tempDir, cmd, bgcolor, q))
+ args=(self.imageWidth, self.imageHeight, self._tempDir,
+ cmd, region, bgcolor, q))
p.start()
queue_list.append(q)
proc_list.append(p)
- cmd_list.append(cmd)
+ cmd_list.append((cmd, region))
proc_count += 1
# Wait for all running processes and read/store the created images
@@ -329,8 +350,8 @@
for i in range(len(cmd_list)):
proc_list[i].join()
filename = queue_list[i].get()
- self._mapFilesPool[HashCmd(cmd_list[i])] = filename
- self._mapFilesPool.SetSize(HashCmd(cmd_list[i]),
+ self._mapFilesPool[HashCmd(cmd_list[i][0], cmd_list[i][1])] = filename
+ self._mapFilesPool.SetSize(HashCmd(cmd_list[i][0], cmd_list[i][1]),
(self.imageWidth, self.imageHeight))
proc_count = 0
@@ -367,10 +388,11 @@
self._stopComposing = False
self._isComposing = False
- def Compose(self, cmdLists, opacityList, bgcolor, force, nprocs):
+ def Compose(self, cmdLists, regions, opacityList, bgcolor, force, nprocs):
"""!Performs the composition of ppm/pgm files.
@param cmdLisst lists of rendering commands lists to compose
+ @param regions regions for 2D rendering assigned to commands
@param opacityList list of lists of opacity values
@param bgcolor background color as a tuple of 3 values 0 to 255
@param force if True reload all data, otherwise only missing data
@@ -387,31 +409,31 @@
cmd_lists = []
filteredCmdLists = []
- for cmdList in cmdLists:
- if not force and HashCmds(cmdList) in self._bitmapPool and \
- self._bitmapPool[HashCmds(cmdList)].GetSize() == (self.imageWidth,
- self.imageHeight):
+ for cmdList, region in zip(cmdLists, regions):
+ if not force and HashCmds(cmdList, region) in self._bitmapPool and \
+ self._bitmapPool[HashCmds(cmdList, region)].GetSize() == (self.imageWidth,
+ self.imageHeight):
# TODO: find a better way than to assign the same to increase the reference
- self._bitmapPool[HashCmds(cmdList)] = self._bitmapPool[HashCmds(cmdList)]
+ self._bitmapPool[HashCmds(cmdList, region)] = self._bitmapPool[HashCmds(cmdList, region)]
continue
- filteredCmdLists.append(cmdList)
+ filteredCmdLists.append((cmdList, region))
num = len(filteredCmdLists)
self._isComposing = True
- for cmdList in filteredCmdLists:
+ for cmdList, region in filteredCmdLists:
count += 1
# Queue object for interprocess communication
q = Queue()
# The separate render process
p = Process(target=CompositeProcess,
args=(self.imageWidth, self.imageHeight, self._tempDir,
- cmdList, opacityList, bgcolor, q))
+ cmdList, region, opacityList, bgcolor, q))
p.start()
queue_list.append(q)
proc_list.append(p)
- cmd_lists.append(cmdList)
+ cmd_lists.append((cmdList, region))
proc_count += 1
@@ -421,11 +443,11 @@
proc_list[i].join()
filename = queue_list[i].get()
if filename is None:
- self._bitmapPool[HashCmds(cmd_lists[i])] = \
+ self._bitmapPool[HashCmds(cmd_lists[i][0], cmd_lists[i][1])] = \
createNoDataBitmap(self.imageWidth, self.imageHeight,
text="Failed to render")
else:
- self._bitmapPool[HashCmds(cmd_lists[i])] = \
+ self._bitmapPool[HashCmds(cmd_lists[i][0], cmd_lists[i][1])] = \
wx.BitmapFromImage(wx.Image(filename))
os.remove(filename)
proc_count = 0
@@ -446,7 +468,7 @@
self._stopComposing = True
-def RenderProcess2D(imageWidth, imageHeight, tempDir, cmd, bgcolor, fileQueue):
+def RenderProcess2D(imageWidth, imageHeight, tempDir, cmd, region, bgcolor, fileQueue):
"""!Render raster or vector files as ppm image and write the
resulting ppm filename in the provided file queue
@@ -454,26 +476,32 @@
@param imageHeight image height
@param tempDir directory for rendering
@param cmd d.rast/d.vect command as a list
+ @param region region as a dict or None
@param bgcolor background color as a tuple of 3 values 0 to 255
@param fileQueue the inter process communication queue
storing the file name of the image
"""
- filename = GetFileFromCmd(tempDir, cmd)
+ filename = GetFileFromCmd(tempDir, cmd, region)
transparency = True
# Set the environment variables for this process
_setEnvironment(imageWidth, imageHeight, filename,
transparent=transparency, bgcolor=bgcolor)
-
+ if region:
+ os.environ['GRASS_REGION'] = gcore.region_env(**region)
cmdTuple = CmdToTuple(cmd)
returncode, stdout, messages = read2_command(cmdTuple[0], **cmdTuple[1])
if returncode != 0:
gcore.warning("Rendering failed:\n" + messages)
fileQueue.put(None)
+ if region:
+ os.environ.pop('GRASS_REGION')
os.remove(filename)
return
+ if region:
+ os.environ.pop('GRASS_REGION')
fileQueue.put(filename)
@@ -485,12 +513,13 @@
@param imageHeight image height
@param tempDir directory for rendering
@param cmd m.nviz.image command as a list
+ @param region region as a dict
@param bgcolor background color as a tuple of 3 values 0 to 255
@param fileQueue the inter process communication queue
storing the file name of the image
"""
- filename = GetFileFromCmd(tempDir, cmd)
+ filename = GetFileFromCmd(tempDir, cmd, None)
os.environ['GRASS_REGION'] = gcore.region_env(region3d=True, **region)
Debug.msg(1, "Render image to file " + str(filename))
@@ -512,7 +541,7 @@
fileQueue.put(filename)
-def CompositeProcess(imageWidth, imageHeight, tempDir, cmdList, opacities, bgcolor, fileQueue):
+def CompositeProcess(imageWidth, imageHeight, tempDir, cmdList, region, opacities, bgcolor, fileQueue):
"""!Performs the composition of image ppm files and writes the
resulting ppm filename in the provided file queue
@@ -520,6 +549,7 @@
@param imageHeight image height
@param tempDir directory for rendering
@param cmdList list of d.rast/d.vect commands
+ @param region region as a dict or None
@param opacities list of opacities
@param bgcolor background color as a tuple of 3 values 0 to 255
@param fileQueue the inter process communication queue
@@ -529,9 +559,9 @@
maps = []
masks = []
for cmd in cmdList:
- maps.append(GetFileFromCmd(tempDir, cmd))
- masks.append(GetFileFromCmd(tempDir, cmd, 'pgm'))
- filename = GetFileFromCmds(tempDir, cmdList)
+ maps.append(GetFileFromCmd(tempDir, cmd, region))
+ masks.append(GetFileFromCmd(tempDir, cmd, region, 'pgm'))
+ filename = GetFileFromCmds(tempDir, cmdList, region)
# Set the environment variables for this process
_setEnvironment(imageWidth, imageHeight, filename,
transparent=False, bgcolor=bgcolor)
Modified: grass/trunk/gui/wxpython/animation/utils.py
===================================================================
--- grass/trunk/gui/wxpython/animation/utils.py 2014-01-01 19:54:09 UTC (rev 58575)
+++ grass/trunk/gui/wxpython/animation/utils.py 2014-01-01 20:57:48 UTC (rev 58576)
@@ -242,26 +242,30 @@
return pilImage
-def HashCmd(cmd):
- """!Returns a hash from command given as a list."""
+def HashCmd(cmd, region):
+ """!Returns a hash from command given as a list and a region as a dict."""
name = '_'.join(cmd)
+ if region:
+ name += str(sorted(region.items()))
return hashlib.sha1(name).hexdigest()
-def HashCmds(cmds):
- """!Returns a hash from list of commands."""
+def HashCmds(cmds, region):
+ """!Returns a hash from list of commands and regions as dicts."""
name = ';'.join([item for sublist in cmds for item in sublist])
+ if region:
+ name += str(sorted(region.items()))
return hashlib.sha1(name).hexdigest()
-def GetFileFromCmd(dirname, cmd, extension='ppm'):
- """!Returns file path created as a hash from command."""
- return os.path.join(dirname, HashCmd(cmd) + '.' + extension)
+def GetFileFromCmd(dirname, cmd, region, extension='ppm'):
+ """!Returns file path created as a hash from command and region."""
+ return os.path.join(dirname, HashCmd(cmd, region) + '.' + extension)
-def GetFileFromCmds(dirname, cmds, extension='ppm'):
- """!Returns file path created as a hash from list of commands."""
- return os.path.join(dirname, HashCmds(cmds) + '.' + extension)
+def GetFileFromCmds(dirname, cmds, region, extension='ppm'):
+ """!Returns file path created as a hash from list of commands and regions."""
+ return os.path.join(dirname, HashCmds(cmds, region) + '.' + extension)
def layerListToCmdsMatrix(layerList):
@@ -295,7 +299,7 @@
return zip(*cmdsForComposition)
-def sampleCmdMatrixAndCreateNames(cmdMatrix, sampledSeries):
+def sampleCmdMatrixAndCreateNames(cmdMatrix, sampledSeries, regions):
"""!Applies information from temporal sampling
to the command matrix."""
namesList = []
@@ -306,7 +310,7 @@
if lastName != name:
lastName = name
j += 1
- namesList.append(HashCmds(cmdMatrix[j]))
+ namesList.append(HashCmds(cmdMatrix[j], regions[j]))
else:
namesList.append(None)
assert(j == len(cmdMatrix) - 1)
@@ -321,3 +325,29 @@
return cpu_count()
except NotImplementedError:
return 4
+
+
+def interpolate(start, end, count):
+ """!Interpolates values between start and end.
+
+ @param start start value (float)
+ @param end end value (float)
+ @param count total number of values including start and end
+
+ >>> interpolate(0, 10, 5)
+ [0, 2.5, 5.0, 7.5, 10]
+ >>> interpolate(10, 0, 5)
+ [10, 7.5, 5.0, 2.5, 0]
+ """
+ step = (end - start) / float(count - 1)
+ values = []
+ if start < end:
+ while start < end:
+ values.append(start)
+ start += step
+ else:
+ while end < start:
+ values.append(start)
+ start += step
+ values.append(end)
+ return values
More information about the grass-commit
mailing list