animation.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. """!
  2. @package nviz.animation
  3. @brief Nviz (3D view) animation
  4. Classes:
  5. - animation::Animation
  6. (C) 2011 by the GRASS Development Team
  7. This program is free software under the GNU General Public License
  8. (>=v2). Read the file COPYING that comes with GRASS for details.
  9. @author Anna Kratochvilova <kratochanna gmail.com>
  10. """
  11. import os
  12. import copy
  13. import wx
  14. from wx.lib.newevent import NewEvent
  15. wxAnimationFinished, EVT_ANIM_FIN = NewEvent()
  16. wxAnimationUpdateIndex, EVT_ANIM_UPDATE_IDX = NewEvent()
  17. class Animation:
  18. """!Class represents animation as a sequence of states (views).
  19. It enables to record, replay the sequence and finally generate
  20. all image files. Recording and replaying is based on timer events.
  21. There is no frame interpolation like in the Tcl/Tk based Nviz.
  22. """
  23. def __init__(self, mapWindow, timer):
  24. """!Animation constructor
  25. @param mapWindow glWindow where rendering takes place
  26. @param timer timer for recording and replaying
  27. """
  28. self.animationList = [] # view states
  29. self.timer = timer
  30. self.mapWindow = mapWindow
  31. self.actions = {'record': self.Record,
  32. 'play': self.Play}
  33. self.formats = ['ppm', 'tif'] # currently supported formats
  34. self.mode = 'record' # current mode (record, play, save)
  35. self.paused = False # recording/replaying paused
  36. self.currentFrame = 0 # index of current frame
  37. self.fps = 24 # user settings # Frames per second
  38. self.stopSaving = False # stop during saving images
  39. self.animationSaved = False # current animation saved or not
  40. def Start(self):
  41. """!Start recording/playing"""
  42. self.timer.Start(self.GetInterval())
  43. def Pause(self):
  44. """!Pause recording/playing"""
  45. self.timer.Stop()
  46. def Stop(self):
  47. """!Stop recording/playing"""
  48. self.timer.Stop()
  49. self.PostFinishedEvent()
  50. def Update(self):
  51. """!Record/play next view state (on timer event)"""
  52. self.actions[self.mode]()
  53. def Record(self):
  54. """!Record new view state"""
  55. self.animationList.append({'view' : copy.deepcopy(self.mapWindow.view),
  56. 'iview': copy.deepcopy(self.mapWindow.iview)})
  57. self.currentFrame += 1
  58. self.PostUpdateIndexEvent(index = self.currentFrame)
  59. self.animationSaved = False
  60. def Play(self):
  61. """!Render next frame"""
  62. if not self.animationList:
  63. self.Stop()
  64. return
  65. try:
  66. self.IterAnimation()
  67. except IndexError:
  68. # no more frames
  69. self.Stop()
  70. def IterAnimation(self):
  71. params = self.animationList[self.currentFrame]
  72. self.UpdateView(params)
  73. self.currentFrame += 1
  74. self.PostUpdateIndexEvent(index = self.currentFrame)
  75. def UpdateView(self, params):
  76. """!Update view data in map window and render"""
  77. toolWin = self.mapWindow.GetToolWin()
  78. toolWin.UpdateState(view = params['view'], iview = params['iview'])
  79. self.mapWindow.UpdateView()
  80. self.mapWindow.render['quick'] = True
  81. self.mapWindow.Refresh(False)
  82. def IsRunning(self):
  83. """!Test if timer is running"""
  84. return self.timer.IsRunning()
  85. def SetMode(self, mode):
  86. """!Start animation mode
  87. @param mode animation mode (record, play, save)
  88. """
  89. self.mode = mode
  90. def GetMode(self):
  91. """!Get animation mode (record, play, save)"""
  92. return self.mode
  93. def IsPaused(self):
  94. """!Test if animation is paused"""
  95. return self.paused
  96. def SetPause(self, pause):
  97. self.paused = pause
  98. def Exists(self):
  99. """!Returns if an animation has been recorded"""
  100. return bool(self.animationList)
  101. def GetFrameCount(self):
  102. """!Return number of recorded frames"""
  103. return len(self.animationList)
  104. def Clear(self):
  105. """!Clear all records"""
  106. self.animationList = []
  107. self.currentFrame = 0
  108. def GoToFrame(self, index):
  109. """!Render frame of given index"""
  110. if index >= len(self.animationList):
  111. return
  112. self.currentFrame = index
  113. params = self.animationList[self.currentFrame]
  114. self.UpdateView(params)
  115. def PostFinishedEvent(self):
  116. """!Animation ends"""
  117. toolWin = self.mapWindow.GetToolWin()
  118. event = wxAnimationFinished(mode = self.mode)
  119. wx.PostEvent(toolWin, event)
  120. def PostUpdateIndexEvent(self, index):
  121. """!Frame index changed, update tool window"""
  122. toolWin = self.mapWindow.GetToolWin()
  123. event = wxAnimationUpdateIndex(index = index, mode = self.mode)
  124. wx.PostEvent(toolWin, event)
  125. def StopSaving(self):
  126. """!Abort image files generation"""
  127. self.stopSaving = True
  128. def IsSaved(self):
  129. """"!Test if animation has been saved (to images)"""
  130. return self.animationSaved
  131. def SaveAnimationFile(self, path, prefix, format):
  132. """!Generate image files
  133. @param path path to direcory
  134. @param prefix file prefix
  135. @param format index of image file format
  136. """
  137. w, h = self.mapWindow.GetClientSizeTuple()
  138. toolWin = self.mapWindow.GetToolWin()
  139. self.currentFrame = 0
  140. self.mode = 'save'
  141. for params in self.animationList:
  142. if not self.stopSaving:
  143. self.UpdateView(params)
  144. filename = prefix + "_" + str(self.currentFrame) + '.' + self.formats[format]
  145. filepath = os.path.join(path, filename)
  146. self.mapWindow.SaveToFile(FileName = filepath, FileType = self.formats[format],
  147. width = w, height = h)
  148. self.currentFrame += 1
  149. wx.Yield()
  150. toolWin.UpdateFrameIndex(index = self.currentFrame, goToFrame = False)
  151. else:
  152. self.stopSaving = False
  153. break
  154. self.animationSaved = True
  155. self.PostFinishedEvent()
  156. def SetFPS(self, fps):
  157. """!Set Frames Per Second value
  158. @param fps frames per second
  159. """
  160. self.fps = fps
  161. def GetInterval(self):
  162. """!Return timer interval in ms"""
  163. return 1000. / self.fps