/*========================================================================= Program: ParaView Module: $RCSfile$ Copyright (c) Kitware, Inc. All rights reserved. See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkSMAnimationSceneProxy.h" #include "vtkCompositeAnimationPlayer.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkPVXMLElement.h" #include "vtkSMAnimationScene.h" #include "vtkSMParaViewPipelineController.h" #include "vtkSMPropertyHelper.h" #include "vtkSMProxyIterator.h" #include "vtkSMTimeKeeperProxy.h" #include "vtkSMTrace.h" #include "vtkVector.h" namespace { // This is a terrible way to address BUG #0015407. What's happening is that // when state is being loaded the timekeeper gets updated timesteps which are // then correctly propagated to the animation scene, which then, correctly (I // might add) updates the start and end times. However all this happends // before the "EndTime"/"StartTime" properties from the XML state are loaded. // Hence they get set and loose the values just updated by the application, // instead use the old values from the state files. // This function will prune the EndTime/StartTime XML elements from the state // being loaded if they should not be loaded. void PruneEndTimesIfNeeded(vtkPVXMLElement* element, vtkSMAnimationScene* self) { vtkPVXMLElement* startTimeElement = NULL; vtkPVXMLElement* endTimeElement = NULL; int playMode = self? self->GetPlayMode() : vtkCompositeAnimationPlayer::SEQUENCE ; int lockEndTime = self? (self->GetLockEndTime()? 1 : 0) : 0; int lockStartTime = self? (self->GetLockStartTime()? 1 : 0) : 0; for (unsigned int cc=0, max = element->GetNumberOfNestedElements(); cc < max; cc++) { vtkPVXMLElement* cur = element->GetNestedElement(cc); if (cur && cur->GetName() && strcmp(cur->GetName(), "Property") == 0) { const char* name = cur->GetAttributeOrDefault("name", ""); if (strcmp(name, "EndTime") == 0) { endTimeElement = cur; } else if (strcmp(name, "StartTime") == 0) { startTimeElement = cur; } else if (strcmp(name, "PlayMode") == 0) { if (vtkPVXMLElement* valueElem = cur->FindNestedElementByName("Element")) { valueElem->GetScalarAttribute("value", &playMode); } } else if (strcmp(name, "LockEndTime") == 0) { if (vtkPVXMLElement* valueElem = cur->FindNestedElementByName("Element")) { valueElem->GetScalarAttribute("value", &lockEndTime); } } else if (strcmp(name, "LockStartTime") == 0) { if (vtkPVXMLElement* valueElem = cur->FindNestedElementByName("Element")) { valueElem->GetScalarAttribute("value", &lockStartTime); } } } } if (playMode == vtkCompositeAnimationPlayer::SNAP_TO_TIMESTEPS) { if (lockStartTime != 1 && startTimeElement) { element->RemoveNestedElement(startTimeElement); } if (lockEndTime != 1 && endTimeElement) { element->RemoveNestedElement(endTimeElement); } } } } vtkStandardNewMacro(vtkSMAnimationSceneProxy); //---------------------------------------------------------------------------- vtkSMAnimationSceneProxy::vtkSMAnimationSceneProxy() { } //---------------------------------------------------------------------------- vtkSMAnimationSceneProxy::~vtkSMAnimationSceneProxy() { } //---------------------------------------------------------------------------- void vtkSMAnimationSceneProxy::CreateVTKObjects() { if (this->ObjectsCreated) { return; } this->Superclass::CreateVTKObjects(); if (vtkObject* object = vtkObject::SafeDownCast(this->GetClientSideObject())) { object->AddObserver(vtkSMAnimationScene::UpdateStartEndTimesEvent, this, &vtkSMAnimationSceneProxy::OnUpdateStartEndTimesEvent); } } //---------------------------------------------------------------------------- void vtkSMAnimationSceneProxy::OnUpdateStartEndTimesEvent( vtkObject* object, unsigned long, void* calldata) { const vtkVector2d &range = *(reinterpret_cast(calldata)); vtkSMAnimationScene* caller = vtkSMAnimationScene::SafeDownCast(object); assert(caller == this->GetClientSideObject()); vtkSMPropertyHelper startTime(this, "StartTime"); vtkSMPropertyHelper endTime(this, "EndTime"); vtkVector2d newRange(startTime.GetAsDouble(0), endTime.GetAsDouble(0)); if (!caller->GetLockStartTime()) { newRange.SetX(range.GetX()); } if (!caller->GetLockEndTime()) { newRange.SetY(range.GetY()); } startTime.Set(newRange.GetX()); endTime.Set(newRange.GetY()); // XXX: What to do if the start or end time was locked and the suggested start // or end time would make the range invalid? this->UpdateVTKObjects(); } //---------------------------------------------------------------------------- bool vtkSMAnimationSceneProxy::UpdateAnimationUsingDataTimeSteps() { vtkSMProxy* timeKeeper = vtkSMPropertyHelper(this, "TimeKeeper").GetAsProxy(); if (!timeKeeper) { vtkWarningMacro("Failed to locate TimeKeeper proxy."); return false; } SM_SCOPED_TRACE(CallMethodIfPropertiesModified) .arg("proxy", this) .arg("methodname", "UpdateAnimationUsingDataTimeSteps") .arg("comment", "update animation scene based on data timesteps"); bool using_snap_to_timesteps_mode = false; vtkSMPropertyHelper timestepsHelper(timeKeeper, "TimestepValues"); if (timestepsHelper.GetNumberOfElements() > 1) { vtkSMPropertyHelper(this, "PlayMode").Set(vtkCompositeAnimationPlayer::SNAP_TO_TIMESTEPS); using_snap_to_timesteps_mode = true; } else { vtkSMPropertyHelper playmodeHelper(this, "PlayMode"); if (playmodeHelper.GetAsInt() == vtkCompositeAnimationPlayer::SNAP_TO_TIMESTEPS) { playmodeHelper.Set(vtkCompositeAnimationPlayer::SEQUENCE); } } this->UpdateVTKObjects(); // This will internally adjust the Start and End times for the animation scene // based of the Locks for the times. We not simply need to copy the info // property values. /// If the animation time is not in the scene time range, set it to the min /// value. double minTime = vtkSMPropertyHelper(this, "StartTime").GetAsDouble(); double maxTime = vtkSMPropertyHelper(this, "EndTime").GetAsDouble(); double animationTime = vtkSMPropertyHelper(this, "AnimationTime").GetAsDouble(); if (animationTime < minTime || animationTime > maxTime) { vtkSMPropertyHelper(this, "AnimationTime").Set(minTime); } else if (using_snap_to_timesteps_mode) { // BUG #15060. When using SNAP_TO_TIMESTEPS mode, ensure that the timestep // is "snapped". vtkSMPropertyHelper(this, "AnimationTime").Set( vtkSMTimeKeeperProxy::GetLowerBoundTimeStep(timeKeeper, animationTime)); } this->UpdateVTKObjects(); return true; } //---------------------------------------------------------------------------- vtkSMProxy* vtkSMAnimationSceneProxy::FindAnimationCue( vtkSMProxy* animatedProxy, const char* animatedPropertyName) { if (!animatedProxy || !animatedPropertyName) { return NULL; } vtkSMPropertyHelper cuesHelper(this, "Cues"); for (unsigned int cc=0, max = cuesHelper.GetNumberOfElements(); cc iter; iter->SetSessionProxyManager(animatedProxy->GetSessionProxyManager()); iter->SetModeToOneGroup(); for (iter->Begin(groupname.c_str()); !iter->IsAtEnd(); iter->Next()) { vtkSMProxy* cue = this->FindAnimationCue(iter->GetProxy(), animatedPropertyName); if (cue) { return cue; } } return NULL; } //---------------------------------------------------------------------------- int vtkSMAnimationSceneProxy::LoadXMLState( vtkPVXMLElement* element, vtkSMProxyLocator* locator) { PruneEndTimesIfNeeded(element, (this->ObjectsCreated? vtkSMAnimationScene::SafeDownCast(this->GetClientSideObject()): NULL)); return this->Superclass::LoadXMLState(element, locator);; } //---------------------------------------------------------------------------- void vtkSMAnimationSceneProxy::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); }