[GRASS-SVN] r58343 - in grass/trunk/gui: icons/grass wxpython/animation wxpython/core wxpython/gui_core wxpython/lmgr
svn_grass at osgeo.org
svn_grass at osgeo.org
Sat Nov 30 19:46:14 PST 2013
Author: annakrat
Date: 2013-11-30 19:46:14 -0800 (Sat, 30 Nov 2013)
New Revision: 58343
Added:
grass/trunk/gui/icons/grass/mapset-add.png
grass/trunk/gui/wxpython/animation/data.py
grass/trunk/gui/wxpython/animation/provider.py
Modified:
grass/trunk/gui/wxpython/animation/__init__.py
grass/trunk/gui/wxpython/animation/anim.py
grass/trunk/gui/wxpython/animation/controller.py
grass/trunk/gui/wxpython/animation/dialogs.py
grass/trunk/gui/wxpython/animation/frame.py
grass/trunk/gui/wxpython/animation/g.gui.animation.py
grass/trunk/gui/wxpython/animation/mapwindow.py
grass/trunk/gui/wxpython/animation/nviztask.py
grass/trunk/gui/wxpython/animation/temporal_manager.py
grass/trunk/gui/wxpython/animation/toolbars.py
grass/trunk/gui/wxpython/animation/utils.py
grass/trunk/gui/wxpython/core/layerlist.py
grass/trunk/gui/wxpython/gui_core/simplelmgr.py
grass/trunk/gui/wxpython/lmgr/frame.py
Log:
wxGUI/animation: adding support for multiple base layers/series; pep8 compliance
Added: grass/trunk/gui/icons/grass/mapset-add.png
===================================================================
(Binary files differ)
Property changes on: grass/trunk/gui/icons/grass/mapset-add.png
___________________________________________________________________
Added: svn:mime-type
+ image/png
Modified: grass/trunk/gui/wxpython/animation/__init__.py
===================================================================
--- grass/trunk/gui/wxpython/animation/__init__.py 2013-11-30 19:48:36 UTC (rev 58342)
+++ grass/trunk/gui/wxpython/animation/__init__.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -9,4 +9,4 @@
'toolbars',
'utils',
'frame',
- ]
+]
Modified: grass/trunk/gui/wxpython/animation/anim.py
===================================================================
--- grass/trunk/gui/wxpython/animation/anim.py 2013-11-30 19:48:36 UTC (rev 58342)
+++ grass/trunk/gui/wxpython/animation/anim.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -6,18 +6,19 @@
Classes:
- anim::Animation
-(C) 2012 by the GRASS Development Team
+(C) 2013 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
- at author Anna Kratochvilova <kratochanna gmail.com>
+ at author Anna Petrasova <kratochanna gmail.com>
"""
import wx
from utils import Orientation, ReplayMode
from core.utils import _
+
class Animation(wx.EvtHandler):
"""!Animation class specifies which frame to show at which instance."""
def __init__(self):
@@ -28,7 +29,7 @@
# states
self.orientation = Orientation.FORWARD
self.replayMode = ReplayMode.ONESHOT
-
+
self.callbackUpdateFrame = None
self.callbackEndAnimation = None
self.callbackOrientationChanged = None
@@ -59,7 +60,7 @@
"""!Get frame count."""
return len(self.frames)
- count = property(fget = GetCount)
+ count = property(fget=GetCount)
def GetReplayMode(self):
"""!Returns replay mode (loop)."""
@@ -68,7 +69,7 @@
def SetReplayMode(self, mode):
self._replayMode = mode
- replayMode = property(fset = SetReplayMode, fget = GetReplayMode)
+ replayMode = property(fset=SetReplayMode, fget=GetReplayMode)
def GetOrientation(self):
return self._orientation
@@ -76,7 +77,7 @@
def SetOrientation(self, mode):
self._orientation = mode
- orientation = property(fset = SetOrientation, fget = GetOrientation)
+ orientation = property(fset=SetOrientation, fget=GetOrientation)
def SetCallbackUpdateFrame(self, callback):
"""!Sets function to be called when updating frame."""
@@ -92,7 +93,7 @@
def Start(self):
if not self.IsActive():
- return
+ return
def Pause(self, paused):
if not self.IsActive():
@@ -116,14 +117,14 @@
self.currentIndex = 0
elif self.replayMode == ReplayMode.REVERSE:
self.orientation = Orientation.BACKWARD
- self.currentIndex = self.count - 2 # -1
+ self.currentIndex = self.count - 2 # -1
self.callbackOrientationChanged(Orientation.BACKWARD)
else:
if self.replayMode == ReplayMode.REPEAT:
self.currentIndex = self.count - 1
elif self.replayMode == ReplayMode.REVERSE:
self.orientation = Orientation.FORWARD
- self.currentIndex = 1 # 0
+ self.currentIndex = 1 # 0
self.callbackOrientationChanged(Orientation.FORWARD)
def Update(self):
@@ -140,7 +141,7 @@
self.currentIndex -= 1
if self.currentIndex == -1:
self._arrivedToEnd()
-
+
def FrameChangedFromOutside(self, index):
"""!Let the animation know that frame was changed from outside."""
if not self.IsActive():
@@ -188,5 +189,3 @@
#
#if __name__ == '__main__':
# test()
-
-
Modified: grass/trunk/gui/wxpython/animation/controller.py
===================================================================
--- grass/trunk/gui/wxpython/animation/controller.py 2013-11-30 19:48:36 UTC (rev 58342)
+++ grass/trunk/gui/wxpython/animation/controller.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -6,12 +6,12 @@
Classes:
- controller::AnimationController
-(C) 2012 by the GRASS Development Team
+(C) 2013 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
- at author Anna Kratochvilova <kratochanna gmail.com>
+ at author Anna Petrasova <kratochanna gmail.com>
"""
import os
import wx
@@ -20,12 +20,15 @@
from core.utils import _
from grass.imaging import writeAvi, writeGif, writeIms, writeSwf
-from temporal_manager import TemporalManager
-from dialogs import InputDialog, EditDialog, AnimationData, ExportDialog
-from utils import TemporalMode, Orientation, RenderText, WxImageToPil
+from animation.temporal_manager import TemporalManager
+from animation.dialogs import InputDialog, EditDialog, ExportDialog
+from animation.utils import TemporalMode, Orientation, RenderText, WxImageToPil, \
+ sampleCmdMatrixAndCreateNames, layerListToCmdsMatrix, HashCmds
+from animation.data import AnimationData
+
class AnimationController(wx.EvtHandler):
- def __init__(self, frame, sliders, animations, mapwindows, providers, bitmapPool):
+ def __init__(self, frame, sliders, animations, mapwindows, provider, bitmapPool, mapFilesPool):
wx.EvtHandler.__init__(self)
self.mapwindows = mapwindows
@@ -38,14 +41,17 @@
self.temporalMode = None
self.animationData = []
- self.timer = wx.Timer(self, id = wx.NewId())
+ self.timer = wx.Timer(self, id=wx.NewId())
self.animations = animations
self.bitmapPool = bitmapPool
- self.bitmapProviders = providers
- for anim, win, provider in zip(self.animations, self.mapwindows, self.bitmapProviders):
- anim.SetCallbackUpdateFrame(lambda index, dataId, win = win, provider = provider : self.UpdateFrame(index, win, provider, dataId))
- anim.SetCallbackEndAnimation(lambda index, dataId, win = win, provider = provider: self.UpdateFrameEnd(index, win, provider, dataId))
+ self.mapFilesPool = mapFilesPool
+ self.bitmapProvider = provider
+ for anim, win in zip(self.animations, self.mapwindows):
+ anim.SetCallbackUpdateFrame(
+ lambda index, dataId, win=win: self.UpdateFrame(index, win, dataId))
+ anim.SetCallbackEndAnimation(
+ lambda index, dataId, win=win: self.UpdateFrameEnd(index, win, dataId))
anim.SetCallbackOrientationChanged(self.OrientationChangedInReverseMode)
for slider in self.sliders.values():
@@ -75,8 +81,8 @@
self.timer.Start(self._timeTick)
self.DisableSliderIfNeeded()
- timeTick = property(fget = GetTimeTick, fset = SetTimeTick)
-
+ timeTick = property(fget=GetTimeTick, fset=SetTimeTick)
+
def OnTimerTick(self, event):
for anim in self.animations:
anim.Update()
@@ -102,7 +108,7 @@
if not self.timer.IsRunning():
self.timer.Start(self.timeTick)
self.DisableSliderIfNeeded()
-
+
for anim in self.animations:
anim.Pause(paused)
@@ -114,20 +120,20 @@
for anim in self.animations:
anim.Stop()
- def UpdateFrameEnd(self, index, win, provider, dataId):
+ def UpdateFrameEnd(self, index, win, dataId):
if self.timer.IsRunning():
self.timer.Stop()
self.DisableSliderIfNeeded()
self.animationToolbar.Stop()
-
- self.UpdateFrame(index, win, provider, dataId)
- def UpdateFrame(self, index, win, provider, dataId):
- bitmap = provider.GetBitmap(dataId)
+ self.UpdateFrame(index, win, dataId)
+
+ def UpdateFrame(self, index, win, dataId):
+ bitmap = self.bitmapProvider.GetBitmap(dataId)
if dataId is None:
dataId = ''
- win.DrawBitmap(bitmap, dataId)
+ win.DrawBitmap(bitmap)
# self.frame.SetStatusText(dataId)
self.slider.UpdateFrame(index)
@@ -151,7 +157,6 @@
self.slider.EnableSlider(False)
else:
self.slider.EnableSlider(True)
-
def OrientationChangedInReverseMode(self, mode):
if mode == Orientation.FORWARD:
@@ -167,14 +172,13 @@
for anim in self.animations:
anim.orientation = mode
-
def SetTemporalMode(self, mode):
self._temporalMode = mode
def GetTemporalMode(self):
return self._temporalMode
- temporalMode = property(fget = GetTemporalMode, fset = SetTemporalMode)
+ temporalMode = property(fget=GetTemporalMode, fset=SetTemporalMode)
def GetTimeGranularity(self):
if self.temporalMode == TemporalMode.TEMPORAL:
@@ -187,9 +191,8 @@
# if self.timer.IsRunning():
# running = True
self.EndAnimation()
-
- dlg = EditDialog(parent = self.frame, evalFunction = self.EvaluateInput,
- animationData = self.animationData, maxAnimations = len(self.animations))
+ dlg = EditDialog(parent=self.frame, evalFunction=self.EvaluateInput,
+ animationData=self.animationData, maxAnimations=len(self.animations))
if dlg.ShowModal() == wx.ID_CANCEL:
dlg.Destroy()
return
@@ -206,9 +209,10 @@
if windowIndex not in indices:
found = True
break
-
+
if not found:
- GMessage(parent = self.frame, message = _("Maximum number of animations is %s.") % len(self.animations))
+ GMessage(parent=self.frame,
+ message=_("Maximum number of animations is %s.") % len(self.animations))
return
# running = False
@@ -221,20 +225,20 @@
# number of active animations
animationIndex = len([anim for anim in self.animations if anim.IsActive()])
animData.SetDefaultValues(windowIndex, animationIndex)
- dlg = InputDialog(parent = self.frame, mode = 'add', animationData = animData)
+ dlg = InputDialog(parent=self.frame, mode='add', animationData=animData)
if dlg.ShowModal() == wx.ID_CANCEL:
dlg.Destroy()
return
dlg.Destroy()
# check compatibility
if animData.windowIndex in indices:
- GMessage(parent = self.frame, message = _("More animations are using one window."
- " Please select different window for each animation."))
+ GMessage(parent=self.frame, message=_("More animations are using one window."
+ " Please select different window for each animation."))
return
try:
temporalMode, tempManager = self.EvaluateInput(self.animationData + [animData])
except GException, e:
- GError(parent = self.frame, message = e.value, showTraceback = False)
+ GError(parent=self.frame, message=e.value, showTraceback=False)
return
# if ok, set temporal mode
self.temporalMode = temporalMode
@@ -244,41 +248,28 @@
self.animationData.append(animData)
self._setAnimations()
- def SetAnimations(self, inputs=None, dataType=None):
+ def SetAnimations(self, layerLists):
"""!Set animation data directly.
- @param raster list of lists of raster maps or None
- @param strds list of strds or None
- @param inputs list of lists of raster maps or vector maps,
- or a space time raster or vector dataset
- @param dataType The type of the input data must be one of 'rast', 'vect', 'strds' or 'strds'
+ @param layerLists list of layerLists
"""
try:
animationData = []
for i in range(len(self.animations)):
- if inputs is not None and inputs[i]:
- if dataType == 'rast' or dataType == 'vect':
- if type(inputs[i]) == list:
- anim = AnimationData()
- anim.SetDefaultValues(i, i)
- anim.inputMapType = dataType
- anim.inputData = ','.join(inputs[i])
- animationData.append(anim)
- elif dataType == 'strds' or dataType == 'stvds':
- anim = AnimationData()
- anim.SetDefaultValues(i, i)
- anim.inputMapType = dataType
- anim.inputData = inputs[i]
- animationData.append(anim)
+ if layerLists[i]:
+ anim = AnimationData()
+ anim.SetDefaultValues(i, i)
+ anim.SetLayerList(layerLists[i])
+ animationData.append(anim)
except (GException, ValueError, IOError) as e:
- GError(parent = self.frame, message = str(e),
- showTraceback = False, caption = _("Invalid input"))
+ GError(parent=self.frame, message=str(e),
+ showTraceback=False, caption=_("Invalid input"))
return
try:
temporalMode, tempManager = self.EvaluateInput(animationData)
except GException, e:
- GError(parent = self.frame, message = e.value, showTraceback = False)
+ GError(parent=self.frame, message=e.value, showTraceback=False)
return
self.animationData = animationData
self.temporalManager = tempManager
@@ -288,15 +279,19 @@
def _setAnimations(self):
indices = [anim.windowIndex for anim in self.animationData]
- self._updateWindows(activeIndices = indices)
+ self._updateWindows(activeIndices=indices)
if self.temporalMode == TemporalMode.TEMPORAL:
timeLabels, mapNamesDict = self.temporalManager.GetLabelsAndMaps()
else:
timeLabels, mapNamesDict = None, None
-
- self._updateSlider(timeLabels = timeLabels)
- self._updateAnimations(activeIndices = indices, mapNamesDict = mapNamesDict)
+ for anim in self.animationData:
+ if anim.viewMode == '2d':
+ anim.cmdMatrix = layerListToCmdsMatrix(anim.layerList)
+ else:
+ anim.cmdMatrix = [(cmd,) for cmd in anim.GetNvizCommands()['commands']]
+ self._updateSlider(timeLabels=timeLabels)
+ self._updateAnimations(activeIndices=indices, mapNamesDict=mapNamesDict)
wx.Yield()
self._updateBitmapData()
# if running:
@@ -305,11 +300,11 @@
# else:
self.EndAnimation()
- def _updateSlider(self, timeLabels = None):
+ def _updateSlider(self, timeLabels=None):
if self.temporalMode == TemporalMode.NONTEMPORAL:
self.frame.SetSlider('nontemporal')
self.slider = self.sliders['nontemporal']
- frameCount = len(self.animationData[0].mapData) # should be the same for all
+ frameCount = self.animationData[0].mapCount
self.slider.SetFrames(frameCount)
elif self.temporalMode == TemporalMode.TEMPORAL:
self.frame.SetSlider('temporal')
@@ -320,14 +315,14 @@
self.frame.SetSlider(None)
self.slider = None
- def _updateAnimations(self, activeIndices, mapNamesDict = None):
+ def _updateAnimations(self, activeIndices, mapNamesDict=None):
if self.temporalMode == TemporalMode.NONTEMPORAL:
for i in range(len(self.animations)):
if i not in activeIndices:
self.animations[i].SetActive(False)
continue
anim = [anim for anim in self.animationData if anim.windowIndex == i][0]
- self.animations[i].SetFrames(anim.mapData)
+ self.animations[i].SetFrames([HashCmds(cmdList) for cmdList in anim.cmdMatrix])
self.animations[i].SetActive(True)
else:
for i in range(len(self.animations)):
@@ -335,7 +330,9 @@
self.animations[i].SetActive(False)
continue
anim = [anim for anim in self.animationData if anim.windowIndex == i][0]
- self.animations[i].SetFrames(mapNamesDict[anim.inputData])
+ identifiers = sampleCmdMatrixAndCreateNames(anim.cmdMatrix,
+ mapNamesDict[anim.firstStdsNameType[0]])
+ self.animations[i].SetFrames(identifiers)
self.animations[i].SetActive(True)
def _updateWindows(self, activeIndices):
@@ -347,48 +344,33 @@
self.frame.RemoveWindow(windowIndex)
def _updateBitmapData(self):
- # unload data:
- for prov in self.bitmapProviders:
- prov.Unload()
+ # unload previous data
+ self.bitmapProvider.Unload()
- # load data
+ # load new data
for animData in self.animationData:
if animData.viewMode == '2d':
- self._load2DData(animData)
+ self._set2DData(animData)
else:
self._load3DData(animData)
self._loadLegend(animData)
+ self.bitmapProvider.Load(nprocs=4)
+ # clear pools
+ self.bitmapPool.Clear()
+ self.mapFilesPool.Clear()
- # clear bitmapPool
- usedNames = []
- for prov in self.bitmapProviders:
- names = prov.GetDataNames()
- if names:
- usedNames.extend(names)
- self.bitmapPool.Clear(usedNames)
+ def _set2DData(self, animationData):
+ opacities = [layer.opacity for layer in animationData.layerList if layer.active]
+ self.bitmapProvider.SetCmds(animationData.cmdMatrix, opacities)
- def _load2DData(self, animationData):
- prov = self.bitmapProviders[animationData.windowIndex]
- prov.SetData(datasource = animationData.mapData, dataType=animationData.inputMapType)
-
- prov.Load()
-
def _load3DData(self, animationData):
- prov = self.bitmapProviders[animationData.windowIndex]
nviz = animationData.GetNvizCommands()
- prov.SetData(datasource = nviz['commands'],
- dataNames = animationData.mapData, dataType = 'nviz',
- suffix = animationData.nvizParameter,
- nvizRegion = nviz['region'])
+ self.bitmapProvider.SetCmds3D(nviz['commands'], nviz['region'])
- self.bitmapProviders[animationData.windowIndex].Load()
-
def _loadLegend(self, animationData):
if animationData.legendCmd:
- prov = self.bitmapProviders[animationData.windowIndex]
try:
- bitmap = prov.LoadOverlay(animationData.legendCmd)
- # place legend
+ bitmap = self.bitmapProvider.LoadOverlay(animationData.legendCmd)
try:
from PIL import Image
for param in animationData.legendCmd:
@@ -411,15 +393,15 @@
tempManager = None
windowIndex = []
for anim in animationData:
-
- mapCount.add(len(anim.mapData))
+ for layer in anim.layerList:
+ if layer.active and hasattr(layer, 'maps'):
+ if layer.mapType in ('strds', 'stvds'):
+ stds += 1
+ else:
+ maps += 1
+ mapCount.add(len(layer.maps))
windowIndex.append(anim.windowIndex)
- if anim.inputMapType in ('rast', 'vect'):
- maps += 1
- elif anim.inputMapType in ('strds', 'stvds'):
- stds += 1
-
if maps and stds:
temporalMode = TemporalMode.NONTEMPORAL
elif maps:
@@ -436,27 +418,24 @@
tempManager = TemporalManager()
# these raise GException:
for anim in animationData:
- if anim.inputMapType not in ('strds', 'stvds'):
- continue
- tempManager.AddTimeSeries(anim.inputData, anim.inputMapType)
+ tempManager.AddTimeSeries(*anim.firstStdsNameType)
+
message = tempManager.EvaluateInputData()
if message:
- GMessage(parent = self.frame, message = message)
+ GMessage(parent=self.frame, message=message)
return temporalMode, tempManager
def Reload(self):
self.EndAnimation()
- activeIndices = [anim.windowIndex for anim in self.animationData]
- for index in activeIndices:
- self.bitmapProviders[index].Load(force = True)
+ self.bitmapProvider.Load(force=True)
self.EndAnimation()
def Export(self):
if not self.animationData:
- GMessage(parent = self.frame, message = _("No animation to export."))
+ GMessage(parent=self.frame, message=_("No animation to export."))
return
if 'export' in self._dialogs:
@@ -468,14 +447,14 @@
dlg.doExport.connect(self._export)
self._dialogs['export'] = dlg
dlg.Show()
-
+
def _export(self, exportInfo, decorations):
size = self.frame.animationPanel.GetSize()
if self.temporalMode == TemporalMode.TEMPORAL:
timeLabels, mapNamesDict = self.temporalManager.GetLabelsAndMaps()
frameCount = len(timeLabels)
else:
- frameCount = len(self.animationData[0].mapData) # should be the same for all
+ frameCount = self.animationData[0].mapCount # should be the same for all
animWinSize = []
animWinPos = []
@@ -488,7 +467,7 @@
animWinPos.append(pos)
animWinSize.append(win.GetSize())
animWinIndex.append(i)
-
+
images = []
busy = wx.BusyInfo(message=_("Preparing export, please wait..."), parent=self.frame)
wx.Yield()
@@ -498,13 +477,13 @@
# collect bitmaps of all windows and paste them into the one
for i in animWinIndex:
frameId = self.animations[i].GetFrame(frameIndex)
- bitmap = self.bitmapProviders[i].GetBitmap(frameId)
+ bitmap = self.bitmapProvider.GetBitmap(frameId)
im = wx.ImageFromBitmap(bitmap)
# add legend if used
legend = legends[i]
if legend:
- legendBitmap = self.bitmapProviders[i].LoadOverlay(legend)
+ legendBitmap = self.bitmapProvider.LoadOverlay(legend)
x, y = self.mapwindows[i].GetOverlayPos()
legImage = wx.ImageFromBitmap(legendBitmap)
# not so nice result, can we handle the transparency otherwise?
@@ -525,11 +504,11 @@
timeLabel = timeLabels[frameIndex]
if timeLabel[1]:
text = _("%(from)s %(dash)s %(to)s") % \
- {'from': timeLabel[0], 'dash': u"\u2013", 'to': timeLabel[1]}
+ {'from': timeLabel[0], 'dash': u"\u2013", 'to': timeLabel[1]}
else:
text = _("%(start)s %(unit)s") % \
- {'start': timeLabel[0], 'unit': timeLabel[2]}
-
+ {'start': timeLabel[0], 'unit': timeLabel[2]}
+
decImage = RenderText(text, decoration['font']).ConvertToImage()
elif decoration['name'] == 'text':
text = decoration['text']
@@ -552,42 +531,17 @@
writeIms(filename=filename, images=pilImages)
elif exportInfo['method'] == 'gif':
writeGif(filename=exportInfo['file'], images=pilImages,
- duration=self.timeTick / float(1000), repeat=True)
+ duration=self.timeTick / float(1000), repeat=True)
elif exportInfo['method'] == 'swf':
writeSwf(filename=exportInfo['file'], images=pilImages,
- duration=self.timeTick / float(1000), repeat=True)
+ duration=self.timeTick / float(1000), repeat=True)
elif exportInfo['method'] == 'avi':
writeAvi(filename=exportInfo['file'], images=pilImages,
- duration=self.timeTick / float(1000),
- encoding=exportInfo['encoding'],
- inputOptions=exportInfo['options'])
+ duration=self.timeTick / float(1000),
+ encoding=exportInfo['encoding'],
+ inputOptions=exportInfo['options'])
except Exception, e:
del busy
GError(parent=self.frame, message=str(e))
return
del busy
-
-#def test():
-# import grass.script as grass
-# import wx
-# app = wx.PySimpleApp()
-# wx.InitAllImageHandlers()
-# # app.MainLoop()
-#
-# bitmaps = {}
-# rasters = ['elevation.dem']
-# # rasters = ['streams']
-# # rasters = grass.read_command("g.mlist", type = 'rast', fs = ',', quiet = True).strip().split(',')
-#
-# # print nrows, ncols
-# size = (300,100)
-# newSize, scale = ComputeScale(size)
-# # print scale
-# LoadRasters(rasters = rasters, bitmaps = bitmaps, scale = scale, size = newSize)
-#
-# for b in bitmaps.keys():
-# bitmaps[b].SaveFile('/home/anna/testy/ctypes/' + b + '.png', wx.BITMAP_TYPE_PNG)
-#
-#if __name__ == '__main__':
-#
-# test()
Added: grass/trunk/gui/wxpython/animation/data.py
===================================================================
--- grass/trunk/gui/wxpython/animation/data.py (rev 0)
+++ grass/trunk/gui/wxpython/animation/data.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -0,0 +1,219 @@
+# -*- coding: utf-8 -*-
+"""!
+ at package animation.data
+
+ at brief animation data structures
+
+Classes:
+ - data::AnimationData
+ - data::AnimationLayer
+
+
+(C) 2013 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Anna Petrasova <kratochanna gmail.com>
+"""
+import os
+
+from grass.script import core as gcore
+
+from core.utils import _
+from core.gcmd import GException
+from animation.nviztask import NvizTask
+from animation.utils import validateMapNames, getRegisteredMaps, \
+ checkSeriesCompatibility, validateTimeseriesName
+from core.layerlist import LayerList, Layer
+import grass.temporal as tgis
+
+
+class AnimationData(object):
+ def __init__(self):
+ self._name = None
+ self._windowIndex = 0
+ self._layerList = None
+ # only this stds is taken into account for time computations
+ # if there are any stds at all
+ self._firstStdsNameType = None
+ self._mapCount = None
+ self._cmdMatrix = None
+ self._viewModes = [('2d', _("2D view")),
+ ('3d', _("3D view"))]
+ self.viewMode = '2d'
+
+ self.nvizTask = NvizTask()
+ self._nvizParameters = self.nvizTask.ListMapParameters()
+ self.nvizParameter = self._nvizParameters[0]
+
+ self.workspaceFile = None
+ self.legendCmd = None
+
+ def GetName(self):
+ return self._name
+
+ def SetName(self, name):
+ if name == '':
+ raise ValueError(_("No animation name selected."))
+ self._name = name
+
+ name = property(fget=GetName, fset=SetName)
+
+ def GetWindowIndex(self):
+ return self._windowIndex
+
+ def SetWindowIndex(self, windowIndex):
+ self._windowIndex = windowIndex
+
+ windowIndex = property(fget=GetWindowIndex, fset=SetWindowIndex)
+
+ def SetLayerList(self, layerList):
+ """!
+ Throws GException if layer list's combination of stds is not valid.
+ """
+ mapSeriesList = []
+ timeseriesList = []
+ for layer in layerList:
+ if layer.active and hasattr(layer, 'maps'):
+ if layer.mapType in ('strds', 'stvds'):
+ timeseriesList.append((layer.name, layer.mapType))
+ self._firstStdsNameType = layer.name, layer.mapType
+ else:
+ mapSeriesList.append((layer.maps))
+ if not timeseriesList:
+ self._firstStdsNameType = None, None
+ # this throws GException
+ count = checkSeriesCompatibility(mapSeriesList=mapSeriesList,
+ timeseriesList=timeseriesList)
+ self._mapCount = count
+ self._layerList = layerList
+
+ def GetLayerList(self):
+ return self._layerList
+
+ layerList = property(fget=GetLayerList, fset=SetLayerList)
+
+ def GetFirstStdsNameType(self):
+ return self._firstStdsNameType
+
+ firstStdsNameType = property(fget=GetFirstStdsNameType)
+
+ def GetMapCount(self):
+ return self._mapCount
+
+ mapCount = property(fget=GetMapCount)
+
+ def GetCmdMatrix(self):
+ return self._cmdMatrix
+
+ def SetCmdMatrix(self, cmdMatrix):
+ self._cmdMatrix = cmdMatrix
+
+ cmdMatrix = property(fget=GetCmdMatrix, fset=SetCmdMatrix)
+
+ def GetWorkspaceFile(self):
+ return self._workspaceFile
+
+ def SetWorkspaceFile(self, fileName):
+ if fileName is None:
+ self._workspaceFile = None
+ return
+
+ if fileName == '':
+ raise ValueError(_("No workspace file selected."))
+
+ if not os.path.exists(fileName):
+ raise IOError(_("File %s not found") % fileName)
+ self._workspaceFile = fileName
+
+ self.nvizTask.Load(self.workspaceFile)
+
+ workspaceFile = property(fget=GetWorkspaceFile, fset=SetWorkspaceFile)
+
+ def SetDefaultValues(self, windowIndex, animationIndex):
+ self.windowIndex = windowIndex
+ self.name = _("Animation %d") % (animationIndex + 1)
+ self.layerList = LayerList()
+
+ def GetNvizParameters(self):
+ return self._nvizParameters
+
+ nvizParameters = property(fget=GetNvizParameters)
+
+ def GetNvizParameter(self):
+ return self._nvizParameter
+
+ def SetNvizParameter(self, param):
+ self._nvizParameter = param
+
+ nvizParameter = property(fget=GetNvizParameter, fset=SetNvizParameter)
+
+ def GetViewMode(self):
+ return self._viewMode
+
+ def SetViewMode(self, mode):
+ self._viewMode = mode
+
+ viewMode = property(fget=GetViewMode, fset=SetViewMode)
+
+ def GetViewModes(self):
+ 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._layerList:
+ return []
+
+ cmds = self.nvizTask.GetCommandSeries(layerList=self._layerList,
+ paramName=self.nvizParameter)
+ region = self.nvizTask.GetRegion()
+
+ return {'commands': cmds, 'region': region}
+
+ def __repr__(self):
+ return "%s(%r)" % (self.__class__, self.__dict__)
+
+
+class AnimLayer(Layer):
+ """!Animation layer allows to add either space-time dataset
+ or series of maps."""
+ def __init__(self):
+ Layer.__init__(self)
+ self._mapTypes.extend(['strds', 'stvds'])
+ self._maps = []
+ tgis.init()
+
+ def SetName(self, name):
+ if not self.hidden:
+ if self._mapType is None:
+ raise ValueError("To set layer name, the type of layer must be specified.")
+ if self._mapType in ('strds', 'stvds'):
+ try:
+ name = validateTimeseriesName(name, self._mapType)
+ self._maps = getRegisteredMaps(name, self._mapType)
+ except (GException, gcore.ScriptError), e:
+ raise ValueError(str(e))
+ else:
+ self._maps = validateMapNames(name.split(','), self._internalTypes[self._mapType])
+ self._name = name
+ self.label = name
+
+ def GetName(self):
+ return self._name
+
+ name = property(fget=GetName, fset=SetName)
+
+ def GetMaps(self):
+ return self._maps
+
+ maps = property(fget=GetMaps)
Property changes on: grass/trunk/gui/wxpython/animation/data.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Modified: grass/trunk/gui/wxpython/animation/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/animation/dialogs.py 2013-11-30 19:48:36 UTC (rev 58342)
+++ grass/trunk/gui/wxpython/animation/dialogs.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -7,16 +7,17 @@
- dialogs::SpeedDialog
- dialogs::InputDialog
- dialogs::EditDialog
- - dialogs::AnimationData
- dialogs::ExportDialog
+ - dialogs::AnimSimpleLayerManager
+ - dialogs::AddTemporalLayerDialog
-(C) 2012 by the GRASS Development Team
+(C) 2013 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
- at author Anna Kratochvilova <kratochanna gmail.com>
+ at author Anna Petrasova <kratochanna gmail.com>
"""
import os
import sys
@@ -30,25 +31,28 @@
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 gui_core.gselect import Select
-from utils import TemporalMode, getRegisteredMaps, validateTimeseriesName, validateMapNames
-from nviztask import NvizTask
+from animation.utils import TemporalMode, getRegisteredMaps
+from animation.data import AnimationData, AnimLayer
+from animation.toolbars import AnimSimpleLmgrToolbar, SIMPLE_LMGR_STDS
+from gui_core.simplelmgr import SimpleLayerManager, \
+ SIMPLE_LMGR_RASTER, SIMPLE_LMGR_VECTOR, SIMPLE_LMGR_TB_TOP
from grass.pydispatch.signal import Signal
import grass.script.core as gcore
class SpeedDialog(wx.Dialog):
- def __init__(self, parent, title = _("Adjust speed of animation"),
- temporalMode = None, minimumDuration = 20, timeGranularity = None,
- initialSpeed = 200):#, framesCount = None
- wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title,
- style = wx.DEFAULT_DIALOG_STYLE)
+ def __init__(self, parent, title=_("Adjust speed of animation"),
+ temporalMode=None, minimumDuration=20, timeGranularity=None,
+ initialSpeed=200):
+ wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=title,
+ style=wx.DEFAULT_DIALOG_STYLE)
# signal emitted when speed has changed; has attribute 'ms'
self.speedChanged = Signal('SpeedDialog.speedChanged')
self.minimumDuration = minimumDuration
@@ -71,7 +75,7 @@
def GetTimeGranularity(self):
return self._timeGranularity
- timeGranularity = property(fset = SetTimeGranularity, fget = GetTimeGranularity)
+ timeGranularity = property(fset=SetTimeGranularity, fget=GetTimeGranularity)
def SetTemporalMode(self, mode):
self._temporalMode = mode
@@ -80,7 +84,7 @@
def GetTemporalMode(self):
return self._temporalMode
- temporalMode = property(fset = SetTemporalMode, fget = GetTemporalMode)
+ temporalMode = property(fset=SetTemporalMode, fget=GetTemporalMode)
def _layout(self):
"""!Layout window"""
@@ -88,53 +92,53 @@
#
# simple mode
#
- self.nontemporalBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
- label = ' %s ' % _("Simple mode"))
+ self.nontemporalBox = wx.StaticBox(parent=self, id=wx.ID_ANY,
+ label=' %s ' % _("Simple mode"))
box = wx.StaticBoxSizer(self.nontemporalBox, wx.VERTICAL)
- gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+ gridSizer = wx.GridBagSizer(hgap=5, vgap=5)
- labelDuration = wx.StaticText(self, id = wx.ID_ANY, label = _("Frame duration:"))
- labelUnits = wx.StaticText(self, id = wx.ID_ANY, label = _("ms"))
- self.spinDuration = wx.SpinCtrl(self, id = wx.ID_ANY, min = self.minimumDuration,
- max = 10000, initial = self.defaultSpeed)
+ labelDuration = wx.StaticText(self, id=wx.ID_ANY, label=_("Frame duration:"))
+ labelUnits = wx.StaticText(self, id=wx.ID_ANY, label=_("ms"))
+ self.spinDuration = wx.SpinCtrl(self, id=wx.ID_ANY, min=self.minimumDuration,
+ max=10000, initial=self.defaultSpeed)
# TODO total time
- gridSizer.Add(item = labelDuration, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
- gridSizer.Add(item = self.spinDuration, pos = (0, 1), flag = wx.ALIGN_CENTER)
- gridSizer.Add(item = labelUnits, pos = (0, 2), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+ gridSizer.Add(item=labelDuration, pos=(0, 0), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+ gridSizer.Add(item=self.spinDuration, pos=(0, 1), flag = wx.ALIGN_CENTER)
+ gridSizer.Add(item=labelUnits, pos=(0, 2), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
gridSizer.AddGrowableCol(0)
- box.Add(item = gridSizer, proportion = 1, border = 5, flag = wx.ALL | wx.EXPAND)
+ box.Add(item=gridSizer, proportion=1, border=5, flag=wx.ALL | wx.EXPAND)
self.nontemporalSizer = gridSizer
- mainSizer.Add(item = box, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5)
+ mainSizer.Add(item=box, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
#
# temporal mode
#
- self.temporalBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
- label = ' %s ' % _("Temporal mode"))
+ self.temporalBox = wx.StaticBox(parent=self, id=wx.ID_ANY,
+ label=' %s ' % _("Temporal mode"))
box = wx.StaticBoxSizer(self.temporalBox, wx.VERTICAL)
- gridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+ gridSizer = wx.GridBagSizer(hgap=5, vgap=5)
- labelTimeUnit = wx.StaticText(self, id = wx.ID_ANY, label = _("Time unit:"))
- labelDuration = wx.StaticText(self, id = wx.ID_ANY, label = _("Duration of time unit:"))
- labelUnits = wx.StaticText(self, id = wx.ID_ANY, label = _("ms"))
- self.spinDurationTemp = wx.SpinCtrl(self, id = wx.ID_ANY, min = self.minimumDuration,
- max = 10000, initial = self.defaultSpeed)
- self.choiceUnits = wx.Choice(self, id = wx.ID_ANY)
+ labelTimeUnit = wx.StaticText(self, id=wx.ID_ANY, label=_("Time unit:"))
+ labelDuration = wx.StaticText(self, id=wx.ID_ANY, label=_("Duration of time unit:"))
+ labelUnits = wx.StaticText(self, id=wx.ID_ANY, label=_("ms"))
+ self.spinDurationTemp = wx.SpinCtrl(self, id=wx.ID_ANY, min=self.minimumDuration,
+ max=10000, initial=self.defaultSpeed)
+ self.choiceUnits = wx.Choice(self, id=wx.ID_ANY)
# TODO total time
- gridSizer.Add(item = labelTimeUnit, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
- gridSizer.Add(item = self.choiceUnits, pos = (0, 1), flag = wx.ALIGN_CENTER | wx.EXPAND)
- gridSizer.Add(item = labelDuration, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
- gridSizer.Add(item = self.spinDurationTemp, pos = (1, 1), flag = wx.ALIGN_CENTER | wx.EXPAND)
- gridSizer.Add(item = labelUnits, pos = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+ gridSizer.Add(item=labelTimeUnit, pos=(0, 0), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+ gridSizer.Add(item=self.choiceUnits, pos=(0, 1), flag = wx.ALIGN_CENTER | wx.EXPAND)
+ gridSizer.Add(item=labelDuration, pos=(1, 0), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+ gridSizer.Add(item=self.spinDurationTemp, pos=(1, 1), flag = wx.ALIGN_CENTER | wx.EXPAND)
+ gridSizer.Add(item=labelUnits, pos=(1, 2), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
gridSizer.AddGrowableCol(1)
self.temporalSizer = gridSizer
- box.Add(item = gridSizer, proportion = 1, border = 5, flag = wx.ALL | wx.EXPAND)
- mainSizer.Add(item = box, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5)
-
+ box.Add(item=gridSizer, proportion=1, border=5, flag=wx.ALL | wx.EXPAND)
+ mainSizer.Add(item=box, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
+
self.btnOk = wx.Button(self, wx.ID_OK)
self.btnApply = wx.Button(self, wx.ID_APPLY)
self.btnCancel = wx.Button(self, wx.ID_CANCEL)
@@ -143,17 +147,17 @@
self.btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
self.btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
self.btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
- self.Bind(wx.EVT_CLOSE, self.OnCancel)
+ self.Bind(wx.EVT_CLOSE, self.OnCancel)
# button sizer
btnStdSizer = wx.StdDialogButtonSizer()
btnStdSizer.AddButton(self.btnOk)
btnStdSizer.AddButton(self.btnApply)
btnStdSizer.AddButton(self.btnCancel)
btnStdSizer.Realize()
-
- mainSizer.Add(item = btnStdSizer, proportion = 0,
- flag = wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border = 5)
+ mainSizer.Add(item=btnStdSizer, proportion=0,
+ flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=5)
+
self.SetSizer(mainSizer)
mainSizer.Fit(self)
@@ -199,12 +203,12 @@
if self.temporalMode == TemporalMode.TEMPORAL:
index = self.choiceUnits.GetSelection()
unit = self.choiceUnits.GetClientData(index)
- delta = self._timedelta(unit = unit, number = 1)
+ delta = self._timedelta(unit=unit, number=1)
seconds1 = self._total_seconds(delta)
number, unit = self.timeGranularity
number = float(number)
- delta = self._timedelta(unit = unit, number = number)
+ delta = self._timedelta(unit=unit, number=number)
seconds2 = self._total_seconds(delta)
value = timeTick
ms = value * seconds1 / float(seconds2)
@@ -219,39 +223,38 @@
elif self.temporalMode == TemporalMode.TEMPORAL:
index = self.choiceUnits.GetSelection()
unit = self.choiceUnits.GetClientData(index)
- delta = self._timedelta(unit = unit, number = 1)
+ delta = self._timedelta(unit=unit, number=1)
seconds1 = self._total_seconds(delta)
-
number, unit = self.timeGranularity
number = float(number)
- delta = self._timedelta(unit = unit, number = number)
+ delta = self._timedelta(unit=unit, number=number)
seconds2 = self._total_seconds(delta)
value = self.spinDurationTemp.GetValue()
ms = value * seconds2 / float(seconds1)
if ms < self.minimumDuration:
- GMessage(parent = self, message = _("Animation speed is too high."))
+ GMessage(parent=self, message=_("Animation speed is too high."))
return
self.lastAppliedValueTemp = self.spinDurationTemp.GetValue()
else:
return
- self.speedChanged.emit(ms = ms)
+ self.speedChanged.emit(ms=ms)
def _timedelta(self, unit, number):
if unit in "years":
- delta = datetime.timedelta(days = 365.25 * number)
+ delta = datetime.timedelta(days=365.25 * number)
elif unit in "months":
- delta = datetime.timedelta(days = 30.4375 * number) # 365.25/12
+ delta = datetime.timedelta(days=30.4375 * number) # 365.25/12
elif unit in "days":
- delta = datetime.timedelta(days = 1 * number)
+ delta = datetime.timedelta(days=1 * number)
elif unit in "hours":
- delta = datetime.timedelta(hours = 1 * number)
+ delta = datetime.timedelta(hours=1 * number)
elif unit in "minutes":
- delta = datetime.timedelta(minutes = 1 * number)
+ delta = datetime.timedelta(minutes=1 * number)
elif unit in "seconds":
- delta = datetime.timedelta(seconds = 1 * number)
+ delta = datetime.timedelta(seconds=1 * number)
return delta
@@ -263,8 +266,8 @@
class InputDialog(wx.Dialog):
def __init__(self, parent, mode, animationData):
- wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY,
- style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
+ wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY,
+ style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
if mode == 'add':
self.SetTitle(_("Add new animation"))
elif mode == 'edit':
@@ -274,49 +277,53 @@
self._tmpLegendCmd = None
self._layout()
- self.OnViewMode(event = None)
+ self.OnViewMode(event=None)
def _layout(self):
mainSizer = wx.BoxSizer(wx.VERTICAL)
- self.windowChoice = wx.Choice(self, id = wx.ID_ANY,
- choices = [_("top left"), _("top right"),
- _("bottom left"), _("bottom right")])
+ self.windowChoice = wx.Choice(self, 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(self, id=wx.ID_ANY, value=self.animationData.name)
- self.nDChoice = wx.Choice(self, id = wx.ID_ANY)
+ self.nDChoice = wx.Choice(self, id=wx.ID_ANY)
mode = self.animationData.viewMode
index = 0
for i, (viewMode, viewModeName) in enumerate(self.animationData.viewModes):
- self.nDChoice.Append(viewModeName, clientData = viewMode)
+ self.nDChoice.Append(viewModeName, clientData=viewMode)
if mode == viewMode:
index = i
self.nDChoice.SetSelection(index)
- # TODO
- self.nDChoice.SetToolTipString(_(""))
+ self.nDChoice.SetToolTipString(_("Select 2D or 3D view"))
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:")),
- 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:")),
- 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:")),
- flag = wx.ALIGN_CENTER_VERTICAL)
- gridSizer.Add(item = self.nDChoice, proportion = 1, flag = wx.ALIGN_RIGHT)
+ gridSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
+ gridSizer.Add(item=wx.StaticText(self, 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:")),
+ 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:")),
+ flag=wx.ALIGN_CENTER_VERTICAL)
+ gridSizer.Add(item=self.nDChoice, proportion=1, flag=wx.ALIGN_RIGHT)
gridSizer.AddGrowableCol(0, 1)
gridSizer.AddGrowableCol(1, 1)
- mainSizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
+ 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.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()
- mainSizer.Add(item = self.dataPanel, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 3)
- mainSizer.Add(item = self.threeDPanel, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 3)
+ 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)
@@ -328,166 +335,100 @@
btnStdSizer.AddButton(self.btnOk)
btnStdSizer.AddButton(self.btnCancel)
btnStdSizer.Realize()
-
- mainSizer.Add(item = btnStdSizer, proportion = 0,
- flag = wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border = 5)
+ mainSizer.Add(item=btnStdSizer, proportion=0,
+ flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=5)
+
self.SetSizer(mainSizer)
mainSizer.Fit(self)
def _createDataPanel(self):
- panel = wx.Panel(self, id = wx.ID_ANY)
- dataStBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
- label = ' %s ' % _("Data"))
- dataBoxSizer = wx.StaticBoxSizer(dataStBox, wx.VERTICAL)
+ panel = wx.Panel(self)
+ 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))
+ slmgrSizer.Add(self.simpleLmgr, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
- self.dataChoice = wx.Choice(panel, id = wx.ID_ANY)
- self._setMapTypes()
- self.dataChoice.Bind(wx.EVT_CHOICE, self.OnDataType)
-
- self.dataSelect = gselect.Select(parent = panel, id = wx.ID_ANY,
- size = globalvar.DIALOG_GSELECT_SIZE)
-
-
- iconTheme = UserSettings.Get(group = 'appearance', key = 'iconTheme', subkey = 'type')
- bitmapPath = os.path.join(globalvar.ETCICONDIR, iconTheme, 'layer-open.png')
- if os.path.isfile(bitmapPath) and os.path.getsize(bitmapPath):
- bitmap = wx.Bitmap(name = bitmapPath)
- else:
- bitmap = wx.ArtProvider.GetBitmap(id = wx.ART_MISSING_IMAGE, client = wx.ART_TOOLBAR)
- 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.legend.Bind(wx.EVT_CHECKBOX, self.OnLegend)
+ self.legendBtn.Bind(wx.EVT_BUTTON, self.OnLegendProperties)
- self.OnDataType(None)
- if self.animationData.inputData is None:
- self.dataSelect.SetValue('')
- else:
- self.dataSelect.SetValue(self.animationData.inputData)
-
hbox = wx.BoxSizer(wx.HORIZONTAL)
- hbox.Add(item = wx.StaticText(panel, wx.ID_ANY, label = _("Input data type:")),
- proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL)
- hbox.Add(item = self.dataChoice, proportion = 1, flag = wx.EXPAND)
- dataBoxSizer.Add(item = hbox, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 3)
-
- hbox = wx.BoxSizer(wx.HORIZONTAL)
- # hbox.Add(item = wx.StaticText(panel, wx.ID_ANY, label = _("Input data:")),
- # proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
- 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)
+ slmgrSizer.Add(item=hbox, proportion=0, flag=wx.EXPAND | wx.ALL, border=3)
- panel.SetSizerAndFit(dataBoxSizer)
+ panel.SetSizerAndFit(slmgrSizer)
panel.SetAutoLayout(True)
return panel
def _create3DPanel(self):
- panel = wx.Panel(self, id = wx.ID_ANY)
- dataStBox = wx.StaticBox(parent = panel, id = wx.ID_ANY,
- label = ' %s ' % _("3D view parameters"))
+ panel = wx.Panel(self, id=wx.ID_ANY)
+ dataStBox = wx.StaticBox(parent=panel, id=wx.ID_ANY,
+ label=' %s ' % _("3D view parameters"))
dataBoxSizer = wx.StaticBoxSizer(dataStBox, wx.VERTICAL)
# workspace file
- self.fileSelector = filebrowse.FileBrowseButton(parent = panel, id = wx.ID_ANY,
- size = globalvar.DIALOG_GSELECT_SIZE,
- labelText = _("Workspace file:"),
- dialogTitle = _("Choose workspace file to import 3D view parameters"),
- buttonText = _('Browse'),
- startDirectory = os.getcwd(), fileMode = 0,
- fileMask = "GRASS Workspace File (*.gxw)|*.gxw")
+ self.fileSelector = \
+ filebrowse.FileBrowseButton(parent=panel, id=wx.ID_ANY,
+ size=globalvar.DIALOG_GSELECT_SIZE,
+ labelText=_("Workspace file:"),
+ dialogTitle=_("Choose workspace file to "
+ "import 3D view parameters"),
+ buttonText=_('Browse'),
+ startDirectory=os.getcwd(), fileMode=0,
+ fileMask="GRASS Workspace File (*.gxw)|*.gxw")
if self.animationData.workspaceFile:
self.fileSelector.SetValue(self.animationData.workspaceFile)
- self.paramLabel = wx.StaticText(panel, wx.ID_ANY, label = _("Parameter for animation:"))
- self.paramChoice = wx.Choice(panel, id = wx.ID_ANY, choices = self.animationData.nvizParameters)
+ self.paramLabel = wx.StaticText(panel, wx.ID_ANY, label=_("Parameter for animation:"))
+ self.paramChoice = wx.Choice(panel, id=wx.ID_ANY, choices=self.animationData.nvizParameters)
self.paramChoice.SetStringSelection(self.animationData.nvizParameter)
hbox = wx.BoxSizer(wx.HORIZONTAL)
- hbox.Add(item = self.fileSelector, proportion = 1, flag = wx.EXPAND | wx.ALIGN_CENTER)
- dataBoxSizer.Add(item = hbox, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 3)
+ hbox.Add(item=self.fileSelector, proportion=1, flag=wx.EXPAND | wx.ALIGN_CENTER)
+ dataBoxSizer.Add(item=hbox, proportion=0, flag=wx.EXPAND | wx.ALL, border=3)
hbox = wx.BoxSizer(wx.HORIZONTAL)
- hbox.Add(item = self.paramLabel, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL)
- hbox.Add(item = self.paramChoice, proportion = 1, flag = wx.EXPAND)
- dataBoxSizer.Add(item = hbox, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 3)
-
+ hbox.Add(item=self.paramLabel, proportion=1, flag=wx.ALIGN_CENTER_VERTICAL)
+ hbox.Add(item=self.paramChoice, proportion=1, flag=wx.EXPAND)
+ dataBoxSizer.Add(item=hbox, proportion=0, flag=wx.EXPAND | wx.ALL, border=3)
+
panel.SetSizerAndFit(dataBoxSizer)
panel.SetAutoLayout(True)
return panel
- def _setMapTypes(self, view2d = True):
- index = 0
-
- inputTypes = self.animationData.inputMapTypes
- self.dataChoice.Clear()
- for i, (itype, itypeName) in enumerate(inputTypes):
- self.dataChoice.Append(itypeName, clientData = itype)
- if itype == self.animationData.inputMapType:
- index = i
- self.dataChoice.SetSelection(index)
-
def OnViewMode(self, event):
mode = self.nDChoice.GetSelection()
self.Freeze()
+ self.simpleLmgr.Activate3D(mode == 1)
+ self.warning3DLayers.Show(mode == 1)
sizer = self.threeDPanel.GetContainingSizer()
- sizer.Show(self.threeDPanel, mode != 0, True)
+ sizer.Show(self.threeDPanel, mode == 1, True)
sizer.Layout()
- self._setMapTypes(mode == 0)
self.Layout()
self.Fit()
self.Thaw()
- def OnDataType(self, event):
- etype = self.dataChoice.GetClientData(self.dataChoice.GetSelection())
- if etype in ('rast', 'vect'):
- self.dataSelect.SetType(etype = etype, multiple = True)
- self.addManyMapsButton.Enable(True)
- else:
- self.dataSelect.SetType(etype = etype, multiple = False)
- self.addManyMapsButton.Enable(False)
+ def OnLegend(self, event):
+ if not self.legend.IsChecked():
+ return
+ if self._tmpLegendCmd or self.animationData.legendCmd:
+ return
+ cmd = ['d.legend', 'at=5,50,2,5']
+ GUI(parent=self, modal=True).ParseCommand(cmd=cmd,
+ completed=(self.GetOptData, '', ''))
- self.legend.Enable(etype in ('rast', 'strds'))
- self.legendBtn.Enable(etype in ('rast', 'strds'))
-
- self.dataSelect.SetValue('')
-
- def OnAddMaps(self, event):
- # TODO: fix dialog
- etype = self.dataChoice.GetClientData(self.dataChoice.GetSelection())
- index = 0
- if etype == 'vect':
- index = 2
-
- dlg = MapLayersDialog(self, title = _("Select raster maps for animation"))
- dlg.applyAddingMapLayers.connect(lambda mapLayers:
- self.dataSelect.SetValue(','.join(mapLayers)))
- dlg.layerType.SetSelection(index)
- dlg.LoadMapLayers(dlg.GetLayerType(cmd = True),
- dlg.mapset.GetStringSelection())
- if dlg.ShowModal() == wx.ID_OK:
- self.dataSelect.SetValue(','.join(dlg.GetMapLayers()))
-
- dlg.Destroy()
-
- def OnLegend(self, event):
+ def OnLegendProperties(self, event):
"""!Set options for legend"""
if self._tmpLegendCmd:
- cmd = self._tmpLegendCmd
+ cmd = self._tmpLegendCmd
elif self.animationData.legendCmd:
cmd = self.animationData.legendCmd
else:
@@ -500,47 +441,39 @@
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:
+ self._tmpLegendCmd = dcmd
- if dcmd and not self.legend.IsChecked():
- self.legend.SetValue(True)
+ if not self.legend.IsChecked():
+ self.legend.SetValue(True)
+ else:
+ if not self._tmpLegendCmd and not self.animationData.legendCmd:
+ self.legend.SetValue(False)
def _update(self):
+ if self.nDChoice.GetSelection() == 1 and len(self._layerList) > 1:
+ raise GException(_("Only one series or space-time "
+ "dataset is accepted for 3D mode."))
+ hasSeries = False
+ for layer in self._layerList:
+ if layer.active and hasattr(layer, 'maps'):
+ hasSeries = True
+ break
+ if not hasSeries:
+ raise GException(_("No map series or space-time dataset added."))
+
+ self.animationData.layerList = self._layerList
self.animationData.name = self.nameCtrl.GetValue()
self.animationData.windowIndex = self.windowChoice.GetSelection()
- sel = self.dataChoice.GetSelection()
- self.animationData.inputMapType = self.dataChoice.GetClientData(sel)
- self.animationData.inputData = self.dataSelect.GetValue()
sel = self.nDChoice.GetSelection()
self.animationData.viewMode = self.nDChoice.GetClientData(sel)
self.animationData.legendCmd = None
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()
@@ -552,13 +485,13 @@
self._update()
self.EndModal(wx.ID_OK)
except (GException, ValueError, IOError) as e:
- GError(message = str(e), showTraceback = False, caption = _("Invalid input"))
+ GError(message=str(e), showTraceback=False, caption=_("Invalid input"))
class EditDialog(wx.Dialog):
def __init__(self, parent, evalFunction, animationData, maxAnimations):
- wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY,
- style = wx.DEFAULT_DIALOG_STYLE)
+ wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY,
+ style=wx.DEFAULT_DIALOG_STYLE)
self.animationData = copy.deepcopy(animationData)
self.eval = evalFunction
self.SetTitle(_("Add, edit or remove animations"))
@@ -569,32 +502,36 @@
def _layout(self):
mainSizer = wx.BoxSizer(wx.VERTICAL)
- box = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("List of animations"))
+ box = wx.StaticBox (parent=self, id=wx.ID_ANY, label=" %s " % _("List of animations"))
sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
- gridBagSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
+ gridBagSizer = wx.GridBagSizer (hgap=5, vgap=5)
gridBagSizer.AddGrowableCol(0)
# gridBagSizer.AddGrowableCol(1,1)
-
- self.listbox = wx.ListBox(self, id = wx.ID_ANY, choices = [], style = wx.LB_SINGLE|wx.LB_NEEDED_SB)
+
+ self.listbox = wx.ListBox(self, id=wx.ID_ANY, choices=[], style=wx.LB_SINGLE | wx.LB_NEEDED_SB)
self.listbox.Bind(wx.EVT_LISTBOX_DCLICK, self.OnEdit)
- self.addButton = wx.Button(self, id = wx.ID_ANY, label = _("Add"))
+ self.addButton = wx.Button(self, id=wx.ID_ANY, label=_("Add"))
self.addButton.Bind(wx.EVT_BUTTON, self.OnAdd)
- self.editButton = wx.Button(self, id = wx.ID_ANY, label = _("Edit"))
+ self.editButton = wx.Button(self, id=wx.ID_ANY, label=_("Edit"))
self.editButton.Bind(wx.EVT_BUTTON, self.OnEdit)
- self.removeButton = wx.Button(self, id = wx.ID_ANY, label = _("Remove"))
+ self.removeButton = wx.Button(self, id=wx.ID_ANY, label=_("Remove"))
self.removeButton.Bind(wx.EVT_BUTTON, self.OnRemove)
-
+
self._updateListBox()
-
- gridBagSizer.Add(self.listbox, pos = (0,0), span = (3, 1), flag = wx.ALIGN_CENTER_VERTICAL| wx.EXPAND, border = 0)
- gridBagSizer.Add(self.addButton, pos = (0,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
- gridBagSizer.Add(self.editButton, pos = (1,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
- gridBagSizer.Add(self.removeButton, pos = (2,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
- sizer.Add(gridBagSizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
- mainSizer.Add(item = sizer, proportion = 0,
- flag = wx.EXPAND | wx.ALL, border = 5)
+ gridBagSizer.Add(self.listbox, pos=(0, 0), span = (3, 1),
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, border=0)
+ gridBagSizer.Add(self.addButton, pos=(0, 1),
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, border=0)
+ gridBagSizer.Add(self.editButton, pos=(1, 1),
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, border=0)
+ gridBagSizer.Add(self.removeButton, pos=(2, 1),
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, border=0)
+ sizer.Add(gridBagSizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=5)
+ mainSizer.Add(item=sizer, proportion=0,
+ flag=wx.EXPAND | wx.ALL, border=5)
+
# buttons
self.btnOk = wx.Button(self, wx.ID_OK)
self.btnCancel = wx.Button(self, wx.ID_CANCEL)
@@ -605,17 +542,17 @@
btnStdSizer.AddButton(self.btnOk)
btnStdSizer.AddButton(self.btnCancel)
btnStdSizer.Realize()
-
- mainSizer.Add(item = btnStdSizer, proportion = 0,
- flag = wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border = 5)
+ mainSizer.Add(item=btnStdSizer, proportion=0,
+ flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=5)
+
self.SetSizer(mainSizer)
mainSizer.Fit(self)
def _updateListBox(self):
self.listbox.Clear()
for anim in self.animationData:
- self.listbox.Append(anim.name, clientData = anim)
+ self.listbox.Append(anim.name, clientData=anim)
if self.animationData:
self.listbox.SetSelection(0)
@@ -629,29 +566,28 @@
def OnAdd(self, event):
windowIndex = self._getNextIndex()
if windowIndex is None:
- GMessage(self, message = _("Maximum number of animations is %d.") % self.maxAnimations)
+ GMessage(self, message=_("Maximum number of animations is %d.") % self.maxAnimations)
return
animData = AnimationData()
# number of active animations
animationIndex = len(self.animationData)
animData.SetDefaultValues(windowIndex, animationIndex)
- dlg = InputDialog(parent = self, mode = 'add', animationData = animData)
+ dlg = InputDialog(parent=self, mode='add', animationData=animData)
if dlg.ShowModal() == wx.ID_CANCEL:
dlg.Destroy()
return
dlg.Destroy()
self.animationData.append(animData)
-
+
self._updateListBox()
-
def OnEdit(self, event):
index = self.listbox.GetSelection()
if index == wx.NOT_FOUND:
return
animData = self.listbox.GetClientData(index)
- dlg = InputDialog(parent = self, mode = 'edit', animationData = animData)
+ dlg = InputDialog(parent=self, mode='edit', animationData=animData)
if dlg.ShowModal() == wx.ID_CANCEL:
dlg.Destroy()
return
@@ -666,7 +602,7 @@
animData = self.listbox.GetClientData(index)
self.animationData.remove(animData)
-
+
self._updateListBox()
def GetResult(self):
@@ -675,182 +611,23 @@
def OnOk(self, event):
indices = set([anim.windowIndex for anim in self.animationData])
if len(indices) != len(self.animationData):
- GError(parent = self, message = _("More animations are using one window."
- " Please select different window for each animation."))
+ GError(parent=self, message=_("More animations are using one window."
+ " Please select different window for each animation."))
return
try:
temporalMode, tempManager = self.eval(self.animationData)
except GException, e:
- GError(parent = self, message = e.value, showTraceback = False)
+ GError(parent=self, message=e.value, showTraceback=False)
return
self.result = (self.animationData, temporalMode, tempManager)
self.EndModal(wx.ID_OK)
-class AnimationData(object):
- def __init__(self):
- self._inputMapTypes = [('rast', _("Multiple raster maps")),
- ('vect', _("Multiple vector maps")),
- ('strds', _("Space time raster dataset")),
- ('stvds', _("Space time vector dataset"))]
- self._inputMapType = 'rast'
- self.inputData = None
- self.mapData = None
- self._viewModes = [('2d', _("2D view")),
- ('3d', _("3D view"))]
- self.viewMode = '2d'
-
- self.nvizTask = NvizTask()
- self._nvizParameters = self.nvizTask.ListMapParameters()
- self.nvizParameter = self._nvizParameters[0]
-
- self.workspaceFile = None
- self.legendCmd = None
-
- def GetName(self):
- return self._name
-
- def SetName(self, name):
- if name == '':
- raise ValueError(_("No animation name selected."))
- self._name = name
-
- name = property(fget = GetName, fset = SetName)
-
- def GetWindowIndex(self):
- return self._windowIndex
-
- def SetWindowIndex(self, windowIndex):
- self._windowIndex = windowIndex
-
- windowIndex = property(fget = GetWindowIndex, fset = SetWindowIndex)
-
- def GetInputMapTypes(self):
- return self._inputMapTypes
-
- inputMapTypes = property(fget = GetInputMapTypes)
-
- def GetInputMapType(self):
- return self._inputMapType
-
- def SetInputMapType(self, itype):
- if itype in [each[0] for each in self.inputMapTypes]:
- self._inputMapType = itype
- else:
- raise ValueError("Bad input type.")
-
- inputMapType = property(fget = GetInputMapType, fset = SetInputMapType)
-
- def GetInputData(self):
- return self._inputData
-
- def SetInputData(self, data):
- if data == '':
- raise ValueError(_("No data selected."))
- if data is None:
- self._inputData = data
- return
-
- if self.inputMapType in ('rast', 'vect'):
- maps = data.split(',')
- newNames = validateMapNames(maps, self.inputMapType)
- self._inputData = ','.join(newNames)
- self.mapData = newNames
-
- elif self.inputMapType in ('strds', 'stvds'):
- timeseries = validateTimeseriesName(data, etype=self.inputMapType)
- timeseriesMaps = getRegisteredMaps(timeseries, self.inputMapType)
- self._inputData = timeseries
- self.mapData = timeseriesMaps
- else:
- self._inputData = data
-
- inputData = property(fget = GetInputData, fset = SetInputData)
-
- def SetMapData(self, data):
- self._mapData = data
-
- def GetMapData(self):
- return self._mapData
-
- mapData = property(fget = GetMapData, fset = SetMapData)
-
- def GetWorkspaceFile(self):
- return self._workspaceFile
-
- def SetWorkspaceFile(self, fileName):
- if fileName is None:
- self._workspaceFile = None
- return
-
- if fileName == '':
- raise ValueError(_("No workspace file selected."))
-
- if not os.path.exists(fileName):
- raise IOError(_("File %s not found") % fileName)
- self._workspaceFile = fileName
-
- self.nvizTask.Load(self.workspaceFile)
-
- workspaceFile = property(fget = GetWorkspaceFile, fset = SetWorkspaceFile)
-
- def SetDefaultValues(self, windowIndex, animationIndex):
- self.windowIndex = windowIndex
- self.name = _("Animation %d") % (animationIndex + 1)
-
- def GetNvizParameters(self):
- return self._nvizParameters
-
- nvizParameters = property(fget = GetNvizParameters)
-
- def GetNvizParameter(self):
- return self._nvizParameter
-
- def SetNvizParameter(self, param):
- self._nvizParameter = param
-
- nvizParameter = property(fget = GetNvizParameter, fset = SetNvizParameter)
-
- def GetViewMode(self):
- return self._viewMode
-
- def SetViewMode(self, mode):
- self._viewMode = mode
-
- viewMode = property(fget = GetViewMode, fset = SetViewMode)
-
- def GetViewModes(self):
- 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 []
-
- cmds = self.nvizTask.GetCommandSeries(series = self.mapData, paramName = self.nvizParameter)
- region = self.nvizTask.GetRegion()
-
- return {'commands': cmds, 'region': region}
-
- def __repr__(self):
- return "%s(%r)" % (self.__class__, self.__dict__)
-
-
-
class ExportDialog(wx.Dialog):
def __init__(self, parent, temporal, timeTick):
- wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = _("Export animation"),
- style = wx.DEFAULT_DIALOG_STYLE)
+ wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=_("Export animation"),
+ style=wx.DEFAULT_DIALOG_STYLE)
self.decorations = []
self.temporal = temporal
@@ -863,15 +640,14 @@
wx.CallAfter(self._hideAll)
def _layout(self):
- notebook = wx.Notebook(self, id = wx.ID_ANY)
+ notebook = wx.Notebook(self, id=wx.ID_ANY)
mainSizer = wx.BoxSizer(wx.VERTICAL)
- notebook.AddPage(page = self._createExportFormatPanel(notebook), text = _("Format"))
- notebook.AddPage(page = self._createDecorationsPanel(notebook), text = _("Decorations"))
- mainSizer.Add(item = notebook, proportion = 0,
- flag = wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border = 5)
+ notebook.AddPage(page=self._createExportFormatPanel(notebook), text=_("Format"))
+ notebook.AddPage(page=self._createDecorationsPanel(notebook), text=_("Decorations"))
+ mainSizer.Add(item=notebook, proportion=0,
+ flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=5)
-
self.btnExport = wx.Button(self, wx.ID_OK)
self.btnExport.SetLabel(_("Export"))
self.btnCancel = wx.Button(self, wx.ID_CANCEL)
@@ -884,9 +660,9 @@
btnStdSizer.AddButton(self.btnExport)
btnStdSizer.AddButton(self.btnCancel)
btnStdSizer.Realize()
-
- mainSizer.Add(item = btnStdSizer, proportion = 0,
- flag = wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border = 5)
+
+ mainSizer.Add(item=btnStdSizer, proportion=0,
+ flag=wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border=5)
self.SetSizer(mainSizer)
# set the longest option to fit
@@ -898,24 +674,25 @@
mainSizer.Fit(self)
def _createDecorationsPanel(self, notebook):
- panel = wx.Panel(notebook, id = wx.ID_ANY)
+ panel = wx.Panel(notebook, id=wx.ID_ANY)
sizer = wx.BoxSizer(wx.VERTICAL)
- sizer.Add(self._createDecorationsList(panel), proportion = 0, flag = wx.ALL | wx.EXPAND, border = 10)
- sizer.Add(self._createDecorationsProperties(panel), proportion = 0, flag = wx.ALL | wx.EXPAND, border = 10)
+ sizer.Add(self._createDecorationsList(panel), proportion=0, flag=wx.ALL | wx.EXPAND, border=10)
+ sizer.Add(self._createDecorationsProperties(panel), proportion=0, flag=wx.ALL | wx.EXPAND, border=10)
panel.SetSizer(sizer)
sizer.Fit(panel)
return panel
def _createDecorationsList(self, panel):
- gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+ gridBagSizer = wx.GridBagSizer(hgap=5, vgap=5)
gridBagSizer.AddGrowableCol(0)
-
- self.listbox = wx.ListBox(panel, id = wx.ID_ANY, choices = [], style = wx.LB_SINGLE|wx.LB_NEEDED_SB)
+
+ self.listbox = wx.ListBox(panel, id=wx.ID_ANY, choices=[],
+ style=wx.LB_SINGLE | wx.LB_NEEDED_SB)
self.listbox.Bind(wx.EVT_LISTBOX, self.OnSelectionChanged)
- gridBagSizer.Add(self.listbox, pos = (0, 0), span = (4, 1),
- flag = wx.ALIGN_CENTER_VERTICAL| wx.EXPAND, border = 0)
+ gridBagSizer.Add(self.listbox, pos=(0, 0), span=(4, 1),
+ flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, border=0)
buttonNames = ['time', 'image', 'text']
buttonLabels = [_("Add time stamp"), _("Add image"), _("Add text")]
@@ -923,14 +700,14 @@
for buttonName, buttonLabel in zip(buttonNames, buttonLabels):
if buttonName == 'time' and self.temporal == TemporalMode.NONTEMPORAL:
continue
- btn = wx.Button(panel, id = wx.ID_ANY, name = buttonName, label = buttonLabel)
- btn.Bind(wx.EVT_BUTTON, lambda evt, temp = buttonName: self.OnAddDecoration(evt, temp))
- gridBagSizer.Add(btn, pos = (i ,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+ btn = wx.Button(panel, id=wx.ID_ANY, name=buttonName, label=buttonLabel)
+ btn.Bind(wx.EVT_BUTTON, lambda evt, temp=buttonName: self.OnAddDecoration(evt, temp))
+ gridBagSizer.Add(btn, pos=(i, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, border=0)
i += 1
- removeButton = wx.Button(panel, id = wx.ID_ANY, label = _("Remove"))
+ removeButton = wx.Button(panel, id=wx.ID_ANY, label=_("Remove"))
removeButton.Bind(wx.EVT_BUTTON, self.OnRemove)
- gridBagSizer.Add(removeButton, pos = (i, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
-
+ gridBagSizer.Add(removeButton, pos=(i, 1), flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, border=0)
+
return gridBagSizer
def _createDecorationsProperties(self, panel):
@@ -942,177 +719,177 @@
else:
label = _("Add image or text decoration by one of the buttons above.")
- label = wx.StaticText(panel, id = wx.ID_ANY, label = label)
+ label = wx.StaticText(panel, id=wx.ID_ANY, label=label)
label.Wrap(400)
- self.informBox.Add(label, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border = 5)
- self.hidevbox.Add(self.informBox, proportion = 0, flag = wx.EXPAND | wx.BOTTOM, border = 5)
-
+ self.informBox.Add(label, proportion=1, flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border=5)
+ self.hidevbox.Add(self.informBox, proportion=0, flag=wx.EXPAND | wx.BOTTOM, border=5)
+
# font
self.fontBox = wx.BoxSizer(wx.HORIZONTAL)
- self.fontBox.Add(wx.StaticText(panel, id = wx.ID_ANY, label = _("Font settings:")),
- proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border = 5)
- self.sampleLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Sample text"))
- self.fontBox.Add(self.sampleLabel, proportion = 1,
- flag = wx.ALIGN_CENTER | wx.RIGHT | wx.LEFT, border = 5)
- fontButton = wx.Button(panel, id = wx.ID_ANY, label = _("Set font"))
+ self.fontBox.Add(wx.StaticText(panel, id=wx.ID_ANY, label=_("Font settings:")),
+ proportion=0, flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border=5)
+ self.sampleLabel = wx.StaticText(panel, id=wx.ID_ANY, label=_("Sample text"))
+ self.fontBox.Add(self.sampleLabel, proportion=1,
+ flag=wx.ALIGN_CENTER | wx.RIGHT | wx.LEFT, border=5)
+ fontButton = wx.Button(panel, id=wx.ID_ANY, label=_("Set font"))
fontButton.Bind(wx.EVT_BUTTON, self.OnFont)
- self.fontBox.Add(fontButton, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
- self.hidevbox.Add(self.fontBox, proportion = 0, flag = wx.EXPAND | wx.BOTTOM, border = 5)
+ self.fontBox.Add(fontButton, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL)
+ self.hidevbox.Add(self.fontBox, proportion=0, flag=wx.EXPAND | wx.BOTTOM, border=5)
# image
self.imageBox = wx.BoxSizer(wx.HORIZONTAL)
filetype, ltype = GetImageHandlers(wx.EmptyImage(10, 10))
- self.browse = filebrowse.FileBrowseButton(parent = panel, id = wx.ID_ANY, fileMask = filetype,
- labelText = _("Image file:"),
- dialogTitle = _('Choose image file'),
- buttonText = _('Browse'),
- startDirectory = os.getcwd(), fileMode = wx.OPEN,
- changeCallback = self.OnSetImage)
- self.imageBox.Add(self.browse, proportion = 1, flag = wx.EXPAND)
- self.hidevbox.Add(self.imageBox, proportion = 0, flag = wx.EXPAND | wx.BOTTOM, border = 5)
+ self.browse = filebrowse.FileBrowseButton(parent=panel, id=wx.ID_ANY, fileMask=filetype,
+ labelText=_("Image file:"),
+ dialogTitle=_('Choose image file'),
+ buttonText=_('Browse'),
+ startDirectory=os.getcwd(), fileMode=wx.OPEN,
+ changeCallback=self.OnSetImage)
+ self.imageBox.Add(self.browse, proportion=1, flag=wx.EXPAND)
+ self.hidevbox.Add(self.imageBox, proportion=0, flag=wx.EXPAND | wx.BOTTOM, border=5)
# text
self.textBox = wx.BoxSizer(wx.HORIZONTAL)
- self.textBox.Add(wx.StaticText(panel, id = wx.ID_ANY, label = _("Text:")),
- proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border = 5)
- self.textCtrl = wx.TextCtrl(panel, id = wx.ID_ANY)
+ self.textBox.Add(wx.StaticText(panel, id=wx.ID_ANY, label=_("Text:")),
+ proportion=0, flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border=5)
+ self.textCtrl = wx.TextCtrl(panel, id=wx.ID_ANY)
self.textCtrl.Bind(wx.EVT_TEXT, self.OnText)
- self.textBox.Add(self.textCtrl, proportion = 1, flag = wx.EXPAND)
- self.hidevbox.Add(self.textBox, proportion = 0, flag = wx.EXPAND)
+ self.textBox.Add(self.textCtrl, proportion=1, flag=wx.EXPAND)
+ self.hidevbox.Add(self.textBox, proportion=0, flag=wx.EXPAND)
self.posBox = self._positionWidget(panel)
- self.hidevbox.Add(self.posBox, proportion = 0, flag = wx.EXPAND | wx.TOP, border = 5)
+ self.hidevbox.Add(self.posBox, proportion=0, flag=wx.EXPAND | wx.TOP, border=5)
return self.hidevbox
def _positionWidget(self, panel):
- grid = wx.GridBagSizer(vgap = 5, hgap = 5)
- label = wx.StaticText(panel, id = wx.ID_ANY, label = _("Placement as percentage of"
+ grid = wx.GridBagSizer(vgap=5, hgap=5)
+ label = wx.StaticText(panel, id=wx.ID_ANY, label=_("Placement as percentage of"
" screen coordinates (X: 0, Y: 0 is top left):"))
label.Wrap(400)
- self.spinX = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 0, max = 100, initial = 10)
- self.spinY = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 0, max = 100, initial = 10)
- self.spinX.Bind(wx.EVT_SPINCTRL, lambda evt, temp = 'X': self.OnPosition(evt, temp))
- self.spinY.Bind(wx.EVT_SPINCTRL, lambda evt, temp = 'Y': self.OnPosition(evt, temp))
-
- grid.Add(label, pos = (0, 0), span = (1, 4), flag = wx.EXPAND)
- grid.Add(wx.StaticText(panel, id = wx.ID_ANY, label = _("X:")), pos = (1, 0),
+ self.spinX = wx.SpinCtrl(panel, id=wx.ID_ANY, min=0, max=100, initial=10)
+ self.spinY = wx.SpinCtrl(panel, id=wx.ID_ANY, min=0, max=100, initial=10)
+ self.spinX.Bind(wx.EVT_SPINCTRL, lambda evt, temp='X': self.OnPosition(evt, temp))
+ self.spinY.Bind(wx.EVT_SPINCTRL, lambda evt, temp='Y': self.OnPosition(evt, temp))
+
+ grid.Add(label, pos=(0, 0), span = (1, 4), flag = wx.EXPAND)
+ grid.Add(wx.StaticText(panel, id=wx.ID_ANY, label=_("X:")), pos=(1, 0),
flag = wx.ALIGN_CENTER_VERTICAL)
- grid.Add(wx.StaticText(panel, id = wx.ID_ANY, label = _("Y:")), pos = (1, 2),
+ grid.Add(wx.StaticText(panel, id=wx.ID_ANY, label=_("Y:")), pos=(1, 2),
flag = wx.ALIGN_CENTER_VERTICAL)
- grid.Add(self.spinX, pos = (1, 1))
- grid.Add(self.spinY, pos = (1, 3))
+ grid.Add(self.spinX, pos=(1, 1))
+ grid.Add(self.spinY, pos=(1, 3))
return grid
def _createExportFormatPanel(self, notebook):
- panel = wx.Panel(notebook, id = wx.ID_ANY)
+ panel = wx.Panel(notebook, id=wx.ID_ANY)
borderSizer = wx.BoxSizer(wx.VERTICAL)
hSizer = wx.BoxSizer(wx.HORIZONTAL)
choices = [_("image sequence"), _("animated GIF"), _("SWF"), _("AVI")]
- self.formatChoice = wx.Choice(parent = panel, id = wx.ID_ANY,
- choices = choices)
+ self.formatChoice = wx.Choice(parent=panel, id=wx.ID_ANY,
+ choices=choices)
self.formatChoice.Bind(wx.EVT_CHOICE, lambda event: self.ChangeFormat(event.GetSelection()))
- hSizer.Add(item = wx.StaticText(panel, id = wx.ID_ANY, label = _("Export to:")),
- proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 2)
- hSizer.Add(item = self.formatChoice, proportion = 1,
- flag = wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.ALL, border = 2)
- borderSizer.Add(item = hSizer, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 3)
+ hSizer.Add(item=wx.StaticText(panel, id=wx.ID_ANY, label=_("Export to:")),
+ proportion=0, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=2)
+ hSizer.Add(item=self.formatChoice, proportion=1,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.ALL, border=2)
+ borderSizer.Add(item=hSizer, proportion=0, flag=wx.EXPAND | wx.ALL, border=3)
helpSizer = wx.BoxSizer(wx.HORIZONTAL)
helpSizer.AddStretchSpacer(1)
self.formatPanelSizer = wx.BoxSizer(wx.VERTICAL)
helpSizer.Add(self.formatPanelSizer, proportion=5, flag=wx.EXPAND)
- borderSizer.Add(helpSizer, proportion = 1, flag = wx.EXPAND)
+ borderSizer.Add(helpSizer, proportion=1, flag=wx.EXPAND)
self.formatPanels = []
# panel for image sequence
- imSeqPanel = wx.Panel(parent = panel, id = wx.ID_ANY)
- prefixLabel = wx.StaticText(imSeqPanel, id = wx.ID_ANY, label = _("File prefix:"))
- self.prefixCtrl = wx.TextCtrl(imSeqPanel, id = wx.ID_ANY, value = _("animation_"))
- formatLabel = wx.StaticText(imSeqPanel, id = wx.ID_ANY, label = _("File format:"))
+ imSeqPanel = wx.Panel(parent=panel, id=wx.ID_ANY)
+ prefixLabel = wx.StaticText(imSeqPanel, id=wx.ID_ANY, label=_("File prefix:"))
+ self.prefixCtrl = wx.TextCtrl(imSeqPanel, id=wx.ID_ANY, value=_("animation_"))
+ formatLabel = wx.StaticText(imSeqPanel, id=wx.ID_ANY, label=_("File format:"))
imageTypes = ['PNG', 'JPEG', 'GIF', 'TIFF', 'PPM', 'BMP']
self.imSeqFormatChoice = wx.Choice(imSeqPanel, choices=imageTypes)
self.imSeqFormatChoice.SetSelection(0)
- self.dirBrowse = filebrowse.DirBrowseButton(parent = imSeqPanel, id = wx.ID_ANY,
- labelText = _("Directory:"),
- dialogTitle = _("Choose directory for export"),
- buttonText = _("Browse"),
- startDirectory = os.getcwd())
+ self.dirBrowse = filebrowse.DirBrowseButton(parent=imSeqPanel, id=wx.ID_ANY,
+ labelText=_("Directory:"),
+ dialogTitle=_("Choose directory for export"),
+ buttonText=_("Browse"),
+ startDirectory=os.getcwd())
- dirGridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+ dirGridSizer = wx.GridBagSizer(hgap=5, vgap=5)
dirGridSizer.AddGrowableCol(1)
- dirGridSizer.Add(prefixLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
- dirGridSizer.Add(self.prefixCtrl, pos = (0, 1), flag = wx.EXPAND)
- dirGridSizer.Add(formatLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
- dirGridSizer.Add(self.imSeqFormatChoice, pos = (1, 1), flag = wx.EXPAND)
- dirGridSizer.Add(self.dirBrowse, pos = (2, 0), flag = wx.EXPAND, span = (1, 2))
+ dirGridSizer.Add(prefixLabel, pos=(0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+ dirGridSizer.Add(self.prefixCtrl, pos=(0, 1), flag = wx.EXPAND)
+ dirGridSizer.Add(formatLabel, pos=(1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+ dirGridSizer.Add(self.imSeqFormatChoice, pos=(1, 1), flag = wx.EXPAND)
+ dirGridSizer.Add(self.dirBrowse, pos=(2, 0), flag = wx.EXPAND, span = (1, 2))
imSeqPanel.SetSizer(dirGridSizer)
dirGridSizer.Fit(imSeqPanel)
- self.formatPanelSizer.Add(item = imSeqPanel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+ self.formatPanelSizer.Add(item=imSeqPanel, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
self.formatPanels.append(imSeqPanel)
# panel for gif
- gifPanel = wx.Panel(parent = panel, id = wx.ID_ANY)
+ gifPanel = wx.Panel(parent=panel, id=wx.ID_ANY)
- self.gifBrowse = filebrowse.FileBrowseButton(parent = gifPanel, id = wx.ID_ANY,
- fileMask = "GIF file (*.gif)|*.gif",
- labelText = _("GIF file:"),
- dialogTitle = _("Choose file to save animation"),
- buttonText = _("Browse"),
- startDirectory = os.getcwd(), fileMode = wx.SAVE)
- gifGridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+ self.gifBrowse = filebrowse.FileBrowseButton(parent=gifPanel, id=wx.ID_ANY,
+ fileMask="GIF file (*.gif)|*.gif",
+ labelText=_("GIF file:"),
+ dialogTitle=_("Choose file to save animation"),
+ buttonText=_("Browse"),
+ startDirectory=os.getcwd(), fileMode=wx.SAVE)
+ gifGridSizer = wx.GridBagSizer(hgap=5, vgap=5)
gifGridSizer.AddGrowableCol(0)
- gifGridSizer.Add(self.gifBrowse, pos = (0, 0), flag = wx.EXPAND)
+ gifGridSizer.Add(self.gifBrowse, pos=(0, 0), flag = wx.EXPAND)
gifPanel.SetSizer(gifGridSizer)
gifGridSizer.Fit(gifPanel)
- self.formatPanelSizer.Add(item = gifPanel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+ self.formatPanelSizer.Add(item=gifPanel, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
self.formatPanels.append(gifPanel)
# panel for swf
- swfPanel = wx.Panel(parent = panel, id = wx.ID_ANY)
- self.swfBrowse = filebrowse.FileBrowseButton(parent = swfPanel, id = wx.ID_ANY,
- fileMask = "SWF file (*.swf)|*.swf",
- labelText = _("SWF file:"),
- dialogTitle = _("Choose file to save animation"),
- buttonText = _("Browse"),
- startDirectory = os.getcwd(), fileMode = wx.SAVE)
- swfGridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+ swfPanel = wx.Panel(parent=panel, id=wx.ID_ANY)
+ self.swfBrowse = filebrowse.FileBrowseButton(parent=swfPanel, id=wx.ID_ANY,
+ fileMask="SWF file (*.swf)|*.swf",
+ labelText=_("SWF file:"),
+ dialogTitle=_("Choose file to save animation"),
+ buttonText=_("Browse"),
+ startDirectory=os.getcwd(), fileMode=wx.SAVE)
+ swfGridSizer = wx.GridBagSizer(hgap=5, vgap=5)
swfGridSizer.AddGrowableCol(0)
- swfGridSizer.Add(self.swfBrowse, pos = (0, 0), flag = wx.EXPAND)
+ swfGridSizer.Add(self.swfBrowse, pos=(0, 0), flag = wx.EXPAND)
swfPanel.SetSizer(swfGridSizer)
swfGridSizer.Fit(swfPanel)
- self.formatPanelSizer.Add(item = swfPanel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+ self.formatPanelSizer.Add(item=swfPanel, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
self.formatPanels.append(swfPanel)
# panel for avi
- aviPanel = wx.Panel(parent = panel, id = wx.ID_ANY)
+ aviPanel = wx.Panel(parent=panel, id=wx.ID_ANY)
ffmpeg = gcore.find_program('ffmpeg', '--help')
if not ffmpeg:
warning = _("Program 'ffmpeg' was not found.\nPlease install it first "
"and make sure\nit's in the PATH variable.")
warningLabel = wx.StaticText(parent=aviPanel, label=warning)
warningLabel.SetForegroundColour(wx.RED)
- self.aviBrowse = filebrowse.FileBrowseButton(parent = aviPanel, id = wx.ID_ANY,
- fileMask = "AVI file (*.avi)|*.avi",
- labelText = _("AVI file:"),
- dialogTitle = _("Choose file to save animation"),
- buttonText = _("Browse"),
- startDirectory = os.getcwd(), fileMode = wx.SAVE)
- encodingLabel = wx.StaticText(parent = aviPanel, id = wx.ID_ANY, label = _("Video codec:"))
- self.encodingText = wx.TextCtrl(parent = aviPanel, id = wx.ID_ANY, value = 'mpeg4')
+ self.aviBrowse = filebrowse.FileBrowseButton(parent=aviPanel, id=wx.ID_ANY,
+ fileMask="AVI file (*.avi)|*.avi",
+ labelText=_("AVI file:"),
+ dialogTitle=_("Choose file to save animation"),
+ buttonText=_("Browse"),
+ startDirectory=os.getcwd(), fileMode=wx.SAVE)
+ encodingLabel = wx.StaticText(parent=aviPanel, id=wx.ID_ANY, label=_("Video codec:"))
+ self.encodingText = wx.TextCtrl(parent=aviPanel, id=wx.ID_ANY, value='mpeg4')
optionsLabel = wx.StaticText(parent=aviPanel, label=_("Additional options:"))
self.optionsText = wx.TextCtrl(parent=aviPanel)
self.optionsText.SetToolTipString(_("Consider adding '-sameq' or '-qscale 1' "
"if not satisfied with video quality. "
"Options depend on ffmpeg version."))
- aviGridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+ aviGridSizer = wx.GridBagSizer(hgap=5, vgap=5)
aviGridSizer.AddGrowableCol(1)
- aviGridSizer.Add(self.aviBrowse, pos = (0, 0), span = (1, 2), flag = wx.EXPAND)
- aviGridSizer.Add(encodingLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
- aviGridSizer.Add(self.encodingText, pos = (1, 1), flag = wx.EXPAND)
+ aviGridSizer.Add(self.aviBrowse, pos=(0, 0), span = (1, 2), flag = wx.EXPAND)
+ aviGridSizer.Add(encodingLabel, pos=(1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+ aviGridSizer.Add(self.encodingText, pos=(1, 1), flag = wx.EXPAND)
aviGridSizer.Add(optionsLabel, pos=(2, 0), flag=wx.ALIGN_CENTER_VERTICAL)
aviGridSizer.Add(self.optionsText, pos=(2, 1), flag=wx.EXPAND)
if not ffmpeg:
@@ -1122,24 +899,24 @@
aviPanel.SetSizer(aviGridSizer)
aviGridSizer.Fit(aviPanel)
- self.formatPanelSizer.Add(item = aviPanel, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
+ self.formatPanelSizer.Add(item=aviPanel, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
self.formatPanels.append(aviPanel)
fpsSizer = wx.BoxSizer(wx.HORIZONTAL)
fps = 1000 / self.timeTick
- fpsSizer.Add(wx.StaticText(panel, id = wx.ID_ANY, label = _("Current frame rate: %.2f fps") % fps),
- proportion = 1, flag = wx.EXPAND)
- borderSizer.Add(fpsSizer, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
+ fpsSizer.Add(wx.StaticText(panel, id=wx.ID_ANY, label=_("Current frame rate: %.2f fps") % fps),
+ proportion=1, flag=wx.EXPAND)
+ borderSizer.Add(fpsSizer, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
panel.SetSizer(borderSizer)
borderSizer.Fit(panel)
- self.ChangeFormat(index = 0)
+ self.ChangeFormat(index=0)
return panel
def ChangeFormat(self, index):
for i, panel in enumerate(self.formatPanels):
- self.formatPanelSizer.Show(item = panel, show = (i == index))
+ self.formatPanelSizer.Show(item=panel, show=(i == index))
self.formatPanelSizer.Layout()
def OnFont(self, event):
@@ -1149,14 +926,14 @@
return
cdata = self.listbox.GetClientData(index)
font = cdata['font']
-
+
fontdata = wx.FontData()
fontdata.EnableEffects(True)
fontdata.SetColour('black')
fontdata.SetInitialFont(font)
-
+
dlg = wx.FontDialog(self, fontdata)
-
+
if dlg.ShowModal() == wx.ID_OK:
newfontdata = dlg.GetFontData()
font = newfontdata.GetChosenFont()
@@ -1164,7 +941,6 @@
cdata['font'] = font
self.Layout()
-
def OnPosition(self, event, coord):
index = self.listbox.GetSelection()
# should not happen
@@ -1194,7 +970,7 @@
self._updateListBox()
self.listbox.SetSelection(self.listbox.GetCount() - 1)
- self.OnSelectionChanged(event = None)
+ self.OnSelectionChanged(event=None)
def OnSelectionChanged(self, event):
index = self.listbox.GetSelection()
@@ -1235,37 +1011,37 @@
decData = self.listbox.GetClientData(index)
self.decorations.remove(decData)
-
+
self._updateListBox()
if self.listbox.GetCount():
self.listbox.SetSelection(0)
- self.OnSelectionChanged(event = None)
+ self.OnSelectionChanged(event=None)
def OnExport(self, event):
for decor in self.decorations:
if decor['name'] == 'image':
if not os.path.exists(decor['file']):
if decor['file']:
- GError(parent = self, message = _("File %s not found.") % decor['file'])
+ GError(parent=self, message=_("File %s not found.") % decor['file'])
else:
- GError(parent = self, message = _("Decoration image file is missing."))
+ GError(parent=self, message=_("Decoration image file is missing."))
return
if self.formatChoice.GetSelection() == 0:
name = self.dirBrowse.GetValue()
if not os.path.exists(name):
if name:
- GError(parent = self, message = _("Directory %s not found.") % name)
+ GError(parent=self, message=_("Directory %s not found.") % name)
else:
- GError(parent = self, message = _("Export directory is missing."))
+ GError(parent=self, message=_("Export directory is missing."))
return
elif self.formatChoice.GetSelection() == 1:
if not self.gifBrowse.GetValue():
- GError(parent = self, message = _("Export file is missing."))
+ GError(parent=self, message=_("Export file is missing."))
return
elif self.formatChoice.GetSelection() == 2:
if not self.swfBrowse.GetValue():
- GError(parent = self, message = _("Export file is missing."))
+ GError(parent=self, message=_("Export file is missing."))
return
# hide only to keep previous values
@@ -1304,7 +1080,7 @@
self.listbox.Clear()
names = {'time': _("Time stamp"), 'image': _("Image"), 'text': _("Text")}
for decor in self.decorations:
- self.listbox.Append(names[decor['name']], clientData = decor)
+ self.listbox.Append(names[decor['name']], clientData=decor)
def _hideAll(self):
self.hidevbox.Show(self.fontBox, False)
@@ -1314,37 +1090,277 @@
self.hidevbox.Show(self.informBox, True)
self.hidevbox.Layout()
+
+class AnimSimpleLayerManager(SimpleLayerManager):
+ """!Simple layer manager for animation tool.
+ Allows to add space-time dataset or series of maps.
+ """
+ def __init__(self, parent, layerList,
+ lmgrStyle=SIMPLE_LMGR_RASTER | SIMPLE_LMGR_VECTOR |
+ SIMPLE_LMGR_TB_TOP | SIMPLE_LMGR_STDS,
+ toolbarCls=AnimSimpleLmgrToolbar, modal=True):
+ SimpleLayerManager.__init__(self, parent, layerList, lmgrStyle, toolbarCls, modal)
+
+ def OnAddStds(self, event):
+ """!Opens dialog for specifying temporal dataset.
+ Dummy layer is added first."""
+ layer = AnimLayer()
+ layer.hidden = True
+ self._layerList.AddLayer(layer)
+ self.SetStdsProperties(layer)
+ event.Skip()
+
+ def SetStdsProperties(self, layer):
+ dlg = AddTemporalLayerDialog(parent=self, layer=layer)
+ # first get hidden property, it's altered afterwards
+ hidden = layer.hidden
+ if dlg.ShowModal() == wx.ID_OK:
+ layer = dlg.GetLayer()
+ if hidden:
+ signal = self.layerAdded
+ else:
+ signal = self.cmdChanged
+ signal.emit(index=self._layerList.GetLayerIndex(layer), layer=layer)
+ else:
+ if hidden:
+ self._layerList.RemoveLayer(layer)
+ dlg.Destroy()
+ self._update()
+ self.anyChange.emit()
+
+ def _layerChangeProperties(self, layer):
+ """!Opens new module dialog or recycles it."""
+ if layer in self._dialogs:
+ dlg = self._dialogs[layer]
+ if dlg.IsShown():
+ dlg.Raise()
+ dlg.SetFocus()
+ else:
+ dlg.Show()
+ else:
+ if not hasattr(layer, 'maps'):
+ GUI(parent=self, giface=None,
+ modal=self._modal).ParseCommand(cmd=layer.cmd,
+ completed=(self.GetOptData, layer, ''))
+ else:
+ self.SetStdsProperties(layer)
+
+ def Activate3D(self, activate=True):
+ """!Activates/deactivates certain tool depending on 2D/3D view."""
+ self._toolbar.EnableTools(['addRaster', 'addVector',
+ 'opacity', 'up', 'down'], not activate)
+
+
+class AddTemporalLayerDialog(wx.Dialog):
+ """!Dialog for adding space-time dataset/ map series."""
+ def __init__(self, parent, layer, title=_("Add space-time dataset layer")):
+ wx.Dialog.__init__(self, parent=parent, title=title)
+
+ self.layer = layer
+ self._mapType = None
+ self._name = None
+ self._cmd = None
+
+ self.tselect = Select(parent=self, type='strds')
+ iconTheme = UserSettings.Get(group='appearance', key='iconTheme', subkey='type')
+ bitmapPath = os.path.join(globalvar.ETCICONDIR, iconTheme, 'layer-open.png')
+ if os.path.isfile(bitmapPath) and os.path.getsize(bitmapPath):
+ bitmap = wx.Bitmap(name=bitmapPath)
+ else:
+ bitmap = wx.ArtProvider.GetBitmap(id=wx.ART_MISSING_IMAGE, client=wx.ART_TOOLBAR)
+ self.addManyMapsButton = wx.BitmapButton(self, bitmap=bitmap)
+ self.addManyMapsButton.Bind(wx.EVT_BUTTON, self._onAddMaps)
+
+ types = [('rast', _("Multiple raster maps")),
+ ('vect', _("Multiple vector maps")),
+ ('strds', _("Space time raster dataset")),
+ ('stvds', _("Space time vector dataset"))]
+ self._types = dict(types)
+
+ self.tchoice = wx.Choice(parent=self)
+ for type_, text in types:
+ self.tchoice.Append(text, clientData=type_)
+
+ self.editBtn = wx.Button(parent=self, label='Set properties')
+
+ self.okBtn = wx.Button(parent=self, id=wx.ID_OK)
+ self.cancelBtn = wx.Button(parent=self, id=wx.ID_CANCEL)
+
+ self.okBtn.Bind(wx.EVT_BUTTON, self._onOK)
+ self.editBtn.Bind(wx.EVT_BUTTON, self._onProperties)
+ self.tchoice.Bind(wx.EVT_CHOICE,
+ lambda evt: self._setType())
+ self.tselect.Bind(wx.EVT_TEXT,
+ lambda evt: self._datasetChanged())
+
+ if self.layer.mapType:
+ self._setType(self.layer.mapType)
+ else:
+ self._setType('rast')
+ if self.layer.name:
+ self.tselect.SetValue(self.layer.name)
+ if self.layer.cmd:
+ self._cmd = self.layer.cmd
+
+ self._layout()
+ self.SetSize(self.GetBestSize())
+
+ def _layout(self):
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ bodySizer = wx.BoxSizer(wx.VERTICAL)
+ typeSizer = wx.BoxSizer(wx.HORIZONTAL)
+ selectSizer = wx.BoxSizer(wx.HORIZONTAL)
+ typeSizer.Add(wx.StaticText(self, label=_("Input data type:")),
+ flag=wx.ALIGN_CENTER_VERTICAL)
+ typeSizer.AddStretchSpacer()
+ typeSizer.Add(self.tchoice)
+ bodySizer.Add(typeSizer, flag=wx.EXPAND | wx.BOTTOM, border=5)
+
+ selectSizer.Add(self.tselect, flag=wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, border=5)
+ selectSizer.Add(self.addManyMapsButton, flag=wx.EXPAND)
+ bodySizer.Add(selectSizer, flag=wx.BOTTOM, border=5)
+ bodySizer.Add(self.editBtn, flag=wx.BOTTOM, border=5)
+ mainSizer.Add(bodySizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
+
+ btnSizer = wx.StdDialogButtonSizer()
+ btnSizer.AddButton(self.okBtn)
+ btnSizer.AddButton(self.cancelBtn)
+ btnSizer.Realize()
+
+ mainSizer.Add(btnSizer, proportion=0,
+ flag=wx.EXPAND | wx.ALL, border=10)
+
+ self.SetSizer(mainSizer)
+ mainSizer.Fit(self)
+
+ def _datasetChanged(self):
+ if self._name != self.tselect.GetValue():
+ self._name = self.tselect.GetValue()
+ self._cmd = None
+
+ def _setType(self, typeName=None):
+ if typeName:
+ self.tchoice.SetStringSelection(self._types[typeName])
+ self.tselect.SetType(typeName)
+ if typeName in ('strds', 'stvds'):
+ self.tselect.SetType(typeName, multiple=False)
+ self.addManyMapsButton.Disable()
+ else:
+ self.tselect.SetType(typeName, multiple=True)
+ self.addManyMapsButton.Enable()
+ self._mapType = typeName
+ self.tselect.SetValue('')
+ else:
+ typeName = self.tchoice.GetClientData(self.tchoice.GetSelection())
+ if typeName in ('strds', 'stvds'):
+ self.tselect.SetType(typeName, multiple=False)
+ self.addManyMapsButton.Disable()
+ else:
+ self.tselect.SetType(typeName, multiple=True)
+ self.addManyMapsButton.Enable()
+ if typeName != self._mapType:
+ self._cmd = None
+ self._mapType = typeName
+ self.tselect.SetValue('')
+
+ def _createDefaultCommand(self):
+ cmd = []
+ if self._mapType in ('rast', 'strds'):
+ cmd.append('d.rast')
+ elif self._mapType in ('vect', 'stvds'):
+ cmd.append('d.vect')
+ if self._name:
+ if self._mapType in ('rast', 'vect'):
+ cmd.append('map={}'.format(self._name.split(',')[0]))
+ else:
+ try:
+ maps = getRegisteredMaps(self._name, etype=self._mapType)
+ if maps:
+ cmd.append('map={}'.format(maps[0]))
+ except gcore.ScriptError, e:
+ GError(parent=self, message=str(e), showTraceback=False)
+ return None
+ return cmd
+
+ def _onAddMaps(self, event):
+ dlg = MapLayersDialog(self, title=_("Select raster/vector maps."))
+ dlg.applyAddingMapLayers.connect(lambda mapLayers:
+ self.tselect.SetValue(','.join(mapLayers)))
+ index = 0 if self._mapType == 'rast' else 1
+ dlg.layerType.SetSelection(index)
+ dlg.LoadMapLayers(dlg.GetLayerType(cmd=True),
+ dlg.mapset.GetStringSelection())
+ if dlg.ShowModal() == wx.ID_OK:
+ self.tselect.SetValue(','.join(dlg.GetMapLayers()))
+
+ dlg.Destroy()
+
+ def _onProperties(self, event):
+ self._checkInput()
+ if self._cmd:
+ GUI(parent=self, show=True, modal=True).ParseCommand(cmd=self._cmd,
+ completed=(self._getOptData, '', ''))
+
+ def _checkInput(self):
+ if not self.tselect.GetValue():
+ GMessage(parent=self, message=_("Please select maps or dataset first."))
+ return
+
+ if not self._cmd:
+ self._cmd = self._createDefaultCommand()
+
+ def _getOptData(self, dcmd, layer, params, propwin):
+ if dcmd:
+ self._cmd = dcmd
+
+ def _onOK(self, event):
+ self._checkInput()
+ if self._cmd:
+ try:
+ self.layer.hidden = False
+ self.layer.mapType = self._mapType
+ self.layer.name = self._name
+ self.layer.cmd = self._cmd
+ event.Skip()
+ except (GException, gcore.ScriptError), e:
+ GError(parent=self, message=str(e))
+
+ def GetLayer(self):
+ return self.layer
+
+
def test():
import wx.lib.inspection
- import grass.script as grass
-
app = wx.PySimpleApp()
- testExport()
+# testTemporalLayer()
+# testAnimLmgr()
+ testAnimInput()
# wx.lib.inspection.InspectionTool().Show()
-
-
app.MainLoop()
+
def testAnimInput():
anim = AnimationData()
- anim.SetDefaultValues(animationIndex = 0, windowIndex = 0)
+ anim.SetDefaultValues(animationIndex=0, windowIndex=0)
- dlg = InputDialog(parent = None, mode = 'add', animationData = anim)
+ dlg = InputDialog(parent=None, mode='add', animationData=anim)
dlg.Show()
+
def testAnimEdit():
anim = AnimationData()
- anim.SetDefaultValues(animationIndex = 0, windowIndex = 0)
+ anim.SetDefaultValues(animationIndex=0, windowIndex=0)
- dlg = EditDialog(parent = None, animationData = [anim])
+ dlg = EditDialog(parent=None, animationData=[anim])
dlg.Show()
+
def testExport():
- dlg = ExportDialog(parent = None, temporal = TemporalMode.TEMPORAL,
- timeTick = 200, visvis = True)
+ dlg = ExportDialog(parent=None, temporal=TemporalMode.TEMPORAL,
+ timeTick=200)
if dlg.ShowModal() == wx.ID_OK:
print dlg.GetDecorations()
print dlg.GetExportInformation()
@@ -1353,6 +1369,28 @@
dlg.Destroy()
+def testTemporalLayer():
+ frame = wx.Frame(None)
+ frame.Show()
+ layer = AnimLayer()
+ dlg = AddTemporalLayerDialog(parent=frame, layer=layer)
+ if dlg.ShowModal() == wx.ID_OK:
+ layer = dlg.GetLayer()
+ print layer.name, layer.cmd, layer.mapType
+ dlg.Destroy()
+ else:
+ dlg.Destroy()
+
+
+def testAnimLmgr():
+ from core.layerlist import LayerList
+
+ frame = wx.Frame(None)
+ mgr = AnimSimpleLayerManager(parent=frame, layerList=LayerList())
+ frame.mgr = mgr
+ frame.Show()
+
+
if __name__ == '__main__':
-
- test()
\ No newline at end of file
+ gcore.set_raise_on_error(True)
+ test()
Modified: grass/trunk/gui/wxpython/animation/frame.py
===================================================================
--- grass/trunk/gui/wxpython/animation/frame.py 2013-11-30 19:48:36 UTC (rev 58342)
+++ grass/trunk/gui/wxpython/animation/frame.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -4,46 +4,54 @@
@brief Animation frame and different types of sliders
Classes:
- - frame::SwipeMapDialog
- frame::AnimationFrame
- frame::AnimationsPanel
- frame::AnimationSliderBase
- frame::SimpleAnimationSlider
- frame::TimeAnimationSlider
+(C) 2013 by the GRASS Development Team
-(C) 2012 by the GRASS Development Team
-
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
- at author Anna Kratochvilova <kratochanna gmail.com>
+ at author Anna Petrasova <kratochanna gmail.com>
"""
import os
import sys
import wx
import wx.aui
+import tempfile
if __name__ == '__main__':
sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "gui", "wxpython"))
+import grass.script as gcore
from core import globalvar
from gui_core.widgets import IntegerValidator
from core.gcmd import RunCommand
from core.utils import _
-from mapwindow import AnimationWindow, BitmapProvider, BitmapPool
-from controller import AnimationController
-from anim import Animation
-from toolbars import MainToolbar, AnimationToolbar, MiscToolbar
-from dialogs import SpeedDialog
-from utils import Orientation, ReplayMode, TemporalType
+from animation.mapwindow import AnimationWindow
+from animation.provider import BitmapProvider, BitmapPool, \
+ MapFilesPool, CleanUp
+from animation.controller import AnimationController
+from animation.anim import Animation
+from animation.toolbars import MainToolbar, AnimationToolbar, MiscToolbar
+from animation.dialogs import SpeedDialog
+from animation.utils import Orientation, ReplayMode, TemporalType
MAX_COUNT = 4
+TMP_DIR = tempfile.mkdtemp()
+gcore.set_raise_on_error(True)
+
+
class AnimationFrame(wx.Frame):
- def __init__(self, parent = None, id = wx.ID_ANY, title = _("Animation tool"), rasters = None, timeseries = None):
- wx.Frame.__init__(self, parent, id, title = title, style = wx.DEFAULT_FRAME_STYLE, size = (800, 600))
+ def __init__(self, parent=None, title=_("Animation tool"),
+ rasters=None, timeseries=None):
+ wx.Frame.__init__(self, parent, title=title,
+ style=wx.DEFAULT_FRAME_STYLE, size=(800, 600))
self.SetClientSize(self.GetSize())
self.iconsize = (16, 16)
@@ -52,22 +60,37 @@
self.animations = [Animation() for i in range(MAX_COUNT)]
self.windows = []
- self.animationPanel = AnimationsPanel(self, self.windows, initialCount = MAX_COUNT)
+ self.animationPanel = AnimationsPanel(self, self.windows, initialCount=MAX_COUNT)
bitmapPool = BitmapPool()
- self.providers = [BitmapProvider(frame = self, bitmapPool = bitmapPool) for i in range(MAX_COUNT)]
+ mapFilesPool = MapFilesPool()
+ # create temporal directory and ensure it's deleted after programs ends
+# tempDir = tempfile.mkdtemp()
+# self.cleanUp = CleanUp(tempDir)
+
+ self._progressDlg = None
+ self._progressDlgMax = None
+
+ self.provider = BitmapProvider(bitmapPool=bitmapPool,
+ mapFilesPool=mapFilesPool, tempDir=TMP_DIR)
self.animationSliders = {}
self.animationSliders['nontemporal'] = SimpleAnimationSlider(self)
self.animationSliders['temporal'] = TimeAnimationSlider(self)
- self.controller = AnimationController(frame = self,
- sliders = self.animationSliders,
- animations = self.animations,
- mapwindows = self.windows,
- providers = self.providers,
- bitmapPool = bitmapPool)
- for win, provider in zip(self.windows, self.providers):
- win.Bind(wx.EVT_SIZE, lambda event, provider=provider,
- sizeMethod=win.GetClientSize: self.FrameSizeChanged(event, provider, sizeMethod))
- provider.mapsLoaded.connect(lambda: self.SetStatusText(''))
+ self.controller = AnimationController(frame=self,
+ sliders=self.animationSliders,
+ animations=self.animations,
+ mapwindows=self.windows,
+ provider=self.provider,
+ bitmapPool=bitmapPool,
+ mapFilesPool=mapFilesPool)
+ for win in self.windows:
+ win.Bind(wx.EVT_SIZE, self.FrameSizeChanged)
+ self.provider.mapsLoaded.connect(lambda: self.SetStatusText(''))
+ self.provider.renderingStarted.connect(self._showRenderingProgress)
+ self.provider.renderingContinues.connect(self._updateProgress)
+ self.provider.renderingFinished.connect(self._closeProgress)
+ self.provider.compositionStarted.connect(self._showRenderingProgress)
+ self.provider.compositionContinues.connect(self._updateProgress)
+ self.provider.compositionFinished.connect(self._closeProgress)
self.InitStatusbar()
self._mgr = wx.aui.AuiManager(self)
@@ -90,13 +113,14 @@
def InitStatusbar(self):
"""!Init statusbar."""
- self.CreateStatusBar(number = 1, style = 0)
+ self.CreateStatusBar(number=1, style=0)
def _addPanes(self):
- self._mgr.AddPane(self.animationPanel, wx.aui.AuiPaneInfo().CentrePane().
- Name('animPanel').CentrePane().CaptionVisible(False).PaneBorder(False).
- Floatable(False).BestSize((-1,-1)).
- CloseButton(False).DestroyOnClose(True).Layer(0))
+ self._mgr.AddPane(self.animationPanel,
+ wx.aui.AuiPaneInfo().CentrePane().
+ Name('animPanel').CentrePane().CaptionVisible(False).PaneBorder(False).
+ Floatable(False).BestSize((-1, -1)).
+ CloseButton(False).DestroyOnClose(True).Layer(0))
for name, slider in self.animationSliders.iteritems():
self._mgr.AddPane(slider, wx.aui.AuiPaneInfo().PaneBorder(False).Name('slider_' + name).
Layer(1).CaptionVisible(False).BestSize(slider.GetBestSize()).
@@ -105,7 +129,7 @@
def _addToolbar(self, name):
"""!Add defined toolbar to the window
-
+
Currently known toolbars are:
- 'mainToolbar' - data management
- 'animationToolbar' - animation controls
@@ -143,15 +167,13 @@
CloseButton(False).Layer(2).Row(1).
BestSize((self.toolbars['miscToolbar'].GetBestSize())))
- def SetAnimations(self, inputs=None, dataType=None):
+ def SetAnimations(self, layerLists):
"""!Set animation data
-
- @param inputs list of lists of raster maps or vector maps,
- or a space time raster or vector dataset
- @param dataType The type of the input data must be one of 'rast', 'vect', 'strds' or 'strds'
- """
- self.controller.SetAnimations(inputs, dataType)
+ @param layerLists list of layerLists
+ """
+ self.controller.SetAnimations(layerLists)
+
def OnAddAnimation(self, event):
self.controller.AddAnimation()
@@ -166,7 +188,7 @@
def OnEditAnimation(self, event):
self.controller.EditAnimations()
-
+
def SetSlider(self, name):
if name == 'nontemporal':
self._mgr.GetPane('slider_nontemporal').Show()
@@ -189,7 +211,7 @@
self.controller.StartAnimation()
def OnPause(self, event):
- self.controller.PauseAnimation(paused = event.IsChecked())
+ self.controller.PauseAnimation(paused=event.IsChecked())
def OnStop(self, event):
self.controller.EndAnimation()
@@ -218,10 +240,10 @@
win.SetFocus()
else:
win.Show()
- else: # start
- win = SpeedDialog(self, temporalMode = self.controller.GetTemporalMode(),
- timeGranularity = self.controller.GetTimeGranularity(),
- initialSpeed = self.controller.timeTick)
+ else: # start
+ win = SpeedDialog(self, temporalMode=self.controller.GetTemporalMode(),
+ timeGranularity=self.controller.GetTimeGranularity(),
+ initialSpeed=self.controller.timeTick)
self.dialogs['speed'] = win
win.speedChanged.connect(self.ChangeSpeed)
win.Show()
@@ -232,40 +254,64 @@
def Reload(self, event):
self.controller.Reload()
+ def _showRenderingProgress(self, count):
+ # the message is not really visible, it's there for the initial dlg size
+ self._progressDlg = wx.ProgressDialog(title=_("Loading data"),
+ message="Loading data started, please be patient.",
+ maximum=count,
+ parent=self,
+ style=wx.PD_CAN_ABORT | wx.PD_APP_MODAL |
+ wx.PD_AUTO_HIDE | wx.PD_SMOOTH)
+ self._progressDlgMax = count
+
+ def _updateProgress(self, current, text):
+ text += _(" ({} out of {})").format(current, self._progressDlgMax)
+ keepGoing, skip = self._progressDlg.Update(current, text)
+ if not keepGoing:
+ self.provider.RequestStopRendering()
+
+ def _closeProgress(self):
+ self._progressDlg.Destroy()
+ self._progressDlg = None
+
def OnExportAnimation(self, event):
self.controller.Export()
- def FrameSizeChanged(self, event, provider, sizeMethod):
- provider.WindowSizeChanged(*sizeMethod())
- if self.animationPanel.shown:
- self.SetStatusText(_("Window size has changed, rerender maps if needed"))
+ def FrameSizeChanged(self, event):
+ maxWidth = maxHeight = 0
+ for win in self.windows:
+ w, h = win.GetClientSize()
+ if w >= maxWidth and h >= maxHeight:
+ maxWidth, maxHeight = w, h
+ self.provider.WindowSizeChanged(maxWidth, maxHeight)
event.Skip()
-
-
+
def OnHelp(self, event):
RunCommand('g.manual',
- quiet = True,
- entry = 'wxGUI.animation')
+ quiet=True,
+ entry='wxGUI.animation')
def OnCloseWindow(self, event):
+ CleanUp(TMP_DIR)()
self.Destroy()
def __del__(self):
if hasattr(self, 'controller') and hasattr(self.controller, 'timer'):
if self.controller.timer.IsRunning():
self.controller.timer.Stop()
+ CleanUp(TMP_DIR)()
class AnimationsPanel(wx.Panel):
- def __init__(self, parent, windows, initialCount = 4):
- wx.Panel.__init__(self, parent, id = wx.ID_ANY, style = wx.NO_BORDER)
+ def __init__(self, parent, windows, initialCount=4):
+ wx.Panel.__init__(self, parent, id=wx.ID_ANY, style=wx.NO_BORDER)
self.shown = []
self.count = initialCount
- self.mainSizer = wx.FlexGridSizer(rows = 2, hgap = 0, vgap = 0)
+ self.mainSizer = wx.FlexGridSizer(rows=2, hgap=0, vgap=0)
for i in range(initialCount):
w = AnimationWindow(self)
windows.append(w)
- self.mainSizer.Add(item = w, proportion = 1, flag = wx.EXPAND)
+ self.mainSizer.Add(item=w, proportion=1, flag=wx.EXPAND)
self.mainSizer.AddGrowableCol(0)
self.mainSizer.AddGrowableCol(1)
@@ -278,7 +324,6 @@
self.mainSizer.Hide(windows[i])
self.Layout()
-
def AddWindow(self, index):
if len(self.shown) == self.count:
return
@@ -299,12 +344,12 @@
class AnimationSliderBase(wx.Panel):
def __init__(self, parent):
- wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
- self.label1 = wx.StaticText(self, id = wx.ID_ANY)
- self.slider = wx.Slider(self, id = wx.ID_ANY, style = wx.SL_HORIZONTAL)
- self.indexField = wx.TextCtrl(self, id = wx.ID_ANY, size = (40, -1),
- style = wx.TE_PROCESS_ENTER | wx.TE_RIGHT,
- validator = IntegerValidator())
+ wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY)
+ self.label1 = wx.StaticText(self, id=wx.ID_ANY)
+ self.slider = wx.Slider(self, id=wx.ID_ANY, style=wx.SL_HORIZONTAL)
+ self.indexField = wx.TextCtrl(self, id=wx.ID_ANY, size=(40, -1),
+ style=wx.TE_PROCESS_ENTER | wx.TE_RIGHT,
+ validator=IntegerValidator())
self.callbackSliderChanging = None
self.callbackSliderChanged = None
@@ -333,7 +378,7 @@
def SetFrames(self, frames):
self._setFrames(frames)
-
+
def _setFrames(self, frames):
raise NotImplementedError
@@ -346,7 +391,7 @@
def SetCallbackFrameIndexChanged(self, callback):
self.callbackFrameIndexChanged = callback
- def EnableSlider(self, enable = True):
+ def EnableSlider(self, enable=True):
if enable and self.framesCount <= 1:
enable = False # we don't want to enable it
self.enable = enable
@@ -394,11 +439,11 @@
def _doLayout(self):
hbox = wx.BoxSizer(wx.HORIZONTAL)
- hbox.Add(item = self.indexField, proportion = 0,
- flag = wx.ALIGN_CENTER | wx.LEFT, border = 5)
- hbox.Add(item = self.label1, proportion = 0,
- flag = wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, border = 5)
- hbox.Add(item = self.slider, proportion = 1, flag = wx.ALIGN_CENTER| wx.EXPAND, border = 0)
+ hbox.Add(item=self.indexField, proportion=0,
+ flag=wx.ALIGN_CENTER | wx.LEFT, border=5)
+ hbox.Add(item=self.label1, proportion=0,
+ flag=wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, border=5)
+ hbox.Add(item=self.slider, proportion=1, flag=wx.ALIGN_CENTER | wx.EXPAND, border=0)
self.SetSizerAndFit(hbox)
def _setFrames(self, count):
@@ -423,8 +468,8 @@
def __init__(self, parent):
AnimationSliderBase.__init__(self, parent)
self.timeLabels = []
- self.label2 = wx.StaticText(self, id = wx.ID_ANY)
- self.label3 = wx.StaticText(self, id = wx.ID_ANY)
+ self.label2 = wx.StaticText(self, id=wx.ID_ANY)
+ self.label3 = wx.StaticText(self, id=wx.ID_ANY)
self.label2Length = 0
self.temporalType = TemporalType.RELATIVE
@@ -434,21 +479,21 @@
def _doLayout(self):
vbox = wx.BoxSizer(wx.VERTICAL)
hbox = wx.BoxSizer(wx.HORIZONTAL)
- hbox.Add(item = self.label1, proportion = 0,
- flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
+ hbox.Add(item=self.label1, proportion=0,
+ flag=wx.ALIGN_CENTER_VERTICAL, border=0)
hbox.AddStretchSpacer()
- hbox.Add(item = self.indexField, proportion = 0,
- flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
- hbox.Add(item = self.label2, proportion = 0,
- flag = wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border = 3)
+ hbox.Add(item=self.indexField, proportion=0,
+ flag=wx.ALIGN_CENTER_VERTICAL, border=0)
+ hbox.Add(item=self.label2, proportion=0,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=3)
hbox.AddStretchSpacer()
- hbox.Add(item = self.label3, proportion = 0,
- flag = wx.ALIGN_CENTER_VERTICAL, border = 0)
- vbox.Add(item = hbox, proportion = 0, flag = wx.EXPAND, border = 0)
+ hbox.Add(item=self.label3, proportion=0,
+ flag=wx.ALIGN_CENTER_VERTICAL, border=0)
+ vbox.Add(item=hbox, proportion=0, flag=wx.EXPAND, border=0)
hbox = wx.BoxSizer(wx.HORIZONTAL)
- hbox.Add(item = self.slider, proportion = 1, flag = wx.ALIGN_CENTER | wx.EXPAND, border = 0)
- vbox.Add(item = hbox, proportion = 0, flag = wx.EXPAND, border = 0)
+ hbox.Add(item=self.slider, proportion=1, flag=wx.ALIGN_CENTER | wx.EXPAND, border=0)
+ vbox.Add(item=hbox, proportion=0, flag=wx.EXPAND, border=0)
self._setTemporalType()
self.SetSizerAndFit(vbox)
@@ -507,9 +552,10 @@
def _updateFrameIndex(self, index):
start = self.timeLabels[index][0]
- if self.timeLabels[index][1]: # interval
+ if self.timeLabels[index][1]: # interval
if self.temporalType == TemporalType.ABSOLUTE:
- label = _("%(from)s %(dash)s %(to)s") % {'from': start, 'dash': u"\u2013", 'to': self.timeLabels[index][1]}
+ label = _("%(from)s %(dash)s %(to)s") % \
+ {'from': start, 'dash': u"\u2013", 'to': self.timeLabels[index][1]}
else:
label = _("to %(to)s") % {'to': self.timeLabels[index][1]}
else:
@@ -523,20 +569,3 @@
if len(label) != self.label2Length:
self.label2Length = len(label)
self.Layout()
-
-def test():
-
- import grass.script as grass
-
- app = wx.PySimpleApp()
- wx.InitAllImageHandlers()
-
- frame = AnimationFrame(parent=None)
- frame.SetAnimations(inputs=None, dataType=None)
-
- frame.Show()
- app.MainLoop()
-
-if __name__ == '__main__':
-
- test()
Modified: grass/trunk/gui/wxpython/animation/g.gui.animation.py
===================================================================
--- grass/trunk/gui/wxpython/animation/g.gui.animation.py 2013-11-30 19:48:36 UTC (rev 58342)
+++ grass/trunk/gui/wxpython/animation/g.gui.animation.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -60,22 +60,21 @@
if __name__ == '__main__':
sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "gui", "wxpython"))
-from core.settings import UserSettings
from core.globalvar import CheckWxVersion
-from core.giface import StandaloneGrassInterface
from core.utils import _, GuiModuleMain
+from core.layerlist import LayerList
from animation.frame import AnimationFrame, MAX_COUNT
+from animation.data import AnimLayer
+
def main():
rast = options['rast']
vect = options['vect']
strds = options['strds']
stvds = options['stvds']
-
- dataType=None
- inputs=None
- numInputs=0
-
+
+ numInputs = 0
+
if rast:
numInputs += 1
if vect:
@@ -85,33 +84,47 @@
if stvds:
numInputs += 1
- if numInputs > 1:
+ if numInputs > 1:
grass.fatal(_("Options 'rast', 'vect', 'strds' and 'stvds' are mutually exclusive."))
+ layerList = LayerList()
if rast:
- inputs = [rast.split(',')] + [None] * (MAX_COUNT - 1)
- dataType='rast'
+ layer = AnimLayer()
+ layer.mapType = 'rast'
+ layer.name = rast
+ layer.cmd = ['d.rast', 'map={}'.format(rast.split(',')[0])]
+ layerList.AddLayer(layer)
if vect:
- inputs = [vect.split(',')] + [None] * (MAX_COUNT - 1)
- dataType='vect'
+ layer = AnimLayer()
+ layer.mapType = 'vect'
+ layer.name = vect
+ layer.cmd = ['d.vect', 'map={}'.format(rast.split(',')[0])]
+ layerList.AddLayer(layer)
if strds:
- inputs = [strds] + [None] * (MAX_COUNT - 1)
- dataType='strds'
+ layer = AnimLayer()
+ layer.mapType = 'strds'
+ layer.name = strds
+ layer.cmd = ['d.rast', 'map=']
+ layerList.AddLayer(layer)
if stvds:
- inputs = [stvds] + [None] * (MAX_COUNT - 1)
- dataType='stvds'
+ layer = AnimLayer()
+ layer.mapType = 'stvds'
+ layer.name = stvds
+ layer.cmd = ['d.vect', 'map=']
+ layerList.AddLayer(layer)
app = wx.PySimpleApp()
if not CheckWxVersion([2, 9]):
wx.InitAllImageHandlers()
- frame = AnimationFrame(parent = None)
+ frame = AnimationFrame(parent=None)
frame.CentreOnScreen()
frame.Show()
- frame.SetAnimations(inputs = inputs, dataType = dataType)
+ if len(layerList) >= 1:
+ frame.SetAnimations([layerList] + [None] * (MAX_COUNT - 1))
app.MainLoop()
if __name__ == '__main__':
options, flags = grass.parser()
-
+
GuiModuleMain(main)
Modified: grass/trunk/gui/wxpython/animation/mapwindow.py
===================================================================
--- grass/trunk/gui/wxpython/animation/mapwindow.py 2013-11-30 19:48:36 UTC (rev 58342)
+++ grass/trunk/gui/wxpython/animation/mapwindow.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -1,32 +1,23 @@
"""!
@package animation.mapwindow
- at brief Animation window and bitmaps management
+ at brief Animation window
Classes:
- mapwindow::BufferedWindow
- mapwindow::AnimationWindow
- - mapwindow::BitmapProvider
- - mapwindow::BitmapPool
-(C) 2012 by the GRASS Development Team
+(C) 2013 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
- at author Anna Kratochvilova <kratochanna gmail.com>
+ at author Anna Petrasova <kratochanna gmail.com>
"""
-import os
+
import wx
-from multiprocessing import Process, Queue
-import tempfile
-import grass.script as grass
-from core.gcmd import RunCommand, GException
from core.debug import Debug
-from core.settings import UserSettings
-from core.utils import _, CmdToTuple, autoCropImageFromFile
-from grass.pydispatch.signal import Signal
class BufferedWindow(wx.Window):
"""
@@ -45,7 +36,8 @@
"""
def __init__(self, *args, **kwargs):
# make sure the NO_FULL_REPAINT_ON_RESIZE style flag is set.
- kwargs['style'] = kwargs.setdefault('style', wx.NO_FULL_REPAINT_ON_RESIZE) | wx.NO_FULL_REPAINT_ON_RESIZE
+ kwargs['style'] = kwargs.setdefault('style', wx.NO_FULL_REPAINT_ON_RESIZE) | \
+ wx.NO_FULL_REPAINT_ON_RESIZE
wx.Window.__init__(self, *args, **kwargs)
Debug.msg(2, "BufferedWindow.__init__()")
@@ -71,7 +63,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.GetClientSize()
+ 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
@@ -82,7 +74,7 @@
def SaveToFile(self, FileName, FileType=wx.BITMAP_TYPE_PNG):
## This will save the contents of the buffer
- ## to the specified file. See the wxWindows docs for
+ ## to the specified file. See the wxWindows docs for
## wx.Bitmap::SaveFile for the details
self._Buffer.SaveFile(FileName, FileType)
@@ -99,18 +91,18 @@
dc = wx.MemoryDC()
dc.SelectObject(self._Buffer)
self.Draw(dc)
- del dc # need to get rid of the MemoryDC before Update() is called.
+ del dc # need to get rid of the MemoryDC before Update() is called.
self.Refresh()
self.Update()
class AnimationWindow(BufferedWindow):
def __init__(self, parent, id=wx.ID_ANY,
- style = wx.DEFAULT_FRAME_STYLE | wx.FULL_REPAINT_ON_RESIZE | wx.BORDER_RAISED):
+ style=wx.DEFAULT_FRAME_STYLE | wx.FULL_REPAINT_ON_RESIZE |
+ wx.BORDER_RAISED):
Debug.msg(2, "AnimationWindow.__init__()")
self.bitmap = wx.EmptyBitmap(1, 1)
- self.text = ''
self.parent = parent
self._pdc = wx.PseudoDC()
self._overlay = None
@@ -126,20 +118,19 @@
"""!Draws bitmap."""
Debug.msg(5, "AnimationWindow.Draw()")
- dc.Clear() # make sure you clear the bitmap!
+ dc.Clear() # make sure you clear the bitmap!
dc.DrawBitmap(self.bitmap, x=0, y=0)
- dc.DrawText(self.text, 0, 0)
def OnSize(self, event):
Debug.msg(5, "AnimationWindow.OnSize()")
- self.DrawBitmap(self.bitmap, self.text)
-
+ self.DrawBitmap(self.bitmap)
+
BufferedWindow.OnSize(self, event)
if event:
event.Skip()
- def DrawBitmap(self, bitmap, text):
+ def DrawBitmap(self, bitmap):
"""!Draws bitmap.
Does not draw the bitmap if it is the same one as last time.
"""
@@ -147,7 +138,6 @@
return
self.bitmap = bitmap
- self.text = text
self.UpdateDrawing()
def DrawOverlay(self, x, y):
@@ -193,7 +183,6 @@
if self._overlay:
self._pdc.DrawToDC(dc)
-
def OnMouseEvents(self, event):
"""!Handle mouse events."""
# If it grows larger, split it.
@@ -223,371 +212,3 @@
"""!Returns x, y position in pixels"""
rect = self._pdc.GetIdBounds(1)
return rect.GetX(), rect.GetY()
-
-
-class BitmapProvider(object):
- """!Class responsible for loading data and providing bitmaps"""
- def __init__(self, frame, bitmapPool, imageWidth=640, imageHeight=480, nprocs=4):
-
- self.datasource = None
- self.dataNames = None
- self.dataType = None
- self.bitmapPool = bitmapPool
- self.frame = frame
- self.imageWidth = imageWidth # width of the image to render with d.rast or d.vect
- self.imageHeight = imageHeight # height of the image to render with d.rast or d.vect
- self.nprocs = nprocs # Number of procs to be used for rendering
-
- self.suffix = ''
- self.nvizRegion = None
-
- self.mapsLoaded = Signal('mapsLoaded')
-
- def GetDataNames(self):
- return self.dataNames
-
- def SetData(self, datasource, dataNames = None, dataType = 'rast',
- suffix = '', nvizRegion = None):
- """!Sets data.
-
- @param datasource data to load (raster maps, vector maps, m.nviz.image commands)
- @param dataNames data labels (keys)
- @param dataType 'rast', 'vect', 'nviz'
- @param nvizRegion region which must be set for m.nviz.image
- """
- self.datasource = datasource
- self.dataType = dataType
- self.suffix = suffix
- self.nvizRegion = nvizRegion
-
- if dataNames:
- self.dataNames = dataNames
- else:
- self.dataNames = datasource
-
- self.dataNames = [name + self.suffix for name in self.dataNames]
-
- def GetBitmap(self, dataId):
- """!Returns bitmap with given key
- or 'no data' bitmap if no such key exists.
-
- @param dataId name of bitmap
- """
- if dataId:
- dataId += self.suffix
- try:
- bitmap = self.bitmapPool[dataId]
- except KeyError:
- bitmap = self.bitmapPool[None]
- return bitmap
-
- def WindowSizeChanged(self, width, height):
- """!Sets size when size of related window changes."""
- self.imageWidth, self.imageHeight = width, height
-
- def _createNoDataBitmap(self, width, height, text="No data"):
- """!Creates 'no data' bitmap.
-
- Used when requested bitmap is not available (loading data was not successful) or
- we want to show 'no data' bitmap.
- """
- bitmap = wx.EmptyBitmap(width, height)
- dc = wx.MemoryDC()
- dc.SelectObject(bitmap)
- dc.Clear()
- text = _(text)
- dc.SetFont(wx.Font(pointSize = 40, family = wx.FONTFAMILY_SCRIPT,
- style = wx.FONTSTYLE_NORMAL, weight = wx.FONTWEIGHT_BOLD))
- tw, th = dc.GetTextExtent(text)
- dc.DrawText(text, (width-tw)/2, (height-th)/2)
- dc.SelectObject(wx.NullBitmap)
- return bitmap
-
- def Load(self, force = False, nprocs=4):
- """!Loads data.
-
- Shows progress dialog.
-
- @param force if True reload all data, otherwise only missing data
- @param imageWidth width of the image to render with d.rast or d.vect
- @param imageHeight height of the image to render with d.rast or d.vect
- @param nprocs number of procs to be used for rendering
- """
- if nprocs <= 0:
- nprocs = 1
-
- count, maxLength = self._dryLoad(rasters = self.datasource,
- names = self.dataNames, force = force)
- progress = None
- if self.dataType in ('rast', 'vect', 'strds', 'stvds') and count > 5 or \
- self.dataType == 'nviz':
- progress = wx.ProgressDialog(title = "Loading data",
- message = " " * (maxLength + 20), # ?
- maximum = count,
- parent = self.frame,
- style = wx.PD_CAN_ABORT | wx.PD_APP_MODAL |
- wx.PD_AUTO_HIDE | wx.PD_SMOOTH)
- updateFunction = progress.Update
- else:
- updateFunction = None
-
- if self.dataType in ('rast', 'vect', 'strds', 'stvds'):
- self._loadMaps(mapType=self.dataType, maps = self.datasource, names = self.dataNames,
- force = force, updateFunction = updateFunction,
- imageWidth=self.imageWidth, imageHeight=self.imageHeight, nprocs=nprocs)
- elif self.dataType == 'nviz':
- self._load3D(commands = self.datasource, region = self.nvizRegion, names = self.dataNames,
- force = force, updateFunction = updateFunction)
- if progress:
- progress.Destroy()
-
- self.mapsLoaded.emit()
-
- def Unload(self):
- self.datasource = None
- self.dataNames = None
- self.dataType = None
-
- def _dryLoad(self, rasters, names, force):
- """!Tries how many bitmaps will be loaded.
- Used for progress dialog.
-
- @param rasters raster maps to be loaded
- @param names names used as keys for bitmaps
- @param force load everything even though it is already there
- """
- count = 0
- maxLength = 0
- for raster, name in zip(rasters, names):
- if not force and name in self.bitmapPool and \
- self.bitmapPool[name].GetSize() == (self.imageWidth, self.imageHeight):
- continue
- count += 1
- if len(raster) > maxLength:
- maxLength = len(raster)
-
- return count, maxLength
-
-
- def _loadMaps(self, mapType, maps, names, force, updateFunction,
- imageWidth, imageHeight, nprocs):
- """!Loads rasters/vectors (also from temporal dataset).
-
- Uses d.rast/d.vect and multiprocessing for parallel rendering
-
- @param mapType Must be "rast" or "vect"
- @param maps raster or vector maps to be loaded
- @param names names used as keys for bitmaps
- @param force load everything even though it is already there
- @param updateFunction function called for updating progress dialog
- @param imageWidth width of the image to render with d.rast or d.vect
- @param imageHeight height of the image to render with d.rast or d.vect
- @param nprocs number of procs to be used for rendering
- """
-
- count = 0
-
- # Variables for parallel rendering
- proc_count = 0
- proc_list = []
- queue_list = []
- name_list = []
-
- mapNum = len(maps)
-
- # create no data bitmap
- if None not in self.bitmapPool or force:
- self.bitmapPool[None] = self._createNoDataBitmap(imageWidth, imageHeight)
-
- for mapname, name in zip(maps, names):
- count += 1
-
- if not force and name in self.bitmapPool and \
- self.bitmapPool[name].GetSize() == (self.imageWidth, self.imageHeight):
- continue
-
- # Queue object for interprocess communication
- q = Queue()
- # The separate render process
- p = Process(target=mapRenderProcess, args=(mapType, mapname, imageWidth, imageHeight, q))
- p.start()
-
- queue_list.append(q)
- proc_list.append(p)
- name_list.append(name)
-
- proc_count += 1
-
- # Wait for all running processes and read/store the created images
- if proc_count == nprocs or count == mapNum:
- for i in range(len(name_list)):
- proc_list[i].join()
- filename = queue_list[i].get()
-
- # Unfortunately the png files must be read here,
- # since the swig wx objects can not be serialized by the Queue object :(
- if filename == None:
- self.bitmapPool[name_list[i]] = self._createNoDataBitmap(imageWidth, imageHeight,
- text="Failed to render")
- else:
- self.bitmapPool[name_list[i]] = wx.BitmapFromImage(wx.Image(filename))
- os.remove(filename)
-
- proc_count = 0
- proc_list = []
- queue_list = []
- name_list = []
-
- if updateFunction:
- keepGoing, skip = updateFunction(count, mapname)
- if not keepGoing:
- break
-
- def _load3D(self, commands, region, names, force, updateFunction):
- """!Load 3D view images using m.nviz.image.
-
- @param commands
- @param region
- @param names names used as keys for bitmaps
- @param force load everything even though it is already there
- @param updateFunction function called for updating progress dialog
- """
- ncols, nrows = self.imageWidth, self.imageHeight
- count = 0
- format = 'ppm'
- tempFile = grass.tempfile(False)
- tempFileFormat = tempFile + '.' + format
-
- os.environ['GRASS_REGION'] = grass.region_env(**region)
- # create no data bitmap
- if None not in self.bitmapPool or force:
- self.bitmapPool[None] = self._createNoDataBitmap(ncols, nrows)
- for command, name in zip(commands, names):
- if name in self.bitmapPool and force is False:
- continue
- count += 1
- # set temporary file
- command[1]['output'] = tempFile
- # set size
- command[1]['size'] = '%d,%d' % (ncols, nrows)
- # set format
- command[1]['format'] = format
-
- returncode, messages = RunCommand(getErrorMsg = True, prog = command[0], **command[1])
- if returncode != 0:
- self.bitmapPool[name] = wx.EmptyBitmap(ncols, nrows)
- continue
-
- self.bitmapPool[name] = wx.Bitmap(tempFileFormat)
-
- if updateFunction:
- keepGoing, skip = updateFunction(count, name)
- if not keepGoing:
- break
- 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:
- return wx.BitmapFromImage(autoCropImageFromFile(filename))
- 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
-
- @param mapType Must be "rast" or "vect"
- @param mapname raster or vector map name to be rendered
- @param width Width of the resulting image
- @param height Height of the resulting image
- @param fileQueue The inter process communication queue storing the file name of the image
- """
-
- # temporary file, we use python here to avoid calling g.tempfile for each render process
- fileHandler, filename = tempfile.mkstemp(suffix=".png")
- os.close(fileHandler)
-
- # Set the environment variables for this process
- _setEnvironment(width, height, filename, transparent=False)
-
- if mapType in ('rast', 'strds'):
- Debug.msg(1, "Render raster image " + str(filename))
- returncode, stdout, messages = read2_command('d.rast', map = mapname)
- elif mapType in ('vect', 'stvds'):
- Debug.msg(1, "Render vector image " + str(filename))
- returncode, stdout, messages = read2_command('d.vect', map = mapname)
- else:
- returncode = 1
- return
-
- if returncode != 0:
- grass.warning("Rendering failed:\n" + messages)
- fileQueue.put(None)
- os.remove(filename)
- return
-
- 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):
- self.bitmaps = {}
-
- def __getitem__(self, key):
- return self.bitmaps[key]
-
- def __setitem__(self, key, bitmap):
- self.bitmaps[key] = bitmap
-
- def __contains__(self, key):
- return key in self.bitmaps
-
- def Clear(self, usedKeys):
- """!Removes all bitmaps which are currently not used.
-
- @param usedKeys keys which are currently used
- """
- for key in self.bitmaps.keys():
- if key not in usedKeys and key is not None:
- del self.bitmaps[key]
-
-
-def read2_command(*args, **kwargs):
- kwargs['stdout'] = grass.PIPE
- kwargs['stderr'] = grass.PIPE
- ps = grass.start_command(*args, **kwargs)
- stdout, stderr = ps.communicate()
- return ps.returncode, stdout, stderr
Modified: grass/trunk/gui/wxpython/animation/nviztask.py
===================================================================
--- grass/trunk/gui/wxpython/animation/nviztask.py 2013-11-30 19:48:36 UTC (rev 58342)
+++ grass/trunk/gui/wxpython/animation/nviztask.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -6,12 +6,12 @@
Classes:
- nviztask::NvizTask
-(C) 2012 by the GRASS Development Team
+(C) 2013 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
- at author Anna Kratochvilova <kratochanna gmail.com>
+ at author Anna Petrasova <kratochanna gmail.com>
"""
import os
@@ -19,8 +19,7 @@
try:
import xml.etree.ElementTree as etree
except ImportError:
- import elementtree.ElementTree as etree # Python <= 2.4
-from pprint import pprint
+ import elementtree.ElementTree as etree # Python <= 2.4
if __name__ == '__main__':
sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "gui", "wxpython"))
@@ -29,8 +28,8 @@
from core.gcmd import RunCommand, GException
from core.utils import GetLayerNameFromCmd, CmdToTuple, _
from grass.script import task as gtask
-from grass.script import core as grass
+
class NvizTask:
def __init__(self):
self.task = None
@@ -42,7 +41,7 @@
self.filename = filename
try:
gxwXml = ProcessWorkspaceFile(etree.parse(self.filename))
- except Exception, e:
+ except Exception:
raise GException(_("Reading workspace file <%s> failed.\n"
"Invalid file, unable to parse XML document.") % filename)
# for display in gxwXml.displays:
@@ -71,20 +70,19 @@
if not layer['nviz']:
continue
- layerName, found = GetLayerNameFromCmd(layer['cmd'], fullyQualified = False,
- param = 'map')
+ layerName, found = GetLayerNameFromCmd(layer['cmd'], fullyQualified=False,
+ param='map')
if not found:
continue
if 'surface' in layer['nviz']:
- self._processSurface(layer['nviz']['surface'], mapName = layerName)
+ self._processSurface(layer['nviz']['surface'], mapName=layerName)
-
def _processSurface(self, surface, mapName):
self._setMultiTaskParam('elevation_map', mapName)
# attributes like color, shine, transparency
- attributes = ('color', 'shine', 'transp') # mask missing
+ attributes = ('color', 'shine', 'transp') # mask missing
parameters = (('color_map', 'color'),
('shininess_map', 'shininess_value'),
('transparency_map', 'transparency_value'))
@@ -128,7 +126,7 @@
def _processState(self, state):
color = state['view']['background']['color']
- self.task.set_param('bgcolor', self._join(color, delim = ':'))
+ self.task.set_param('bgcolor', self._join(color, delim=':'))
self.task.set_param('position', self._join((state['view']['position']['x'],
state['view']['position']['y'])))
self.task.set_param('height', state['iview']['height']['value'])
@@ -141,20 +139,17 @@
state['iview']['focus']['z'])))
self.task.set_param('light_position', self._join((state['light']['position']['x'],
state['light']['position']['y'],
- state['light']['position']['z']/100.)))
+ state['light']['position']['z'] / 100.)))
color = state['light']['color'][:3]
- self.task.set_param('light_color', self._join(color, delim = ':'))
+ self.task.set_param('light_color', self._join(color, delim=':'))
self.task.set_param('light_brightness', int(state['light']['bright']))
self.task.set_param('light_ambient', state['light']['ambient'])
-
-
-
def _setMultiTaskParam(self, param, value):
last = self.task.get_param(param)['value']
self.task.set_param(param, self._join((last, value)))
- def _join(self, toJoin, delim = ','):
+ def _join(self, toJoin, delim=','):
toJoin = filter(self._ignore, toJoin)
return delim.join(map(str, toJoin))
@@ -168,13 +163,22 @@
# params = self.task.get_list_params()
# parameter with 'map' name
# params = filter(lambda x: 'map' in x, params)
- return ('elevation_map', 'color_map', 'vline','vpoint')
+ return ('elevation_map', 'color_map', 'vline', 'vpoint')
- def GetCommandSeries(self, series, paramName):
+ def GetCommandSeries(self, layerList, paramName):
commands = []
if not self.task:
return commands
+ if len(layerList) > 1:
+ raise GException(_("Please add only one layer in the list."))
+ return
+ layer = layerList[0]
+ if hasattr(layer, 'maps'):
+ series = layer.maps
+ else:
+ raise GException(_("No map series nor space-time dataset is added."))
+
for value in series:
self.task.set_param(paramName, value)
# FIXME: we assume we want always default color map
@@ -182,8 +186,8 @@
self.task.set_param('color_map', '')
self.task.set_flag('overwrite', True)
self.task.set_param('output', 'tobechanged')
- cmd = self.task.get_cmd(ignoreErrors = False, ignoreRequired = False, ignoreDefault = True)
- commands.append(CmdToTuple(cmd))
+ cmd = self.task.get_cmd(ignoreErrors=False, ignoreRequired=False, ignoreDefault=True)
+ commands.append(cmd)
return commands
@@ -192,29 +196,25 @@
return None
self.task.set_flag('overwrite', True)
self.task.set_param('output', 'tobechanged')
- cmd = self.task.get_cmd(ignoreErrors = False, ignoreRequired = False, ignoreDefault = True)
+ cmd = self.task.get_cmd(ignoreErrors=False, ignoreRequired=False, ignoreDefault=True)
return CmdToTuple(cmd)
def GetRegion(self):
return self.region
-
def test():
-
nviz = NvizTask('/home/anna/testy/nviz/t12.gxw')
# nviz = NvizState('/home/anna/testy/nviz/t3.gxw')
-
+
# cmd = nviz.GetCommand()
- cmds = nviz.GetCommandSeries(['aspect','elevation'], 'color_map')
+ cmds = nviz.GetCommandSeries(['aspect', 'elevation'], 'color_map')
for cmd in cmds:
print cmd
- returncode, message = RunCommand(getErrorMsg = True, prog = cmd[0], **cmd[1])
+ returncode, message = RunCommand(getErrorMsg=True, prog=cmd[0], **cmd[1])
print returncode, message
if __name__ == '__main__':
test()
-
-
Added: grass/trunk/gui/wxpython/animation/provider.py
===================================================================
--- grass/trunk/gui/wxpython/animation/provider.py (rev 0)
+++ grass/trunk/gui/wxpython/animation/provider.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -0,0 +1,764 @@
+# -*- coding: utf-8 -*-
+"""!
+ at package animation.provider
+
+ at brief Animation files and bitmaps management
+
+Classes:
+ - mapwindow::BitmapProvider
+ - mapwindow::BitmapRenderer
+ - mapwindow::BitmapComposer
+ - mapwindow::DictRefCounter
+ - mapwindow::MapFilesPool
+ - mapwindow::BitmapPool
+ - mapwindow::CleanUp
+
+(C) 2013 by the GRASS Development Team
+
+This program is free software under the GNU General Public License
+(>=v2). Read the file COPYING that comes with GRASS for details.
+
+ at author Anna Petrasova <kratochanna gmail.com>
+"""
+import os
+import sys
+import wx
+import tempfile
+from multiprocessing import Process, Queue
+if __name__ == '__main__':
+ sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "gui", "wxpython"))
+
+from core.gcmd import RunCommand, GException
+from core.settings import UserSettings
+from core.debug import Debug
+from core.utils import _, CmdToTuple, autoCropImageFromFile
+
+from animation.utils import HashCmd, HashCmds, GetFileFromCmd, GetFileFromCmds
+
+import grass.script.core as gcore
+from grass.pydispatch.signal import Signal
+
+
+class BitmapProvider:
+ """!Class for management of image files and bitmaps.
+
+ There is one instance of this class in the application.
+ It handles both 2D and 3D animations.
+ """
+ def __init__(self, bitmapPool, mapFilesPool, tempDir,
+ imageWidth=640, imageHeight=480):
+
+ self._bitmapPool = bitmapPool
+ self._mapFilesPool = mapFilesPool
+ self.imageWidth = imageWidth # width of the image to render with d.rast or d.vect
+ self.imageHeight = imageHeight # height of the image to render with d.rast or d.vect
+ self._tempDir = tempDir
+
+ self._uniqueCmds = []
+ self._cmdsForComposition = []
+ self._opacities = []
+
+ self._cmds3D = []
+ self._regionFor3D = None
+
+ self._renderer = BitmapRenderer(self._mapFilesPool, self._tempDir,
+ self.imageWidth, self.imageHeight)
+ self._composer = BitmapComposer(self._tempDir, self._mapFilesPool,
+ self._bitmapPool, self.imageWidth,
+ self.imageHeight)
+ self.renderingStarted = Signal('BitmapProvider.renderingStarted')
+ self.compositionStarted = Signal('BitmapProvider.compositionStarted')
+ self.renderingContinues = Signal('BitmapProvider.renderingContinues')
+ self.compositionContinues = Signal('BitmapProvider.compositionContinues')
+ self.renderingFinished = Signal('BitmapProvider.renderingFinished')
+ self.compositionFinished = Signal('BitmapProvider.compositionFinished')
+ self.mapsLoaded = Signal('BitmapProvider.mapsLoaded')
+
+ self._renderer.renderingContinues.connect(self.renderingContinues)
+ self._composer.compositionContinues.connect(self.compositionContinues)
+
+ def SetCmds(self, cmdsForComposition, opacities):
+ """!Sets commands to be rendered with opacity levels.
+ Applies to 2D mode.
+
+ @param cmdsForComposition list of lists of command lists
+ [[['d.rast', 'map=elev_2001'], ['d.vect', 'map=points']], # g.pnmcomp
+ [['d.rast', 'map=elev_2002'], ['d.vect', 'map=points']],
+ ...]
+ @param opacities list of opacity values
+ """
+ Debug.msg(2, "BitmapProvider.SetCmds: {} lists".format(len(cmdsForComposition)))
+ self._cmdsForComposition.extend(cmdsForComposition)
+ self._uniqueCmds = self._getUniqueCmds()
+ self._opacities.extend(opacities)
+
+ def SetCmds3D(self, cmds, region):
+ """!Sets commands for 3D rendering.
+
+ @param cmds list of commands m.nviz.image (cmd as a list)
+ @param region for 3D rendering
+ """
+ Debug.msg(2, "BitmapProvider.SetCmds3D: {} commands".format(len(cmds)))
+ self._cmds3D = cmds
+ self._regionFor3D = region
+
+ def _getUniqueCmds(self):
+ """!Returns list of unique commands."""
+ unique = set()
+ for cmdList in self._cmdsForComposition:
+ for cmd in cmdList:
+ unique.add(tuple(cmd))
+ return list(unique)
+
+ def Unload(self):
+ """!Unloads currently loaded data.
+ Needs to be called before setting new data.
+ """
+ Debug.msg(2, "BitmapProvider.Unload")
+ if self._cmdsForComposition:
+ for cmd in self._uniqueCmds:
+ del self._mapFilesPool[HashCmd(cmd)]
+
+ for cmdList in self._cmdsForComposition:
+ del self._bitmapPool[HashCmds(cmdList)]
+ self._uniqueCmds = []
+ self._cmdsForComposition = []
+ self._opacities = []
+ if self._cmds3D:
+ self._cmds3D = []
+ self._regionFor3D = None
+
+ def _dryRender(self, uniqueCmds, force):
+ """!Determines how many files will be rendered.
+
+ @param uniqueCmds list of commands which are to be rendered
+ @param force if forced rerendering
+ """
+ count = 0
+ for cmd in uniqueCmds:
+ filename = GetFileFromCmd(self._tempDir, cmd)
+ if not force and os.path.exists(filename) and \
+ self._mapFilesPool.GetSize(HashCmd(cmd)) == (self.imageWidth, self.imageHeight):
+ continue
+ count += 1
+
+ Debug.msg(3, "BitmapProvider._dryRender: {} files to be rendered".format(count))
+
+ return count
+
+ def _dryCompose(self, cmdLists, 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 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):
+ continue
+ count += 1
+
+ Debug.msg(2, "BitmapProvider._dryCompose: {} files to be composed".format(count))
+
+ return count
+
+ def Load(self, force=False, bgcolor=(255, 255, 255), nprocs=4):
+ """!Loads data, both 2D and 3D. In case of 2D, it creates composites,
+ even when there is only 1 layer to compose (to be changed for speedup)
+
+ @param force if True reload all data, otherwise only missing data
+ @param bgcolor background color as a tuple of 3 values 0 to 255
+ @param nprocs number of procs to be used for rendering
+ """
+ Debug.msg(2, "BitmapProvider.Load: "
+ "force={}, bgcolor={}, nprocs={}".format(force, bgcolor, nprocs))
+ cmds = []
+ if self._uniqueCmds:
+ cmds.extend(self._uniqueCmds)
+ if self._cmds3D:
+ cmds.extend(self._cmds3D)
+
+ count = self._dryRender(cmds, 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,
+ 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)
+ self.compositionStarted.emit(count=count)
+ self._composer.Compose(self._cmdsForComposition, self._opacities,
+ bgcolor=bgcolor, force=force, nprocs=nprocs)
+ self.compositionFinished.emit()
+ if self._cmds3D:
+ for cmd in self._cmds3D:
+ self._bitmapPool[HashCmd(cmd)] = \
+ wx.Bitmap(GetFileFromCmd(self._tempDir, cmd))
+
+ self.mapsLoaded.emit()
+
+ def RequestStopRendering(self):
+ """!Requests to stop rendering/composition"""
+ Debug.msg(2, "BitmapProvider.RequestStopRendering")
+ self._renderer.RequestStopRendering()
+ self._composer.RequestStopComposing()
+
+ def GetBitmap(self, dataId):
+ """!Returns bitmap with given key
+ or 'no data' bitmap if no such key exists.
+
+ @param dataId name of bitmap
+ """
+ try:
+ bitmap = self._bitmapPool[dataId]
+ except KeyError:
+ bitmap = self._bitmapPool[None]
+ return bitmap
+
+ def WindowSizeChanged(self, width, height):
+ """!Sets size when size of related window changes."""
+ Debug.msg(5, "BitmapProvider.WindowSizeChanged: w={}, h={}".format(width, height))
+
+ self.imageWidth, self.imageHeight = width, height
+
+ self._composer.imageWidth = self._renderer.imageWidth = width
+ self._composer.imageHeight = self._renderer.imageHeight = height
+
+ def LoadOverlay(self, cmd):
+ """!Creates raster legend with d.legend
+
+ @param cmd d.legend command as a list
+
+ @return bitmap with legend
+ """
+ Debug.msg(5, "BitmapProvider.LoadOverlay: cmd={}".format(cmd))
+
+ fileHandler, filename = tempfile.mkstemp(suffix=".png")
+ os.close(fileHandler)
+ # Set the environment variables for this process
+ _setEnvironment(self.imageWidth, self.imageHeight, filename,
+ transparent=True, bgcolor=(0, 0, 0))
+
+ Debug.msg(1, "Render raster legend " + str(filename))
+ cmdTuple = CmdToTuple(cmd)
+ returncode, stdout, messages = read2_command(cmdTuple[0], **cmdTuple[1])
+
+ if returncode == 0:
+ return wx.BitmapFromImage(autoCropImageFromFile(filename))
+ else:
+ os.remove(filename)
+ raise GException(messages)
+
+
+class BitmapRenderer:
+ """!Class which renderes 2D and 3D images to files."""
+ def __init__(self, mapFilesPool, tempDir,
+ imageWidth, imageHeight):
+ self._mapFilesPool = mapFilesPool
+ self._tempDir = tempDir
+ self.imageWidth = imageWidth
+ self.imageHeight = imageHeight
+
+ self.renderingContinues = Signal('BitmapRenderer.renderingContinues')
+ self._stopRendering = False
+ self._isRendering = False
+
+ def Render(self, cmdList, regionFor3D, bgcolor, force, nprocs):
+ """!Renders all maps and stores files.
+
+ @param cmdList list of rendering commands to run
+ @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
+ @param nprocs number of procs to be used for rendering
+ """
+ Debug.msg(3, "BitmapRenderer.Render")
+ count = 0
+
+ # Variables for parallel rendering
+ proc_count = 0
+ proc_list = []
+ queue_list = []
+ cmd_list = []
+
+ filteredCmdList = []
+ for cmd in cmdList:
+ filename = GetFileFromCmd(self._tempDir, cmd)
+ if not force and os.path.exists(filename) and \
+ self._mapFilesPool.GetSize(HashCmd(cmd)) == (self.imageWidth, self.imageHeight):
+ # for reference counting
+ self._mapFilesPool[HashCmd(cmd)] = filename
+ continue
+ filteredCmdList.append(cmd)
+
+ mapNum = len(filteredCmdList)
+ stopped = False
+ self._isRendering = True
+ for cmd in filteredCmdList:
+ count += 1
+
+ # Queue object for interprocess communication
+ q = Queue()
+ # The separate render process
+ if cmd[0] == 'm.nviz.image':
+ p = Process(target=self.RenderProcess3D, args=(cmd, regionFor3D, bgcolor, q))
+ else:
+ p = Process(target=self.RenderProcess2D, args=(cmd, bgcolor, q))
+ p.start()
+
+ queue_list.append(q)
+ proc_list.append(p)
+ cmd_list.append(cmd)
+
+ proc_count += 1
+ # Wait for all running processes and read/store the created images
+ if proc_count == nprocs or count == mapNum:
+ 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.imageWidth, self.imageHeight))
+
+ proc_count = 0
+ proc_list = []
+ queue_list = []
+ cmd_list = []
+
+ self.renderingContinues.emit(current=count, text=_("Rendering map layers"))
+ if self._stopRendering:
+ self._stopRendering = False
+ stopped = True
+ break
+
+ self._isRendering = False
+ return not stopped
+
+ def RenderProcess2D(self, cmd, bgcolor, fileQueue):
+ """!Render raster or vector files as ppm image and write the
+ resulting ppm filename in the provided file queue
+
+ @param cmd d.rast/d.vect command as a list
+ @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
+ """
+ Debug.msg(3, "BitmapRenderer.RenderProcess2D: cmd={}".format(cmd))
+
+ filename = GetFileFromCmd(self._tempDir, cmd)
+ transparency = True
+
+ # Set the environment variables for this process
+ _setEnvironment(self.imageWidth, self.imageHeight, filename,
+ transparent=transparency, bgcolor=bgcolor)
+
+ Debug.msg(1, "Render image to file " + str(filename))
+ cmdTuple = CmdToTuple(cmd)
+ returncode, stdout, messages = read2_command(cmdTuple[0], **cmdTuple[1])
+ if returncode != 0:
+ gcore.warning("Rendering failed:\n" + messages)
+ fileQueue.put(None)
+ os.remove(filename)
+ return
+
+ fileQueue.put(filename)
+
+ def RenderProcess3D(self, cmd, region, bgcolor, fileQueue):
+ """!Renders image with m.nviz.image and writes the
+ resulting ppm filename in the provided file queue
+
+ @param cmd m.nviz.image command as a list
+ @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
+ """
+ Debug.msg(3, "BitmapRenderer.RenderProcess3D: cmd={}".format(cmd))
+
+ filename = GetFileFromCmd(self._tempDir, cmd)
+ os.environ['GRASS_REGION'] = gcore.region_env(**region)
+
+ Debug.msg(1, "Render image to file " + str(filename))
+ cmdTuple = CmdToTuple(cmd)
+ cmdTuple[1]['output'] = os.path.splitext(filename)[0]
+ # set size
+ cmdTuple[1]['size'] = '%d,%d' % (self.imageWidth, self.imageHeight)
+ # set format
+ cmdTuple[1]['format'] = 'ppm'
+ cmdTuple[1]['bgcolor'] = bgcolor = ':'.join([str(part) for part in bgcolor])
+ returncode, stdout, messages = read2_command(cmdTuple[0], **cmdTuple[1])
+ if returncode != 0:
+ gcore.warning("Rendering failed:\n" + messages)
+ fileQueue.put(None)
+ os.environ.pop('GRASS_REGION')
+ return
+
+ os.environ.pop('GRASS_REGION')
+ fileQueue.put(filename)
+
+ def RequestStopRendering(self):
+ """!Requests to stop rendering."""
+ if self._isRendering:
+ self._stopRendering = True
+
+
+class BitmapComposer:
+ """!Class which handles the composition of image files with g.pnmcomp."""
+ def __init__(self, tmpDir, mapFilesPool, bitmapPool,
+ imageWidth, imageHeight):
+ self._mapFilesPool = mapFilesPool
+ self._bitmapPool = bitmapPool
+ self._tmpDir = tmpDir
+ self.imageWidth = imageWidth
+ self.imageHeight = imageHeight
+
+ self.compositionContinues = Signal('BitmapComposer.composingContinues')
+ self._stopComposing = False
+ self._isComposing = False
+
+ def Compose(self, cmdLists, opacityList, bgcolor, force, nprocs):
+ """!Performs the composition of ppm/pgm files.
+
+ @param cmdLisst lists of rendering commands lists to compose
+ @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
+ @param nprocs number of procs to be used for rendering
+ """
+ Debug.msg(3, "BitmapComposer.Compose")
+
+ count = 0
+
+ # Variables for parallel rendering
+ proc_count = 0
+ proc_list = []
+ queue_list = []
+ 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):
+ # TODO: find a better way than to assign the same to increase the reference
+ self._bitmapPool[HashCmds(cmdList)] = self._bitmapPool[HashCmds(cmdList)]
+ continue
+ filteredCmdLists.append(cmdList)
+
+ num = len(filteredCmdLists)
+
+ self._isComposing = True
+ for cmdList in filteredCmdLists:
+ count += 1
+ # Queue object for interprocess communication
+ q = Queue()
+ # The separate render process
+ p = Process(target=self.CompositeProcess,
+ args=(cmdList, opacityList, bgcolor, q))
+ p.start()
+
+ queue_list.append(q)
+ proc_list.append(p)
+ cmd_lists.append(cmdList)
+
+ proc_count += 1
+
+ # Wait for all running processes and read/store the created images
+ if proc_count == nprocs or count == num:
+ for i in range(len(cmd_lists)):
+ proc_list[i].join()
+ filename = queue_list[i].get()
+ if filename is None:
+ self._bitmapPool[HashCmds(cmd_lists[i])] = \
+ createNoDataBitmap(self.imageWidth, self.imageHeight,
+ text="Failed to render")
+ else:
+ self._bitmapPool[HashCmds(cmd_lists[i])] = \
+ wx.BitmapFromImage(wx.Image(filename))
+ os.remove(filename)
+ proc_count = 0
+ proc_list = []
+ queue_list = []
+ cmd_lists = []
+
+ self.compositionContinues.emit(current=count, text=_("Overlaying map layers"))
+ if self._stopComposing:
+ self._stopComposing = False
+ break
+
+ self._isComposing = False
+
+ def CompositeProcess(self, cmdList, opacities, bgcolor, fileQueue):
+ """!Performs the composition of image ppm files and writes the
+ resulting ppm filename in the provided file queue
+
+ @param cmdList list of d.rast/d.vect commands
+ @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
+ storing the file name of the image
+ """
+ Debug.msg(3, "BitmapComposer.CompositeProcess")
+
+ maps = []
+ masks = []
+ for cmd in cmdList:
+ maps.append(GetFileFromCmd(self._tmpDir, cmd))
+ masks.append(GetFileFromCmd(self._tmpDir, cmd, 'pgm'))
+ filename = GetFileFromCmds(self._tmpDir, cmdList)
+ # Set the environment variables for this process
+ _setEnvironment(self.imageWidth, self.imageHeight, filename,
+ transparent=False, bgcolor=bgcolor)
+
+ opacities = [str(op / 100.) for op in opacities]
+ bgcolor = ':'.join([str(part) for part in bgcolor])
+ returncode, messages = RunCommand('g.pnmcomp',
+ getErrorMsg=True,
+ overwrite=True,
+ input='%s' % ",".join(reversed(maps)),
+ mask='%s' % ",".join(reversed(masks)),
+ opacity='%s' % ",".join(reversed(opacities)),
+ bgcolor=bgcolor,
+ width=self.imageWidth,
+ height=self.imageHeight,
+ output=filename)
+
+ if returncode != 0:
+ gcore.warning("Rendering composite failed:\n" + messages)
+ fileQueue.put(None)
+ os.remove(filename)
+ return
+
+ fileQueue.put(filename)
+
+ def RequestStopComposing(self):
+ """!Requests to stop the composition."""
+ if self._isComposing:
+ self._stopComposing = True
+
+
+class DictRefCounter:
+ """!Base class storing map files/bitmaps (emulates dictionary).
+ Counts the references to know which files/bitmaps to delete."""
+ def __init__(self):
+ self.dictionary = {}
+ self.referenceCount = {}
+
+ def __getitem__(self, key):
+ return self.dictionary[key]
+
+ def __setitem__(self, key, value):
+ self.dictionary[key] = value
+ if key not in self.referenceCount:
+ self.referenceCount[key] = 1
+ else:
+ self.referenceCount[key] += 1
+ Debug.msg(5, 'DictRefCounter.__setitem__: +1 for key {}'.format(key))
+
+ def __contains__(self, key):
+ return key in self.dictionary
+
+ def __delitem__(self, key):
+ self.referenceCount[key] -= 1
+ Debug.msg(5, 'DictRefCounter.__delitem__: -1 for key {}'.format(key))
+
+ def keys(self):
+ return self.dictionary.keys()
+
+ def Clear(self):
+ """!Clears items which are not needed any more."""
+ Debug.msg(4, 'DictRefCounter.Clear')
+ for key in self.dictionary.keys():
+ if key is not None:
+ if self.referenceCount[key] <= 0:
+ del self.dictionary[key]
+ del self.referenceCount[key]
+
+
+class MapFilesPool(DictRefCounter):
+ """!Stores rendered images as files."""
+ def __init__(self):
+ DictRefCounter.__init__(self)
+ self.size = {}
+
+ def SetSize(self, key, size):
+ self.size[key] = size
+
+ def GetSize(self, key):
+ return self.size[key]
+
+ def Clear(self):
+ """!Removes files which are not needed anymore.
+ Removes both ppm and pgm.
+ """
+ Debug.msg(4, 'MapFilesPool.Clear')
+
+ for key in self.dictionary.keys():
+ if self.referenceCount[key] <= 0:
+ name, ext = os.path.splitext(self.dictionary[key])
+ os.remove(self.dictionary[key])
+ if ext == '.ppm':
+ os.remove(name + '.pgm')
+ del self.dictionary[key]
+ del self.referenceCount[key]
+ del self.size[key]
+
+
+class BitmapPool(DictRefCounter):
+ """!Class storing bitmaps (emulates dictionary)"""
+ def __init__(self):
+ DictRefCounter.__init__(self)
+
+
+class CleanUp:
+ """!Responsible for cleaning up the files."""
+ def __init__(self, tempDir):
+ self._tempDir = tempDir
+
+ def __call__(self):
+ import shutil
+ if os.path.exists(self._tempDir):
+ try:
+ shutil.rmtree(self._tempDir)
+ Debug.msg(5, 'CleanUp: removed directory {}'.format(self._tempDir))
+ except OSError:
+ gcore.warning(_("Directory {} not removed.").format(self._tempDir))
+
+
+def _setEnvironment(width, height, filename, transparent, bgcolor):
+ """!Sets environmental variables for 2D rendering.
+
+ @param width rendering width
+ @param height rendering height
+ @param filename file name
+ @param transparent use transparency
+ @param bgcolor background color as a tuple of 3 values 0 to 255
+ """
+ Debug.msg(5, "_setEnvironment: width={}, height={}, "
+ "filename={}, transparent={}, bgcolor={}".format(width, height, filename,
+ transparent, bgcolor))
+
+ 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'] = '{:02x}{:02x}{:02x}'.format(*bgcolor)
+ os.environ['GRASS_TRUECOLOR'] = "TRUE"
+ if transparent:
+ os.environ['GRASS_TRANSPARENT'] = "TRUE"
+ else:
+ os.environ['GRASS_TRANSPARENT'] = "FALSE"
+ os.environ['GRASS_PNGFILE'] = str(filename)
+
+
+def createNoDataBitmap(imageWidth, imageHeight, text="No data"):
+ """!Creates 'no data' bitmap.
+
+ Used when requested bitmap is not available (loading data was not successful) or
+ we want to show 'no data' bitmap.
+
+ @param imageWidth image width
+ @param imageHeight image height
+ """
+ Debug.msg(4, "createNoDataBitmap: w={}, h={}, text={}".format(imageWidth,
+ imageHeight, text))
+ bitmap = wx.EmptyBitmap(imageWidth, imageHeight)
+ dc = wx.MemoryDC()
+ dc.SelectObject(bitmap)
+ dc.Clear()
+ text = _(text)
+ dc.SetFont(wx.Font(pointSize=40, family=wx.FONTFAMILY_SCRIPT,
+ style=wx.FONTSTYLE_NORMAL, weight=wx.FONTWEIGHT_BOLD))
+ tw, th = dc.GetTextExtent(text)
+ dc.DrawText(text, (imageWidth - tw) / 2, (imageHeight - th) / 2)
+ dc.SelectObject(wx.NullBitmap)
+ return bitmap
+
+
+def read2_command(*args, **kwargs):
+ kwargs['stdout'] = gcore.PIPE
+ kwargs['stderr'] = gcore.PIPE
+ ps = gcore.start_command(*args, **kwargs)
+ stdout, stderr = ps.communicate()
+ return ps.returncode, stdout, stderr
+
+
+def test():
+ import shutil
+
+ from core.layerlist import LayerList, Layer
+ from animation.data import AnimLayer
+ from animation.utils import layerListToCmdsMatrix
+
+ layerList = LayerList()
+ layer = AnimLayer()
+ layer.mapType = 'strds'
+ layer.name = 'JR'
+ layer.cmd = ['d.rast', 'map=elev_2007_1m']
+ layerList.AddLayer(layer)
+
+ layer = Layer()
+ layer.mapType = 'vect'
+ layer.name = 'buildings_2009_approx'
+ layer.cmd = ['d.vect', 'map=buildings_2009_approx',
+ 'color=grey']
+ layer.opacity = 50
+ layerList.AddLayer(layer)
+
+ bPool = BitmapPool()
+ mapFilesPool = MapFilesPool()
+
+ tempDir = '/tmp/test'
+ if os.path.exists(tempDir):
+ shutil.rmtree(tempDir)
+ os.mkdir(tempDir)
+ # comment this line to keep the directory after prgm ends
+# cleanUp = CleanUp(tempDir)
+# import atexit
+# atexit.register(cleanUp)
+
+ prov = BitmapProvider(bPool, mapFilesPool, tempDir,
+ imageWidth=640, imageHeight=480)
+ prov.renderingStarted.connect(
+ lambda count: sys.stdout.write("Total number of maps: {}\n".format(count)))
+ prov.renderingContinues.connect(
+ lambda current, text: sys.stdout.write("Current number: {}\n".format(current)))
+ prov.compositionStarted.connect(
+ lambda count: sys.stdout.write("Composition: total number of maps: {}\n".format(count)))
+ prov.compositionContinues.connect(
+ lambda current, text: sys.stdout.write("Composition: Current number: {}\n".format(current)))
+ prov.mapsLoaded.connect(
+ lambda: sys.stdout.write("Maps loading finished\n"))
+ cmdMatrix = layerListToCmdsMatrix(layerList)
+ prov.SetCmds(cmdMatrix, [l.opacity for l in layerList])
+ app = wx.App()
+
+ prov.Load(bgcolor=(13, 156, 230), nprocs=4)
+
+ for key in bPool.keys():
+ if key is not None:
+ bPool[key].SaveFile(os.path.join(tempDir, key + '.png'), wx.BITMAP_TYPE_PNG)
+# prov.Unload()
+# prov.SetCmds(cmdMatrix, [l.opacity for l in layerList])
+# prov.Load(bgcolor=(13, 156, 230))
+# prov.Unload()
+# newList = LayerList()
+# prov.SetCmds(layerListToCmdsMatrix(newList), [l.opacity for l in newList])
+# prov.Load()
+# prov.Unload()
+# mapFilesPool.Clear()
+# bPool.Clear()
+# print bPool.keys(), mapFilesPool.keys()
+
+
+if __name__ == '__main__':
+ test()
Property changes on: grass/trunk/gui/wxpython/animation/provider.py
___________________________________________________________________
Added: svn:mime-type
+ text/x-python
Added: svn:eol-style
+ native
Modified: grass/trunk/gui/wxpython/animation/temporal_manager.py
===================================================================
--- grass/trunk/gui/wxpython/animation/temporal_manager.py 2013-11-30 19:48:36 UTC (rev 58342)
+++ grass/trunk/gui/wxpython/animation/temporal_manager.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -27,13 +27,14 @@
import grass.temporal as tgis
from core.gcmd import GException
from core.utils import _
-from utils import validateTimeseriesName, TemporalType
+from animation.utils import validateTimeseriesName, TemporalType
class DataMode:
SIMPLE = 1
MULTIPLE = 2
+
class GranularityMode:
ONE_UNIT = 1
ORIGINAL = 2
@@ -60,7 +61,7 @@
def SetTemporalType(self, ttype):
self._temporalType = ttype
- temporalType = property(fget = GetTemporalType, fset = SetTemporalType)
+ temporalType = property(fget=GetTemporalType, fset=SetTemporalType)
def AddTimeSeries(self, timeseries, etype):
"""!Add space time dataset
@@ -90,13 +91,11 @@
ret, message = self._setTemporalState()
if not ret:
raise GException(message)
- if message: # warning
+ if message: # warning
return message
return None
-
-
def _setTemporalState(self):
# check for absolute x relative
absolute, relative = 0, 0
@@ -106,13 +105,14 @@
else:
relative += 1
if bool(absolute) == bool(relative):
- message = _("It is not allowed to display data with different temporal types (absolute and relative).")
+ message = _("It is not allowed to display data with different "
+ "temporal types (absolute and relative).")
return False, message
if absolute:
self.temporalType = TemporalType.ABSOLUTE
else:
self.temporalType = TemporalType.RELATIVE
-
+
# check for units for relative type
if relative:
units = set()
@@ -130,9 +130,10 @@
else:
point += 1
if bool(interval) == bool(point):
- message = _("You are going to display data with different temporal types of maps (interval and point)."
+ message = _("You are going to display data with different "
+ "temporal types of maps (interval and point)."
" It is recommended to use data of one temporal type to avoid confusion.")
- return True, message # warning
+ return True, message # warning
return True, None
@@ -140,14 +141,14 @@
"""!Returns temporal granularity of currently loaded timeseries."""
if self.dataMode == DataMode.SIMPLE:
gran = self.timeseriesInfo[self.timeseriesList[0]]['granularity']
- if 'unit' in self.timeseriesInfo[self.timeseriesList[0]]: # relative:
+ if 'unit' in self.timeseriesInfo[self.timeseriesList[0]]: # relative:
granNum = gran
unit = self.timeseriesInfo[self.timeseriesList[0]]['unit']
if self.granularityMode == GranularityMode.ONE_UNIT:
granNum = 1
else: # absolute
granNum, unit = gran.split()
- if self.granularityMode == GranularityMode.ONE_UNIT:
+ if self.granularityMode == GranularityMode.ONE_UNIT:
granNum = 1
return (int(granNum), unit)
@@ -174,25 +175,34 @@
granNum = 1
return (granNum, unit)
-
def GetLabelsAndMaps(self):
"""!Returns time labels and map names.
"""
mapLists = []
labelLists = []
+ labelListSet = set()
for dataset in self.timeseriesList:
grassLabels, listOfMaps = self._getLabelsAndMaps(dataset)
mapLists.append(listOfMaps)
- labelLists.append(grassLabels)
+ labelLists.append(tuple(grassLabels))
+ labelListSet.update(grassLabels)
+ # combine all timeLabels and fill missing maps with None
+ # BUT this does not work properly if the datasets have
+ # no temporal overlap! We would need to sample all datasets
+ # by a temporary dataset, I don't know how it would work with point data
+ if self.temporalType == TemporalType.ABSOLUTE:
+ # ('1996-01-01 00:00:00', '1997-01-01 00:00:00', 'year'),
+ timestamps = sorted(list(labelListSet), key=lambda x: x[0])
+ else:
+ # ('15', '16', u'years'),
+ timestamps = sorted(list(labelListSet), key=lambda x: float(x[0]))
- # choose longest time interval and fill missing maps with None
- timestamps = max(labelLists, key = len)
newMapLists = []
for mapList, labelList in zip(mapLists, labelLists):
newMapList = [None] * len(timestamps)
i = 0
# compare start time
- while timestamps[i][0] != labelList[0][0]: # compare
+ while timestamps[i][0] != labelList[0][0]: # compare
i += 1
newMapList[i:i + len(mapList)] = mapList
newMapLists.append(newMapList)
@@ -208,7 +218,7 @@
for both interval and point data.
"""
sp = tgis.dataset_factory(self.timeseriesInfo[timeseries]['etype'], timeseries)
- if sp.is_in_db() == False:
+ if sp.is_in_db() is False:
raise GException(_("Space time dataset <%s> not found.") % timeseries)
sp.select()
@@ -231,11 +241,11 @@
# after instance, there can be a gap or an interval
# if it is a gap we remove it and put there the previous instance instead
# however the first gap must be removed to avoid duplication
- maps = sp.get_registered_maps_as_objects_by_granularity(gran = gran)
+ maps = sp.get_registered_maps_as_objects_by_granularity(gran=gran)
if maps and len(maps) > 0:
lastTimeseries = None
- followsPoint = False # indicates that we are just after finding a point
- afterPoint = False # indicates that we are after finding a point
+ followsPoint = False # indicates that we are just after finding a point
+ afterPoint = False # indicates that we are after finding a point
for mymap in maps:
if isinstance(mymap, list):
if len(mymap) > 0:
@@ -276,9 +286,6 @@
listOfMaps.append(series)
timeLabels.append((str(start), end, unit))
- if self.temporalType == TemporalType.ABSOLUTE:
- timeLabels = self._pretifyTimeLabels(timeLabels)
-
return timeLabels, listOfMaps
def _pretifyTimeLabels(self, labels):
@@ -312,7 +319,7 @@
sp.select()
# Get ordered map list
maps = sp.get_registered_maps_as_objects()
-
+
if not sp.check_temporal_topology(maps):
raise GException(_("Topology of Space time dataset %s is invalid." % id))
@@ -326,6 +333,7 @@
infoDict[id]['map_time'] = sp.get_map_time()
infoDict[id]['maps'] = maps
+
def test():
from pprint import pprint
@@ -344,84 +352,87 @@
except GException, e:
print e
return
-
+
print '///////////////////////////'
gran = temp.GetGranularity()
print "granularity: " + str(gran)
pprint (temp.GetLabelsAndMaps())
-
def createAbsoluteInterval():
- grass.run_command('g.region', s=0, n=80, w=0, e=120, b=0, t=50, res=10, res3=10, flags = 'p3', quiet = True)
+ grass.run_command('g.region', s=0, n=80, w=0, e=120, b=0, t=50, res=10, res3=10,
+ flags='p3', quiet=True)
- grass.mapcalc(exp="prec_1 = rand(0, 550)", overwrite = True)
- grass.mapcalc(exp="prec_2 = rand(0, 450)", overwrite = True)
- grass.mapcalc(exp="prec_3 = rand(0, 320)", overwrite = True)
- grass.mapcalc(exp="prec_4 = rand(0, 510)", overwrite = True)
- grass.mapcalc(exp="prec_5 = rand(0, 300)", overwrite = True)
- grass.mapcalc(exp="prec_6 = rand(0, 650)", overwrite = True)
+ grass.mapcalc(exp="prec_1 = rand(0, 550)", overwrite=True)
+ grass.mapcalc(exp="prec_2 = rand(0, 450)", overwrite=True)
+ grass.mapcalc(exp="prec_3 = rand(0, 320)", overwrite=True)
+ grass.mapcalc(exp="prec_4 = rand(0, 510)", overwrite=True)
+ grass.mapcalc(exp="prec_5 = rand(0, 300)", overwrite=True)
+ grass.mapcalc(exp="prec_6 = rand(0, 650)", overwrite=True)
- grass.mapcalc(exp="temp_1 = rand(0, 550)", overwrite = True)
- grass.mapcalc(exp="temp_2 = rand(0, 450)", overwrite = True)
- grass.mapcalc(exp="temp_3 = rand(0, 320)", overwrite = True)
- grass.mapcalc(exp="temp_4 = rand(0, 510)", overwrite = True)
- grass.mapcalc(exp="temp_5 = rand(0, 300)", overwrite = True)
- grass.mapcalc(exp="temp_6 = rand(0, 650)", overwrite = True)
+ grass.mapcalc(exp="temp_1 = rand(0, 550)", overwrite=True)
+ grass.mapcalc(exp="temp_2 = rand(0, 450)", overwrite=True)
+ grass.mapcalc(exp="temp_3 = rand(0, 320)", overwrite=True)
+ grass.mapcalc(exp="temp_4 = rand(0, 510)", overwrite=True)
+ grass.mapcalc(exp="temp_5 = rand(0, 300)", overwrite=True)
+ grass.mapcalc(exp="temp_6 = rand(0, 650)", overwrite=True)
- n1 = grass.read_command("g.tempfile", pid = 1, flags = 'd').strip()
+ n1 = grass.read_command("g.tempfile", pid=1, flags='d').strip()
fd = open(n1, 'w')
fd.write(
- "prec_1|2001-01-01|2001-02-01\n"
- "prec_2|2001-04-01|2001-05-01\n"
- "prec_3|2001-05-01|2001-09-01\n"
- "prec_4|2001-09-01|2002-01-01\n"
- "prec_5|2002-01-01|2002-05-01\n"
- "prec_6|2002-05-01|2002-07-01\n"
- )
+ "prec_1|2001-01-01|2001-02-01\n"
+ "prec_2|2001-04-01|2001-05-01\n"
+ "prec_3|2001-05-01|2001-09-01\n"
+ "prec_4|2001-09-01|2002-01-01\n"
+ "prec_5|2002-01-01|2002-05-01\n"
+ "prec_6|2002-05-01|2002-07-01\n"
+ )
fd.close()
- n2 = grass.read_command("g.tempfile", pid = 2, flags = 'd').strip()
+ n2 = grass.read_command("g.tempfile", pid=2, flags='d').strip()
fd = open(n2, 'w')
fd.write(
- "temp_1|2000-10-01|2001-01-01\n"
- "temp_2|2001-04-01|2001-05-01\n"
- "temp_3|2001-05-01|2001-09-01\n"
- "temp_4|2001-09-01|2002-01-01\n"
- "temp_5|2002-01-01|2002-05-01\n"
- "temp_6|2002-05-01|2002-07-01\n"
- )
+ "temp_1|2000-10-01|2001-01-01\n"
+ "temp_2|2001-04-01|2001-05-01\n"
+ "temp_3|2001-05-01|2001-09-01\n"
+ "temp_4|2001-09-01|2002-01-01\n"
+ "temp_5|2002-01-01|2002-05-01\n"
+ "temp_6|2002-05-01|2002-07-01\n"
+ )
fd.close()
name1 = 'absinterval1'
name2 = 'absinterval2'
- grass.run_command('t.unregister', type = 'rast',
- maps='prec_1,prec_2,prec_3,prec_4,prec_5,prec_6,temp_1,temp_2,temp_3,temp_4,temp_5,temp_6')
+ grass.run_command('t.unregister', type='rast',
+ maps='prec_1,prec_2,prec_3,prec_4,prec_5,prec_6,'
+ 'temp_1,temp_2,temp_3,temp_4,temp_5,temp_6')
for name, fname in zip((name1, name2), (n1, n2)):
- grass.run_command('t.create', overwrite = True, type='strds',
- temporaltype='absolute', output=name,
+ grass.run_command('t.create', overwrite=True, type='strds',
+ temporaltype='absolute', output=name,
title="A test with input files", descr="A test with input files")
- grass.run_command('t.register', flags = 'i', input=name, file=fname, overwrite = True)
+ grass.run_command('t.register', flags='i', input=name, file=fname, overwrite=True)
return name1, name2
+
def createRelativeInterval():
- grass.run_command('g.region', s=0, n=80, w=0, e=120, b=0, t=50, res=10, res3=10, flags = 'p3', quiet = True)
+ grass.run_command('g.region', s=0, n=80, w=0, e=120, b=0, t=50, res=10, res3=10,
+ flags='p3', quiet=True)
- grass.mapcalc(exp="prec_1 = rand(0, 550)", overwrite = True)
- grass.mapcalc(exp="prec_2 = rand(0, 450)", overwrite = True)
- grass.mapcalc(exp="prec_3 = rand(0, 320)", overwrite = True)
- grass.mapcalc(exp="prec_4 = rand(0, 510)", overwrite = True)
- grass.mapcalc(exp="prec_5 = rand(0, 300)", overwrite = True)
- grass.mapcalc(exp="prec_6 = rand(0, 650)", overwrite = True)
+ grass.mapcalc(exp="prec_1 = rand(0, 550)", overwrite=True)
+ grass.mapcalc(exp="prec_2 = rand(0, 450)", overwrite=True)
+ grass.mapcalc(exp="prec_3 = rand(0, 320)", overwrite=True)
+ grass.mapcalc(exp="prec_4 = rand(0, 510)", overwrite=True)
+ grass.mapcalc(exp="prec_5 = rand(0, 300)", overwrite=True)
+ grass.mapcalc(exp="prec_6 = rand(0, 650)", overwrite=True)
- grass.mapcalc(exp="temp_1 = rand(0, 550)", overwrite = True)
- grass.mapcalc(exp="temp_2 = rand(0, 450)", overwrite = True)
- grass.mapcalc(exp="temp_3 = rand(0, 320)", overwrite = True)
- grass.mapcalc(exp="temp_4 = rand(0, 510)", overwrite = True)
- grass.mapcalc(exp="temp_5 = rand(0, 300)", overwrite = True)
- grass.mapcalc(exp="temp_6 = rand(0, 650)", overwrite = True)
+ grass.mapcalc(exp="temp_1 = rand(0, 550)", overwrite=True)
+ grass.mapcalc(exp="temp_2 = rand(0, 450)", overwrite=True)
+ grass.mapcalc(exp="temp_3 = rand(0, 320)", overwrite=True)
+ grass.mapcalc(exp="temp_4 = rand(0, 510)", overwrite=True)
+ grass.mapcalc(exp="temp_5 = rand(0, 300)", overwrite=True)
+ grass.mapcalc(exp="temp_6 = rand(0, 650)", overwrite=True)
- n1 = grass.read_command("g.tempfile", pid = 1, flags = 'd').strip()
+ n1 = grass.read_command("g.tempfile", pid=1, flags='d').strip()
fd = open(n1, 'w')
fd.write(
"prec_1|1|4\n"
@@ -430,92 +441,94 @@
"prec_4|10|11\n"
"prec_5|11|14\n"
"prec_6|14|17\n"
- )
+ )
fd.close()
- n2 = grass.read_command("g.tempfile", pid = 2, flags = 'd').strip()
+ n2 = grass.read_command("g.tempfile", pid=2, flags='d').strip()
fd = open(n2, 'w')
fd.write(
- "temp_1|1|4\n"
- "temp_2|4|7\n"
+ "temp_1|5|6\n"
+ "temp_2|6|7\n"
"temp_3|7|10\n"
"temp_4|10|11\n"
- "temp_5|11|14\n"
- "temp_6|14|17\n"
- )
+ "temp_5|11|18\n"
+ "temp_6|19|22\n"
+ )
fd.close()
name1 = 'relinterval1'
name2 = 'relinterval2'
- grass.run_command('t.unregister', type = 'rast',
- maps='prec_1,prec_2,prec_3,prec_4,prec_5,prec_6,temp_1,temp_2,temp_3,temp_4,temp_5,temp_6')
+ grass.run_command('t.unregister', type='rast',
+ maps='prec_1,prec_2,prec_3,prec_4,prec_5,prec_6,'
+ 'temp_1,temp_2,temp_3,temp_4,temp_5,temp_6')
for name, fname in zip((name1, name2), (n1, n2)):
- grass.run_command('t.create', overwrite = True, type='strds',
- temporaltype='relative', output=name,
+ grass.run_command('t.create', overwrite=True, type='strds',
+ temporaltype='relative', output=name,
title="A test with input files", descr="A test with input files")
- grass.run_command('t.register', flags = 'i', input = name, file = fname, unit = "years", overwrite = True)
+ grass.run_command('t.register', flags='i', input=name, file=fname, unit="years", overwrite=True)
return name1, name2
-
+
+
def createAbsolutePoint():
- grass.run_command('g.region', s=0, n=80, w=0, e=120, b=0, t=50, res=10, res3=10, flags = 'p3', quiet = True)
+ grass.run_command('g.region', s=0, n=80, w=0, e=120, b=0, t=50, res=10, res3=10,
+ flags='p3', quiet=True)
- grass.mapcalc(exp="prec_1 = rand(0, 550)", overwrite = True)
- grass.mapcalc(exp="prec_2 = rand(0, 450)", overwrite = True)
- grass.mapcalc(exp="prec_3 = rand(0, 320)", overwrite = True)
- grass.mapcalc(exp="prec_4 = rand(0, 510)", overwrite = True)
- grass.mapcalc(exp="prec_5 = rand(0, 300)", overwrite = True)
- grass.mapcalc(exp="prec_6 = rand(0, 650)", overwrite = True)
+ grass.mapcalc(exp="prec_1 = rand(0, 550)", overwrite=True)
+ grass.mapcalc(exp="prec_2 = rand(0, 450)", overwrite=True)
+ grass.mapcalc(exp="prec_3 = rand(0, 320)", overwrite=True)
+ grass.mapcalc(exp="prec_4 = rand(0, 510)", overwrite=True)
+ grass.mapcalc(exp="prec_5 = rand(0, 300)", overwrite=True)
+ grass.mapcalc(exp="prec_6 = rand(0, 650)", overwrite=True)
- n1 = grass.read_command("g.tempfile", pid = 1, flags = 'd').strip()
+ n1 = grass.read_command("g.tempfile", pid=1, flags='d').strip()
fd = open(n1, 'w')
fd.write(
- "prec_1|2001-01-01\n"
- "prec_2|2001-03-01\n"
- "prec_3|2001-04-01\n"
- "prec_4|2001-05-01\n"
- "prec_5|2001-08-01\n"
- "prec_6|2001-09-01\n"
- )
+ "prec_1|2001-01-01\n"
+ "prec_2|2001-03-01\n"
+ "prec_3|2001-04-01\n"
+ "prec_4|2001-05-01\n"
+ "prec_5|2001-08-01\n"
+ "prec_6|2001-09-01\n"
+ )
fd.close()
name = 'abspoint'
- grass.run_command('t.create', overwrite = True, type='strds',
- temporaltype='absolute', output=name,
+ grass.run_command('t.create', overwrite=True, type='strds',
+ temporaltype='absolute', output=name,
title="A test with input files", descr="A test with input files")
- grass.run_command('t.register', flags = 'i', input=name, file=n1, overwrite = True)
+ grass.run_command('t.register', flags='i', input=name, file=n1, overwrite=True)
return name
+
def createRelativePoint():
- grass.run_command('g.region', s=0, n=80, w=0, e=120, b=0, t=50, res=10, res3=10, flags = 'p3', quiet = True)
+ grass.run_command('g.region', s=0, n=80, w=0, e=120, b=0, t=50, res=10, res3=10,
+ flags='p3', quiet=True)
- grass.mapcalc(exp="prec_1 = rand(0, 550)", overwrite = True)
- grass.mapcalc(exp="prec_2 = rand(0, 450)", overwrite = True)
- grass.mapcalc(exp="prec_3 = rand(0, 320)", overwrite = True)
- grass.mapcalc(exp="prec_4 = rand(0, 510)", overwrite = True)
- grass.mapcalc(exp="prec_5 = rand(0, 300)", overwrite = True)
- grass.mapcalc(exp="prec_6 = rand(0, 650)", overwrite = True)
+ grass.mapcalc(exp="prec_1 = rand(0, 550)", overwrite=True)
+ grass.mapcalc(exp="prec_2 = rand(0, 450)", overwrite=True)
+ grass.mapcalc(exp="prec_3 = rand(0, 320)", overwrite=True)
+ grass.mapcalc(exp="prec_4 = rand(0, 510)", overwrite=True)
+ grass.mapcalc(exp="prec_5 = rand(0, 300)", overwrite=True)
+ grass.mapcalc(exp="prec_6 = rand(0, 650)", overwrite=True)
- n1 = grass.read_command("g.tempfile", pid = 1, flags = 'd').strip()
+ n1 = grass.read_command("g.tempfile", pid=1, flags='d').strip()
fd = open(n1, 'w')
fd.write(
- "prec_1|1\n"
- "prec_2|3\n"
- "prec_3|5\n"
- "prec_4|7\n"
- "prec_5|11\n"
- "prec_6|13\n"
- )
+ "prec_1|1\n"
+ "prec_2|3\n"
+ "prec_3|5\n"
+ "prec_4|7\n"
+ "prec_5|11\n"
+ "prec_6|13\n"
+ )
fd.close()
name = 'relpoint'
- grass.run_command('t.create', overwrite = True, type='strds',
+ grass.run_command('t.create', overwrite=True, type='strds',
temporaltype='relative', output=name,
title="A test with input files", descr="A test with input files")
- grass.run_command('t.register', unit="day", input=name, file=n1, overwrite = True)
+ grass.run_command('t.register', unit="day", input=name, file=n1, overwrite=True)
return name
if __name__ == '__main__':
test()
-
-
-
Modified: grass/trunk/gui/wxpython/animation/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/animation/toolbars.py 2013-11-30 19:48:36 UTC (rev 58342)
+++ grass/trunk/gui/wxpython/animation/toolbars.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -4,42 +4,53 @@
@brief Animation toolbars
Classes:
- - toolbars::MainToolbar(BaseToolbar):
- - toolbars::AnimationToolbar(BaseToolbar):
- - toolbars::MiscToolbar(BaseToolbar):
+ - toolbars::MainToolbar(BaseToolbar)
+ - toolbars::AnimationToolbar(BaseToolbar)
+ - toolbars::MiscToolbar(BaseToolbar)
+ - toolbars::AnimSimpleLmgrToolbar
-(C) 2012 by the GRASS Development Team
+(C) 2013 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
- at author Anna Kratochvilova <kratochanna gmail.com>
+ at author Anna Petrasova <kratochanna gmail.com>
"""
import wx
from gui_core.toolbars import BaseToolbar, BaseIcons
from icons.icon import MetaIcon
-
-from anim import ReplayMode
from core.utils import _
+from gui_core.simplelmgr import SimpleLmgrToolbar
+from animation.anim import ReplayMode
ganimIcons = {
- 'speed': MetaIcon(img = 'settings', label = _("Change animation speed")),
- 'playForward': MetaIcon(img = 'execute', label = _("Play forward")),
- 'playBack': MetaIcon(img = 'player-back', label = _("Play back")),
- 'stop': MetaIcon(img = 'player-stop', label = _("Stop")),
- 'pause': MetaIcon(img = 'player-pause', label = _("Pause")),
- 'oneDirectionReplay': MetaIcon(img = 'redraw', label = _("Repeat")),
- 'bothDirectionReplay': MetaIcon(img = 'player-repeat-back-forward',
- label = _("Play back and forward")),
- 'addAnimation': MetaIcon(img = 'layer-add', label = _("Add new animation"),
- desc = _("Add new animation")),
- 'editAnimation': MetaIcon(img = 'layer-more', label = _("Add, edit or remove animation"),
- desc = _("Add, edit or remove animation")),
- 'exportAnimation': MetaIcon(img = 'layer-export', label = _("Export animation"),
- desc = _("Export animation"))
- }
+ 'speed': MetaIcon(img='settings', label=_("Change animation speed")),
+ 'playForward': MetaIcon(img='execute', label=_("Play forward")),
+ 'playBack': MetaIcon(img='player-back', label=_("Play back")),
+ 'stop': MetaIcon(img='player-stop', label=_("Stop")),
+ 'pause': MetaIcon(img='player-pause', label=_("Pause")),
+ 'oneDirectionReplay': MetaIcon(img='redraw', label=_("Repeat")),
+ 'bothDirectionReplay': MetaIcon(img='player-repeat-back-forward',
+ label=_("Play back and forward")),
+ 'addAnimation': MetaIcon(img='layer-add', label=_("Add new animation"),
+ desc=_("Add new animation")),
+ 'editAnimation': MetaIcon(img='layer-more', label=_("Add, edit or remove animation"),
+ desc=_("Add, edit or remove animation")),
+ 'exportAnimation': MetaIcon(img='layer-export', label=_("Export animation"),
+ desc=_("Export animation"))
+}
+SIMPLE_LMGR_STDS = 128
+
+
+simpleLmgrIcons = {
+ 'addSeries': MetaIcon(img='mapset-add',
+ label=_("Add space-time dataset or series of map layers"),
+ desc=_("Add space-time dataset or series of map layers for animation")),
+}
+
+
class MainToolbar(BaseToolbar):
"""!Main toolbar (data management)
"""
@@ -47,12 +58,12 @@
"""!Main toolbar constructor
"""
BaseToolbar.__init__(self, parent)
-
+
self.InitToolbar(self._toolbarData())
# realize the toolbar
self.Realize()
-
+
def _toolbarData(self):
"""!Returns toolbar data (name, icon, handler)"""
# BaseIcons are a set of often used icons. It is possible
@@ -65,8 +76,10 @@
("reload", BaseIcons["render"],
self.parent.Reload),
("exportAnimation", icons["exportAnimation"],
- self.parent.OnExportAnimation),
- ))
+ self.parent.OnExportAnimation)
+ ))
+
+
class AnimationToolbar(BaseToolbar):
"""!Animation toolbar (to control animation)
"""
@@ -74,7 +87,7 @@
"""!Animation toolbar constructor
"""
BaseToolbar.__init__(self, parent)
-
+
self.InitToolbar(self._toolbarData())
# realize the toolbar
@@ -82,8 +95,7 @@
self.isPlayingForward = True
self.EnableAnimTools(False)
-
-
+
def _toolbarData(self):
"""!Returns toolbar data (name, icon, handler)"""
# BaseIcons are a set of often used icons. It is possible
@@ -107,8 +119,9 @@
wx.ITEM_CHECK),
(None, ),
("adjustSpeed", icons['speed'],
- self.parent.OnAdjustSpeed)
- ))
+ self.parent.OnAdjustSpeed)
+ ))
+
def OnPlayForward(self, event):
self.PlayForward()
self.parent.OnPlayForward(event)
@@ -132,7 +145,7 @@
self.EnableTool(self.stop, True)
self.ToggleTool(self.pause, False)
self.isPlayingForward = False
-
+
def OnPause(self, event):
self.Pause()
self.parent.OnPause(event)
@@ -187,6 +200,7 @@
self.EnableTool(self.pause, enable)
self.EnableTool(self.stop, enable)
+
class MiscToolbar(BaseToolbar):
"""!Toolbar with miscellaneous tools related to app
"""
@@ -194,15 +208,34 @@
"""!Toolbar constructor
"""
BaseToolbar.__init__(self, parent)
-
+
self.InitToolbar(self._toolbarData())
# realize the toolbar
self.Realize()
-
+
def _toolbarData(self):
"""!Toolbar data"""
return self._getToolbarData((("help", BaseIcons['help'],
self.parent.OnHelp),
- ("quit", BaseIcons['quit'],
+ ("quit", BaseIcons['quit'],
self.parent.OnCloseWindow),
- ))
\ No newline at end of file
+ ))
+
+
+class AnimSimpleLmgrToolbar(SimpleLmgrToolbar):
+ """!Simple layer manager toolbar for animation tool.
+ Allows to add space-time dataset or series of maps.
+ """
+ def __init__(self, parent, lmgrStyle):
+ SimpleLmgrToolbar.__init__(self, parent, lmgrStyle)
+
+ def _toolbarData(self):
+ data = SimpleLmgrToolbar._toolbarData(self)
+ if self._style & SIMPLE_LMGR_STDS:
+ data.insert(0, ('addSeries', simpleLmgrIcons['addSeries'],
+ self.parent.OnAddStds))
+ return data
+
+ def EnableTools(self, tools, enable=True):
+ for tool in tools:
+ self.EnableTool(getattr(self, tool), enable)
Modified: grass/trunk/gui/wxpython/animation/utils.py
===================================================================
--- grass/trunk/gui/wxpython/animation/utils.py 2013-11-30 19:48:36 UTC (rev 58342)
+++ grass/trunk/gui/wxpython/animation/utils.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -10,14 +10,16 @@
- utils::ReplayMode
-(C) 2012 by the GRASS Development Team
+(C) 2013 by the GRASS Development Team
This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.
- at author Anna Kratochvilova <kratochanna gmail.com>
+ at author Anna Perasova <kratochanna gmail.com>
"""
+import os
import wx
+import hashlib
try:
from PIL import Image
hasPIL = True
@@ -30,24 +32,29 @@
from core.gcmd import GException
from core.utils import _
+
class TemporalMode:
TEMPORAL = 1
NONTEMPORAL = 2
+
class TemporalType:
ABSOLUTE = 1
RELATIVE = 2
+
class Orientation:
FORWARD = 1
BACKWARD = 2
+
class ReplayMode:
ONESHOT = 1
REVERSE = 2
REPEAT = 3
-def validateTimeseriesName(timeseries, etype = 'strds'):
+
+def validateTimeseriesName(timeseries, etype='strds'):
"""!Checks if space time dataset exists and completes missing mapset.
Raises GException if dataset doesn't exist.
@@ -60,13 +67,13 @@
else:
raise GException(_("Space time dataset <%s> not found.") % timeseries)
-
for mapset, names in trastDict.iteritems():
if timeseries in names:
return timeseries + "@" + mapset
raise GException(_("Space time dataset <%s> not found.") % timeseries)
+
def validateMapNames(names, etype):
"""!Checks if maps exist and completes missing mapset.
@@ -95,18 +102,13 @@
def getRegisteredMaps(timeseries, etype):
- """!Returns list of maps registered in dataset"""
+ """!Returns list of maps registered in dataset.
+ Can throw ScriptError if the dataset doesn't exist.
+ """
timeseriesMaps = []
- if etype == 'strds':
- sp = tgis.SpaceTimeRasterDataset(ident=timeseries)
- elif etype == 'stvds':
- sp = tgis.SpaceTimeVectorDataset(ident=timeseries)
+ sp = tgis.open_old_space_time_dataset(timeseries, etype)
- 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)
+ rows = sp.get_registered_maps(columns="id", where=None, order="start_time")
timeseriesMaps = []
if rows:
for row in rows:
@@ -114,15 +116,84 @@
return timeseriesMaps
+def checkSeriesCompatibility(mapSeriesList=None, timeseriesList=None):
+ """!Checks whether time series (map series and stds) are compatible,
+ which means they have equal number of maps ad times (in case of stds).
+ This is needed within layer list, not within the entire animation tool.
+ Throws GException if these are incompatible.
+
+ @return number of maps for animation
+ """
+ timeseriesInfo = {'count': set(), 'temporalType': set(), 'mapType': set(),
+ 'mapTimes': set()}
+
+ if timeseriesList:
+ for stds, etype in timeseriesList:
+ sp = tgis.open_old_space_time_dataset(stds, etype)
+ mapType = sp.get_map_time() # interval, ...
+ tempType = sp.get_initial_values()[0] # absolute
+ timeseriesInfo['mapType'].add(mapType)
+ timeseriesInfo['temporalType'].add(tempType)
+ rows = sp.get_registered_maps_as_objects(where=None,
+ order="start_time")
+
+ if rows:
+ times = []
+ timeseriesInfo['count'].add(len(rows))
+ for row in rows:
+ if tempType == 'absolute':
+ time = row.get_absolute_time()
+ else:
+ time = row.get_relative_time()
+ times.append(time)
+ timeseriesInfo['mapTimes'].add(tuple(times))
+ else:
+ timeseriesInfo['mapTimes'].add(None)
+ timeseriesInfo['count'].add(None)
+
+ if len(timeseriesInfo['count']) > 1:
+ raise GException(_("The number of maps in space-time datasets "
+ "has to be the same."))
+
+ if len(timeseriesInfo['temporalType']) > 1:
+ raise GException(_("The temporal type (absolute/relative) of space-time datasets "
+ "has to be the same."))
+
+ if len(timeseriesInfo['mapType']) > 1:
+ raise GException(_("The map type (point/interval) of space-time datasets "
+ "has to be the same."))
+
+ if len(timeseriesInfo['mapTimes']) > 1:
+ raise GException(_("The temporal extents of maps in space-time datasets "
+ "have to be the same."))
+
+ if mapSeriesList:
+ count = set()
+ for mapSeries in mapSeriesList:
+ count.add(len(mapSeries))
+ if len(count) > 1:
+ raise GException(_("The number of maps to animate has to be "
+ "the same for each map series."))
+
+ if timeseriesList and list(count)[0] != list(timeseriesInfo['count'])[0]:
+ raise GException(_("The number of maps to animate has to be "
+ "the same as the number of maps in temporal dataset."))
+
+ if mapSeriesList:
+ return list(count)[0]
+ if timeseriesList:
+ return list(timeseriesInfo['count'])[0]
+
+
def ComputeScaledRect(sourceSize, destSize):
"""!Fits source rectangle into destination rectangle
by scaling and centering.
@code
-
+
>>> ComputeScaledRect(sourceSize = (10, 40), destSize = (100, 50))
{'height': 50, 'scale': 1.25, 'width': 13, 'x': 44, 'y': 0}
-
+
@endcode
@param sourceSize size of source rectangle
@@ -145,6 +216,7 @@
return {'width': width, 'height': height, 'x': x, 'y': y, 'scale': scale}
+
def RenderText(text, font):
"""!Renderes text with given font to bitmap."""
dc = wx.MemoryDC()
@@ -160,8 +232,80 @@
return bmp
+
def WxImageToPil(image):
"""!Converts wx.Image to PIL image"""
- pilImage = Image.new( 'RGB', (image.GetWidth(), image.GetHeight()) )
- pilImage.fromstring( image.GetData() )
+ pilImage = Image.new('RGB', (image.GetWidth(), image.GetHeight()))
+ pilImage.fromstring(image.GetData())
return pilImage
+
+
+def HashCmd(cmd):
+ """!Returns a hash from command given as a list."""
+ name = '_'.join(cmd)
+ return hashlib.sha1(name).hexdigest()
+
+
+def HashCmds(cmds):
+ """!Returns a hash from list of commands."""
+ name = '_'.join([item for sublist in cmds for item in sublist])
+ 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 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 layerListToCmdsMatrix(layerList):
+ """!Goes thru layerList and create matrix of commands
+ for the composition of map series.:
+
+ @returns matrix of cmds for composition
+ """
+ count = 0
+ for layer in layerList:
+ if layer.active and hasattr(layer, 'maps'):
+ # assuming the consistency of map number is checked already
+ count = len(layer.maps)
+ break
+ cmdsForComposition = []
+ for layer in layerList:
+ if not layer.active:
+ continue
+ if hasattr(layer, 'maps'):
+ for i, part in enumerate(layer.cmd):
+ if part.startswith('map='):
+ cmd = layer.cmd[:]
+ cmds = []
+ for map_ in layer.maps:
+ cmd[i] = 'map={}'.format(map_)
+ cmds.append(cmd[:])
+ cmdsForComposition.append(cmds)
+ else:
+ cmdsForComposition.append([layer.cmd] * count)
+
+ return zip(*cmdsForComposition)
+
+
+def sampleCmdMatrixAndCreateNames(cmdMatrix, sampledSeries):
+ """!Applies information from temporal sampling
+ to the command matrix."""
+ namesList = []
+ j = -1
+ lastName = ''
+ for name in sampledSeries:
+ if name is not None:
+ if lastName != name:
+ lastName = name
+ j += 1
+ namesList.append(HashCmds(cmdMatrix[j]))
+ else:
+ namesList.append(None)
+ assert(j == len(cmdMatrix) - 1)
+ return namesList
Modified: grass/trunk/gui/wxpython/core/layerlist.py
===================================================================
--- grass/trunk/gui/wxpython/core/layerlist.py 2013-11-30 19:48:36 UTC (rev 58342)
+++ grass/trunk/gui/wxpython/core/layerlist.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -191,7 +191,7 @@
self._mapTypes = ['rast', 'vect', 'rast3d']
self._internalTypes = {'rast': 'cell',
- 'vect': 'vect',
+ 'vect': 'vector',
'rast3d': 'grid3'}
def GetName(self):
Modified: grass/trunk/gui/wxpython/gui_core/simplelmgr.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/simplelmgr.py 2013-11-30 19:48:36 UTC (rev 58342)
+++ grass/trunk/gui/wxpython/gui_core/simplelmgr.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -49,7 +49,8 @@
"""!Simple layer manager class provides similar functionality to
Layertree, but it's just list, not tree."""
def __init__(self, parent, layerList,
- lmgrStyle=SIMPLE_LMGR_RASTER | SIMPLE_LMGR_VECTOR | SIMPLE_LMGR_TB_LEFT):
+ lmgrStyle=SIMPLE_LMGR_RASTER | SIMPLE_LMGR_VECTOR | SIMPLE_LMGR_TB_LEFT,
+ toolbarCls=None, modal=False):
wx.Panel.__init__(self, parent=parent, name='SimpleLayerManager')
self._style = lmgrStyle
@@ -57,9 +58,14 @@
self._checkList = wx.CheckListBox(self, style=wx.LB_EXTENDED)
# dialog windows held separately
self._dialogs = {}
- self._toolbar = SimpleLmgrToolbar(self, lmgrStyle=self._style)
+ if not toolbarCls:
+ toolbarCls = SimpleLmgrToolbar
+ self._toolbar = toolbarCls(self, lmgrStyle=self._style)
self._auimgr = wx.aui.AuiManager(self)
+
+ self._modal = modal
+
# needed in order not to change selection when moving layers
self._blockSelectionChanged = False
@@ -81,6 +87,7 @@
self._layout()
self.SetMinSize((200, -1))
+ self._update()
def _layout(self):
self._auimgr.AddPane(self._checkList,
@@ -132,16 +139,17 @@
Dummy layer is added first."""
cmd = ['d.rast']
layer = self.AddRaster(name='', cmd=cmd, hidden=True, dialog=None)
- GUI(parent=self, giface=None, modal=True).ParseCommand(cmd=cmd,
- completed=(self.GetOptData, layer, ''))
+ GUI(parent=self, giface=None, modal=self._modal).ParseCommand(cmd=cmd,
+ completed=(self.GetOptData, layer, ''))
event.Skip()
def OnAddVector(self, event):
"""!Opens d.vect dialog and adds layer.
Dummy layer is added first."""
cmd = ['d.vect']
+
layer = self.AddVector(name='', cmd=cmd, hidden=True, dialog=None)
- GUI(parent=self, giface=None, modal=True).ParseCommand(cmd=cmd,
+ GUI(parent=self, giface=None, modal=self._modal).ParseCommand(cmd=cmd,
completed=(self.GetOptData, layer, ''))
event.Skip()
@@ -150,7 +158,7 @@
Dummy layer is added first."""
cmd = ['d.rast3d']
layer = self.AddRast3d(name='', cmd=cmd, hidden=True, dialog=None)
- GUI(parent=self, giface=None, modal=True).ParseCommand(cmd=cmd,
+ GUI(parent=self, giface=None, modal=self._modal).ParseCommand(cmd=cmd,
completed=(self.GetOptData, layer, ''))
event.Skip()
@@ -160,7 +168,7 @@
for layer in layers:
self.layerRemoved.emit(index=self._layerList.GetLayerIndex(layer), layer=layer)
self._layerList.RemoveLayer(layer)
- if self._dialogs[layer]:
+ if layer in self._dialogs and self._dialogs[layer]:
self._dialogs[layer].Destroy()
self._update()
self.anyChange.emit()
@@ -208,8 +216,8 @@
def _layerChangeProperties(self, layer):
"""!Opens new module dialog or recycles it."""
- dlg = self._dialogs[layer]
- if dlg is not None:
+ if layer in self._dialogs:
+ dlg = self._dialogs[layer]
if dlg.IsShown():
dlg.Raise()
dlg.SetFocus()
@@ -217,7 +225,7 @@
dlg.Show()
else:
GUI(parent=self, giface=None,
- modal=False).ParseCommand(cmd=layer.cmd,
+ modal=self._modal).ParseCommand(cmd=layer.cmd,
completed=(self.GetOptData, layer, ''))
def OnLayerChangeOpacity(self, event):
@@ -351,7 +359,7 @@
direction = wx.TB_HORIZONTAL
BaseToolbar.__init__(self, parent, style=wx.NO_BORDER | direction)
- self.InitToolbar(self._toolbarData())
+ self.InitToolbar(self._getToolbarData(self._toolbarData()))
# realize the toolbar
self.Realize()
@@ -381,7 +389,7 @@
data.insert(0, ('addRaster', BaseIcons['addRast'],
self.parent.OnAddRaster))
- return self._getToolbarData(data)
+ return data
icons = {
Modified: grass/trunk/gui/wxpython/lmgr/frame.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/frame.py 2013-11-30 19:48:36 UTC (rev 58342)
+++ grass/trunk/gui/wxpython/lmgr/frame.py 2013-12-01 03:46:14 UTC (rev 58343)
@@ -1468,9 +1468,16 @@
if tree.GetLayerInfo(layer, key = 'type') == 'raster':
rasters.append(tree.GetLayerInfo(layer, key = 'maplayer').GetName())
if len(rasters) >= 2:
- frame.SetAnimations(raster = [rasters, None, None, None])
+ from core.layerlist import LayerList
+ from animation.data import AnimLayer
+ layerList = LayerList()
+ layer = AnimLayer()
+ layer.mapType = 'rast'
+ layer.name = ','.join(rasters)
+ layer.cmd = ['d.rast', 'map=']
+ layerList.AddLayer(layer)
+ frame.SetAnimations([layerList, None, None, None])
-
def OnHistogram(self, event):
"""!Init histogram display canvas and tools
"""
More information about the grass-commit
mailing list