nviz_animation.py 6.6 KB

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