diff --git a/Documentation/release/dev/add-frame-options-extracts.md b/Documentation/release/dev/add-frame-options-extracts.md
new file mode 100644
index 0000000000000000000000000000000000000000..3b40e81f7660a025e2759f9f7cdb4efa49466f4f
--- /dev/null
+++ b/Documentation/release/dev/add-frame-options-extracts.md
@@ -0,0 +1,4 @@
+## Add Frame Parameters for Save Extracts
+
+`Save Extracts` now has `FrameWindow` and `FrameStride` parameters which allow you
+to limit the frame timesteps window and select a stride for it.
diff --git a/Qt/ApplicationComponents/pqSaveExtractsReaction.cxx b/Qt/ApplicationComponents/pqSaveExtractsReaction.cxx
index 7909b6126c5c798a9eb0a74419fa16adda76a9ee..1c53c78b3202745510aa069d610be50cd67c3dcc 100644
--- a/Qt/ApplicationComponents/pqSaveExtractsReaction.cxx
+++ b/Qt/ApplicationComponents/pqSaveExtractsReaction.cxx
@@ -37,8 +37,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "pqCoreUtilities.h"
#include "pqProgressManager.h"
#include "pqProxyWidgetDialog.h"
+
#include "vtkNew.h"
#include "vtkSMParaViewPipelineController.h"
+#include "vtkSMPropertyHelper.h"
#include "vtkSMSaveAnimationExtractsProxy.h"
#include "vtkSMSessionProxyManager.h"
#include "vtkSmartPointer.h"
@@ -62,6 +64,8 @@ bool pqSaveExtractsReaction::generateExtracts()
if (exporter)
{
controller->PreInitializeProxy(exporter);
+ auto scene = controller->FindAnimationScene(pxm->GetSession());
+ vtkSMPropertyHelper(exporter, "AnimationScene").Set(scene);
controller->PostInitializeProxy(exporter);
pqProxyWidgetDialog dialog(exporter, pqCoreUtilities::mainWidget());
@@ -72,7 +76,7 @@ bool pqSaveExtractsReaction::generateExtracts()
pqAnimationProgressDialog progress(
"Save Extracts Progress", "Abort", 0, 100, pqCoreUtilities::mainWidget());
progress.setWindowTitle("Saving Extracts ...");
- progress.setAnimationScene(controller->FindAnimationScene(pxm->GetSession()));
+ progress.setAnimationScene(scene);
progress.show();
auto appcore = pqApplicationCore::instance();
diff --git a/Remoting/Animation/Resources/animation.xml b/Remoting/Animation/Resources/animation.xml
index ce2195a74e4b3dbab2f5dd25b7c3f0c6b3215b9a..8ce3e87dfbc16c4e56a207b6952bf445b2765d7b 100644
--- a/Remoting/Animation/Resources/animation.xml
+++ b/Remoting/Animation/Resources/animation.xml
@@ -717,9 +717,50 @@
-
-
-
+
+
+
+
+
+
+ Frame rate in frames-per-second (FPS).
+
+
+
+
+
+
+ The stride which is used to extract the next frame.
+ E.g. 1, 2, 3, would have frame stride = 1, while 1, 3, 5 would have frame stride = 2.
+
+
+
+
+
+
+
+
+
+
+
+ Specify a window to save only a part of the animation.
+
+
+
+
+
+
+
+
diff --git a/Remoting/Animation/vtkSMSaveAnimationExtractsProxy.cxx b/Remoting/Animation/vtkSMSaveAnimationExtractsProxy.cxx
index ffe9c35b7505b598ca15cc0c753b4cc668d79e4c..adbab52695083d8b4aa2fd1ae016e67d82882771 100644
--- a/Remoting/Animation/vtkSMSaveAnimationExtractsProxy.cxx
+++ b/Remoting/Animation/vtkSMSaveAnimationExtractsProxy.cxx
@@ -14,6 +14,7 @@
=========================================================================*/
#include "vtkSMSaveAnimationExtractsProxy.h"
+#include "vtkCompositeAnimationPlayer.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkPVProgressHandler.h"
@@ -105,8 +106,7 @@ bool vtkSMSaveAnimationExtractsProxy::SaveExtracts()
{
auto session = this->GetSession();
- vtkNew controller;
- auto scene = controller->FindAnimationScene(session);
+ vtkSMProxy* scene = vtkSMPropertyHelper(this, "AnimationScene").GetAsProxy();
if (!scene)
{
vtkErrorMacro("No animation scene found. Cannot generate extracts.");
@@ -120,6 +120,48 @@ bool vtkSMSaveAnimationExtractsProxy::SaveExtracts()
vtkNew writer;
writer->Initialize(this);
writer->SetAnimationScene(scene);
+ writer->SetStride(vtkSMPropertyHelper(this, "FrameStride").GetAsInt());
+ // Convert frame window to PlaybackTimeWindow; FrameWindow is an integral
+ // value indicating the frame number of timestep; PlaybackTimeWindow is double
+ // values as animation time.
+ int frameWindow[2] = { 0, 0 };
+ vtkSMPropertyHelper(this, "FrameWindow").Get(frameWindow, 2);
+ double playbackTimeWindow[2] = { -1, 0 };
+ switch (vtkSMPropertyHelper(scene, "PlayMode").GetAsInt())
+ {
+ case vtkCompositeAnimationPlayer::SEQUENCE:
+ {
+ int numFrames = vtkSMPropertyHelper(scene, "NumberOfFrames").GetAsInt();
+ double startTime = vtkSMPropertyHelper(scene, "StartTime").GetAsDouble();
+ double endTime = vtkSMPropertyHelper(scene, "EndTime").GetAsDouble();
+ frameWindow[0] = frameWindow[0] < 0 ? 0 : frameWindow[0];
+ frameWindow[1] = frameWindow[1] >= numFrames ? numFrames - 1 : frameWindow[1];
+ playbackTimeWindow[0] =
+ startTime + ((endTime - startTime) * frameWindow[0]) / (numFrames - 1);
+ playbackTimeWindow[1] =
+ startTime + ((endTime - startTime) * frameWindow[1]) / (numFrames - 1);
+ }
+ break;
+ case vtkCompositeAnimationPlayer::SNAP_TO_TIMESTEPS:
+ {
+ vtkSMProxy* timeKeeper = vtkSMPropertyHelper(scene, "TimeKeeper").GetAsProxy();
+ vtkSMPropertyHelper tsValuesHelper(timeKeeper, "TimestepValues");
+ int numTS = tsValuesHelper.GetNumberOfElements();
+ frameWindow[0] = frameWindow[0] < 0 ? 0 : frameWindow[0];
+ frameWindow[1] = frameWindow[1] >= numTS ? numTS - 1 : frameWindow[1];
+ playbackTimeWindow[0] = tsValuesHelper.GetAsDouble(frameWindow[0]);
+ playbackTimeWindow[1] = tsValuesHelper.GetAsDouble(frameWindow[1]);
+ }
+
+ break;
+ case vtkCompositeAnimationPlayer::REAL_TIME:
+ // this should not happen. vtkSMSaveAnimationProxy::Prepare() should have
+ // changed the play mode to SEQUENCE or SNAP_TO_TIMESTEPS.
+ abort();
+ }
+ writer->SetStartFileCount(frameWindow[0]);
+ writer->SetPlaybackTimeWindow(playbackTimeWindow);
+
// register with progress handler so we monitor progress events.
session->GetProgressHandler()->RegisterProgressEvent(
writer.Get(), static_cast(this->GetGlobalID()));
diff --git a/Remoting/Animation/vtkSMSaveAnimationProxy.cxx b/Remoting/Animation/vtkSMSaveAnimationProxy.cxx
index 7d5d93c8dda755520b767982bbdaaad7b96d3e8a..145b3f6654fcb7ebe92e2dce0b5aff6324bb9b72 100644
--- a/Remoting/Animation/vtkSMSaveAnimationProxy.cxx
+++ b/Remoting/Animation/vtkSMSaveAnimationProxy.cxx
@@ -23,13 +23,11 @@
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkPVProgressHandler.h"
-#include "vtkPVRenderingCapabilitiesInformation.h"
#include "vtkPVServerInformation.h"
#include "vtkPVXMLElement.h"
#include "vtkRenderWindow.h"
#include "vtkSMAnimationScene.h"
#include "vtkSMAnimationSceneWriter.h"
-#include "vtkSMParaViewPipelineController.h"
#include "vtkSMProperty.h"
#include "vtkSMPropertyHelper.h"
#include "vtkSMProxyIterator.h"
diff --git a/Wrapping/Python/paraview/simple.py b/Wrapping/Python/paraview/simple.py
index a09fb6ec4b5560c4bc87d60db2a16172bd5d0a39..9955b3144501b736f3250d63c4210560bb2a7651 100644
--- a/Wrapping/Python/paraview/simple.py
+++ b/Wrapping/Python/paraview/simple.py
@@ -565,8 +565,11 @@ def SaveExtracts(**kwargs):
scene.UpdateAnimationUsingDataTimeSteps()
- pxm = servermanager.ProxyManager()
- proxy = servermanager._getPyProxy(pxm.NewProxy("misc", "SaveAnimationExtracts"))
+ controller = servermanager.ParaViewPipelineController()
+ proxy = servermanager.misc.SaveAnimationExtracts()
+ controller.PreInitializeProxy(proxy)
+ proxy.AnimationScene = scene
+ controller.PostInitializeProxy(proxy)
SetProperties(proxy, **kwargs)
return proxy.SaveExtracts()