0027764: Visualization - add functionality for animation of 3D camera and interactive...
authorkgv <kgv@opencascade.com>
Thu, 27 Oct 2016 14:20:38 +0000 (17:20 +0300)
committerapn <apn@opencascade.com>
Thu, 27 Oct 2016 14:21:02 +0000 (17:21 +0300)
Added classes AIS_Animation, AIS_AnimationCamera, AIS_AnimationObjectLocatio.

Draw Harness command vanimation has been modified to manage animation timeline.
Command vfit has been extended with option -noupdate.
Formatting of vviewparams command output has been improved.
Functionality of commands vlocreset, vlocmove, vloctranslate, vlocrotate,
vlocmirror, vlocscale has been merged into vlocation/vsetlocation.
vlocation now can print the current local transformation of the object.

v3d/ivtk test group does not call vfit anymore.

Fixed misprint in test cases bugs/vis/bug24623_3 and bug25532.

38 files changed:
src/AIS/AIS_Animation.cxx [new file with mode: 0644]
src/AIS/AIS_Animation.hxx [new file with mode: 0644]
src/AIS/AIS_AnimationCamera.cxx [new file with mode: 0644]
src/AIS/AIS_AnimationCamera.hxx [new file with mode: 0644]
src/AIS/AIS_AnimationObject.cxx [new file with mode: 0644]
src/AIS/AIS_AnimationObject.hxx [new file with mode: 0644]
src/AIS/AIS_AnimationTimer.cxx [new file with mode: 0644]
src/AIS/AIS_AnimationTimer.hxx [new file with mode: 0644]
src/AIS/AIS_InteractiveContext.cxx
src/AIS/FILES
src/Graphic3d/Graphic3d_Camera.cxx
src/Graphic3d/Graphic3d_Camera.hxx
src/NCollection/FILES
src/NCollection/NCollection_Lerp.hxx [new file with mode: 0644]
src/OSD/OSD_Chronometer.hxx
src/OSD/OSD_Timer.cxx
src/OSD/OSD_Timer.hxx
src/V3d/V3d_View.hxx
src/ViewerTest/ViewerTest.cxx
src/ViewerTest/ViewerTest_AutoUpdater.cxx
src/ViewerTest/ViewerTest_ObjectCommands.cxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx
src/gp/FILES
src/gp/gp_QuaternionNLerp.hxx
src/gp/gp_QuaternionSLerp.hxx
src/gp/gp_TrsfNLerp.hxx [new file with mode: 0644]
tests/bugs/vis/bug24623_3
tests/bugs/vis/bug25276
tests/bugs/vis/bug25532
tests/bugs/vis/bug26599
tests/v3d/anim/objects [new file with mode: 0644]
tests/v3d/anim/propeller [new file with mode: 0644]
tests/v3d/anim/rotate [new file with mode: 0644]
tests/v3d/anim/scale [new file with mode: 0644]
tests/v3d/anim/translate [new file with mode: 0644]
tests/v3d/end
tests/v3d/grids.list
tests/v3d/raytrace/bug26070

diff --git a/src/AIS/AIS_Animation.cxx b/src/AIS/AIS_Animation.cxx
new file mode 100644 (file)
index 0000000..32a055f
--- /dev/null
@@ -0,0 +1,306 @@
+// Created by: Anastasia BORISOVA
+// Copyright (c) 2016 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <AIS_Animation.hxx>
+
+#include <Standard_Assert.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(AIS_Animation, Standard_Transient)
+
+//=============================================================================
+//function : Constructor
+//purpose  :
+//=============================================================================
+AIS_Animation::AIS_Animation (const TCollection_AsciiString& theAnimationName)
+: myName (theAnimationName),
+  myState (AnimationState_Stopped),
+  myPtsStart (0.0),
+  myOwnDuration (0.0),
+  myChildrenDuration (0.0)
+{
+  //
+}
+
+//=============================================================================
+//function : ~AIS_Animation
+//purpose  :
+//=============================================================================
+AIS_Animation::~AIS_Animation()
+{
+  Clear();
+}
+
+//=============================================================================
+//function : Clear
+//purpose  :
+//=============================================================================
+void AIS_Animation::Clear()
+{
+  myAnimations.Clear();
+  myOwnDuration = 0.0;
+}
+
+//=============================================================================
+//function : Add
+//purpose  :
+//=============================================================================
+void AIS_Animation::Add (const Handle(AIS_Animation)& theAnimation)
+{
+  if (theAnimation.IsNull())
+  {
+    Standard_ProgramError::Raise ("AIS_Animation::Add() - attempt to add a NULL animation!");
+  }
+
+  for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anIter (myAnimations); anIter.More(); anIter.Next())
+  {
+    if (anIter.Value() == theAnimation)
+    {
+      UpdateTotalDuration();
+      return;
+    }
+  }
+
+  myAnimations.Append (theAnimation);
+  UpdateTotalDuration();
+}
+
+//=============================================================================
+//function : Find
+//purpose  :
+//=============================================================================
+Handle(AIS_Animation) AIS_Animation::Find (const TCollection_AsciiString& theAnimationName) const
+{
+  for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anIter (myAnimations); anIter.More(); anIter.Next())
+  {
+    if (anIter.Value()->Name() == theAnimationName)
+    {
+      return anIter.Value();
+    }
+  }
+  return Handle(AIS_Animation)();
+}
+
+//=============================================================================
+//function : Remove
+//purpose  :
+//=============================================================================
+Standard_Boolean AIS_Animation::Remove (const Handle(AIS_Animation)& theAnimation)
+{
+  for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anIter (myAnimations); anIter.More(); anIter.Next())
+  {
+    if (anIter.Value() == theAnimation)
+    {
+      myAnimations.Remove (anIter);
+      UpdateTotalDuration();
+      return Standard_True;
+    }
+  }
+  return Standard_False;
+}
+
+//=============================================================================
+//function : Replace
+//purpose  :
+//=============================================================================
+Standard_Boolean AIS_Animation::Replace (const Handle(AIS_Animation)& theAnimationOld,
+                                         const Handle(AIS_Animation)& theAnimationNew)
+{
+  for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anIter (myAnimations); anIter.More(); anIter.Next())
+  {
+    if (anIter.Value() == theAnimationOld)
+    {
+      anIter.ChangeValue() = theAnimationNew;
+      UpdateTotalDuration();
+      return Standard_True;
+    }
+  }
+  return Standard_False;
+}
+
+//=============================================================================
+//function : CopyFrom
+//purpose  :
+//=============================================================================
+void AIS_Animation::CopyFrom (const Handle(AIS_Animation)& theOther)
+{
+  myAnimations.Clear();
+  for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anIter (theOther->myAnimations); anIter.More(); anIter.Next())
+  {
+    myAnimations.Append (anIter.Value());
+  }
+  UpdateTotalDuration();
+  myPtsStart    = theOther->myPtsStart;
+  myOwnDuration = theOther->myOwnDuration;
+}
+
+//=============================================================================
+//function : UpdateTotalDuration
+//purpose  :
+//=============================================================================
+void AIS_Animation::UpdateTotalDuration()
+{
+  myChildrenDuration = 0.0;
+  for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anIter (myAnimations); anIter.More(); anIter.Next())
+  {
+    myChildrenDuration = Max (myChildrenDuration, anIter.Value()->StartPts() + anIter.Value()->Duration());
+  }
+}
+
+//=============================================================================
+//function : StartTimer
+//purpose  :
+//=============================================================================
+void AIS_Animation::StartTimer (const Standard_Real    theStartPts,
+                                const Standard_Real    thePlaySpeed,
+                                const Standard_Boolean theToUpdate)
+{
+  if (myTimer.IsNull())
+  {
+    myTimer = new AIS_AnimationTimer();
+  }
+  myTimer->Stop();
+  myTimer->Seek (theStartPts);
+  myTimer->SetPlaybackSpeed (thePlaySpeed);
+  Start (theToUpdate);
+}
+
+//=============================================================================
+//function : UpdateTimer
+//purpose  :
+//=============================================================================
+Standard_Real AIS_Animation::UpdateTimer()
+{
+  if (myTimer.IsNull())
+  {
+    Standard_ProgramError::Raise ("AIS_Animation::UpdateTimer() - timer was not created!");
+  }
+
+  const Standard_Real anElapsedTime = myTimer->ElapsedTime();
+  Update (anElapsedTime);
+  return anElapsedTime;
+}
+
+//=============================================================================
+//function : Start
+//purpose  :
+//=============================================================================
+void AIS_Animation::Start (const Standard_Boolean theToUpdate)
+{
+  UpdateTotalDuration();
+  myState = AnimationState_Started;
+  for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anIter (myAnimations); anIter.More(); anIter.Next())
+  {
+    anIter.ChangeValue()->Start (Standard_False);
+  }
+
+  if (theToUpdate)
+  {
+    const Standard_Real anElapsedTime = !myTimer.IsNull()
+                                       ? myTimer->ElapsedTime()
+                                       : 0.0;
+    Update (anElapsedTime);
+  }
+
+  if (!myTimer.IsNull())
+  {
+    myTimer->Start();
+  }
+}
+
+//=============================================================================
+//function : Pause
+//purpose  :
+//=============================================================================
+void AIS_Animation::Pause()
+{
+  myState = AnimationState_Paused;
+  if (!myTimer.IsNull())
+  {
+    myTimer->Pause();
+  }
+
+  for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anIter (myAnimations); anIter.More(); anIter.Next())
+  {
+    anIter.ChangeValue()->Stop();
+  }
+}
+
+//=============================================================================
+//function : Stop
+//purpose  :
+//=============================================================================
+void AIS_Animation::Stop()
+{
+  myState = AnimationState_Stopped;
+  if (!myTimer.IsNull())
+  {
+    myTimer->Stop();
+  }
+
+  for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anIter (myAnimations); anIter.More(); anIter.Next())
+  {
+    anIter.ChangeValue()->Stop();
+  }
+}
+
+//=============================================================================
+//function : Update
+//purpose  :
+//=============================================================================
+Standard_Boolean AIS_Animation::Update (const Standard_Real thePts)
+{
+  AIS_AnimationProgress aPosition;
+  aPosition.Pts             = thePts;
+  aPosition.LocalPts        = thePts - myPtsStart;
+  aPosition.LocalNormalized = HasOwnDuration()
+                            ? (aPosition.LocalPts / myOwnDuration)
+                            : 0.0;
+  aPosition.LocalNormalized = Max (0.0, aPosition.LocalNormalized);
+  aPosition.LocalNormalized = Min (1.0, aPosition.LocalNormalized);
+  updateWithChildren (aPosition);
+  return thePts < myPtsStart + Duration();
+}
+
+//=============================================================================
+//function : updateWithChildren
+//purpose  :
+//=============================================================================
+void AIS_Animation::updateWithChildren (const AIS_AnimationProgress& thePosition)
+{
+  if (thePosition.LocalPts < 0.0
+   || IsStopped())
+  {
+    return;
+  }
+
+  for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anIter (myAnimations); anIter.More(); anIter.Next())
+  {
+    const Handle(AIS_Animation)& anAnim = anIter.Value();
+    AIS_AnimationProgress aPosition = thePosition;
+    aPosition.LocalPts        = aPosition.LocalPts - anAnim->StartPts();
+    aPosition.LocalNormalized = anAnim->HasOwnDuration()
+                              ? (aPosition.LocalPts / anAnim->OwnDuration())
+                              : 0.0;
+    aPosition.LocalNormalized = Max (0.0, aPosition.LocalNormalized);
+    aPosition.LocalNormalized = Min (1.0, aPosition.LocalNormalized);
+    anAnim->updateWithChildren (aPosition);
+  }
+
+  if (thePosition.LocalPts >= Duration())
+  {
+    Stop();
+  }
+
+  update (thePosition);
+}
diff --git a/src/AIS/AIS_Animation.hxx b/src/AIS/AIS_Animation.hxx
new file mode 100644 (file)
index 0000000..9b192cc
--- /dev/null
@@ -0,0 +1,172 @@
+// Created by: Anastasia BORISOVA
+// Copyright (c) 2016 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _AIS_Animation_HeaderFile
+#define _AIS_Animation_HeaderFile
+
+#include <AIS_AnimationTimer.hxx>
+#include <NCollection_Sequence.hxx>
+#include <TCollection_AsciiString.hxx>
+
+//! Structure defining current animation progress.
+struct AIS_AnimationProgress
+{
+  Standard_Real Pts;             //!< global presentation timestamp
+  Standard_Real LocalPts;        //!< presentation within current animation
+  Standard_Real LocalNormalized; //!< normalized position within current animation within 0..1 range
+
+  AIS_AnimationProgress() : Pts (-1.0), LocalPts (-1.0), LocalNormalized (-1.0) {}
+};
+
+DEFINE_STANDARD_HANDLE(AIS_Animation, Standard_Transient)
+
+//! Class represents single animation.
+//! It is defined with:
+//! - Start time on the timeline started from 0, in seconds
+//! - Duration, in seconds
+//! - virtual method Update() for handling an update
+class AIS_Animation : public Standard_Transient
+{
+  DEFINE_STANDARD_RTTIEXT(AIS_Animation, Standard_Transient)
+public:
+
+  //! Creates empty animation.
+  Standard_EXPORT AIS_Animation (const TCollection_AsciiString& theAnimationName);
+
+  //! Destruct object, clear arguments
+  Standard_EXPORT virtual ~AIS_Animation();
+
+  //! Animation name.
+  const TCollection_AsciiString& Name() const { return myName; }
+
+public:
+
+  //! @return start time of the animation in the timeline
+  Standard_Real StartPts() const { return myPtsStart; }
+
+  //! Sets time limits for animation in the animation timeline
+  void SetStartPts (const Standard_Real thePtsStart) { myPtsStart = thePtsStart; }
+
+  //! @return duration of the animation in the timeline
+  Standard_Real Duration() const { return Max (myOwnDuration, myChildrenDuration); }
+
+  //! Update total duration considering all animations on timeline.
+  Standard_EXPORT void UpdateTotalDuration();
+
+  //! Return true if duration is defined.
+  Standard_Boolean HasOwnDuration() const { return myOwnDuration > 0.0; }
+
+  //! @return own duration of the animation in the timeline
+  Standard_Real OwnDuration() const { return myOwnDuration; }
+
+  //! Defines duration of the animation.
+  void SetOwnDuration (const Standard_Real theDuration) { myOwnDuration = theDuration; }
+
+  //! Add single animation to the timeline.
+  //! @param theAnimation input animation
+  Standard_EXPORT void Add (const Handle(AIS_Animation)& theAnimation);
+
+  //! Clear animation timeline - remove all animations from it.
+  Standard_EXPORT void Clear();
+
+  //! Return the child animation with the given name.
+  Standard_EXPORT Handle(AIS_Animation) Find (const TCollection_AsciiString& theAnimationName) const;
+
+  //! Remove the child animation.
+  Standard_EXPORT Standard_Boolean Remove (const Handle(AIS_Animation)& theAnimation);
+
+  //! Replace the child animation.
+  Standard_EXPORT Standard_Boolean Replace (const Handle(AIS_Animation)& theAnimationOld,
+                                            const Handle(AIS_Animation)& theAnimationNew);
+
+  //! Clears own children and then copy child animations from another object.
+  //! Copy also Start Time and Duration values.
+  Standard_EXPORT void CopyFrom (const Handle(AIS_Animation)& theOther);
+
+  //! Return sequence of child animations.
+  const NCollection_Sequence<Handle(AIS_Animation)>& Children() const { return myAnimations; }
+
+public:
+
+  //! Start animation with internally defined timer instance.
+  //! Calls ::Start() internally.
+  Standard_EXPORT virtual void StartTimer (const Standard_Real    theStartPts,
+                                           const Standard_Real    thePlaySpeed,
+                                           const Standard_Boolean theToUpdate);
+
+  //! Update single frame of animation, update timer state
+  //! @return current time of timeline progress.
+  Standard_EXPORT virtual Standard_Real UpdateTimer();
+
+  //! Return elapsed time.
+  Standard_Real ElapsedTime() const { return !myTimer.IsNull() ? myTimer->ElapsedTime() : 0.0; }
+
+public:
+
+  //! Start animation. This method changes status of the animation to Started.
+  //! This status defines whether animation is to be performed in the timeline or not.
+  //! @param theToUpdate call Update() method
+  Standard_EXPORT virtual void Start (const Standard_Boolean theToUpdate);
+
+  //! Pause the process timeline.
+  Standard_EXPORT virtual void Pause();
+
+  //! Stop animation. This method changed status of the animation to Stopped.
+  //! This status shows that animation will not be performed in the timeline or it is finished.
+  Standard_EXPORT virtual void Stop();
+
+  //! Check if animation is to be performed in the animation timeline.
+  //! @return True if it is stopped of finished.
+  bool IsStopped() { return myState != AnimationState_Started; }
+
+  //! Update single frame of animation, update timer state
+  //! @param thePts [in] the time moment within [0; Duration()]
+  //! @return True if timeline is in progress
+  Standard_EXPORT virtual Standard_Boolean Update (const Standard_Real thePts);
+
+protected:
+
+  //! Process one step of the animation according to the input time progress, including all children.
+  //! Calls also ::update() to update own animation.
+  Standard_EXPORT virtual void updateWithChildren (const AIS_AnimationProgress& thePosition);
+
+  //! Update the own animation to specified position - should be overridden by sub-class.
+  virtual void update (const AIS_AnimationProgress& theProgress) { (void )theProgress; }
+
+protected:
+
+  //! Defines animation state.
+  enum AnimationState
+  {
+    AnimationState_Started, //!< animation is in progress
+    AnimationState_Stopped, //!< animation is finished, force stopped or not started
+    AnimationState_Paused   //!< animation is paused and can be started from the pause moment
+  };
+
+protected:
+
+  Handle(AIS_AnimationTimer) myTimer;
+
+  TCollection_AsciiString myName;           //!< animation name
+  NCollection_Sequence<Handle(AIS_Animation)>
+                        myAnimations;       //!< sequence of child animations
+
+  AnimationState        myState;            //!< animation state - started, stopped of paused
+  Standard_Real         myPtsStart;         //!< time of start in the timeline
+  Standard_Real         myOwnDuration;      //!< duration of animation excluding children
+  Standard_Real         myChildrenDuration; //!< duration of animation including children
+
+};
+
+#endif // _AIS_Animation_HeaderFile
diff --git a/src/AIS/AIS_AnimationCamera.cxx b/src/AIS/AIS_AnimationCamera.cxx
new file mode 100644 (file)
index 0000000..b5c6935
--- /dev/null
@@ -0,0 +1,57 @@
+// Created by: Anastasia BORISOVA
+// Copyright (c) 2016 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <AIS_AnimationCamera.hxx>
+
+#include <Graphic3d_Camera.hxx>
+#include <Precision.hxx>
+#include <V3d_View.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(AIS_AnimationCamera, AIS_Animation)
+
+//=============================================================================
+//function : AIS_AnimationCamera
+//purpose  :
+//=============================================================================
+AIS_AnimationCamera::AIS_AnimationCamera (const TCollection_AsciiString& theAnimationName,
+                                          const Handle(V3d_View)& theView)
+: AIS_Animation (theAnimationName),
+  myView (theView)
+{
+  //
+}
+
+//=============================================================================
+//function : update
+//purpose  :
+//=============================================================================
+void AIS_AnimationCamera::update (const AIS_AnimationProgress& theProgress)
+{
+  if (myView.IsNull()
+   || myCamStart.IsNull()
+   || myCamEnd.IsNull())
+  {
+    return;
+  }
+
+  Handle(Graphic3d_Camera) aCamera = myView->Camera();
+
+  Graphic3d_CameraLerp aCamLerp (myCamStart, myCamEnd);
+  aCamLerp.Interpolate (theProgress.LocalNormalized, aCamera);
+
+  const Standard_Boolean aPrevImmUpdate = myView->SetImmediateUpdate (Standard_False);
+  myView->SetCamera (aCamera);
+  myView->SetImmediateUpdate (aPrevImmUpdate);
+  myView->Invalidate();
+}
diff --git a/src/AIS/AIS_AnimationCamera.hxx b/src/AIS/AIS_AnimationCamera.hxx
new file mode 100644 (file)
index 0000000..cd6d7e1
--- /dev/null
@@ -0,0 +1,63 @@
+// Created by: Anastasia BORISOVA
+// Copyright (c) 2016 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _AIS_AnimationCamera_HeaderFile
+#define _AIS_AnimationCamera_HeaderFile
+
+#include <AIS_Animation.hxx>
+
+class Graphic3d_Camera;
+class V3d_View;
+
+//! Camera animation.
+class AIS_AnimationCamera : public AIS_Animation
+{
+  DEFINE_STANDARD_RTTIEXT(AIS_AnimationCamera, AIS_Animation)
+public:
+
+  //! Main constructor.
+  Standard_EXPORT AIS_AnimationCamera (const TCollection_AsciiString& theAnimationName,
+                                       const Handle(V3d_View)& theView);
+
+  //! Return the target view.
+  const Handle(V3d_View)& View() const { return myView; }
+
+  //! Return camera start position.
+  const Handle(Graphic3d_Camera)& CameraStart() const { return myCamStart; }
+
+  //! Define camera start position.
+  void SetCameraStart (const Handle(Graphic3d_Camera)& theCameraStart) { myCamStart = theCameraStart; }
+
+  //! Return camera end position.
+  const Handle(Graphic3d_Camera)& CameraEnd() const { return myCamEnd; }
+
+  //! Define camera end position.
+  void SetCameraEnd (const Handle(Graphic3d_Camera)& theCameraEnd) { myCamEnd = theCameraEnd; }
+
+protected:
+
+  //! Update the progress.
+  Standard_EXPORT virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE;
+
+protected:
+
+  Handle(V3d_View)         myView;        //!< view to setup camera
+  Handle(Graphic3d_Camera) myCamStart;    //!< starting camera position
+  Handle(Graphic3d_Camera) myCamEnd;      //!< end camera position
+
+};
+
+DEFINE_STANDARD_HANDLE(AIS_AnimationCamera, AIS_Animation)
+
+#endif // _AIS_AnimationCamera_HeaderFile
diff --git a/src/AIS/AIS_AnimationObject.cxx b/src/AIS/AIS_AnimationObject.cxx
new file mode 100644 (file)
index 0000000..74ec0e4
--- /dev/null
@@ -0,0 +1,102 @@
+// Created by: Anastasia BORISOVA
+// Copyright (c) 2016 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <AIS_AnimationObject.hxx>
+
+#include <AIS_InteractiveContext.hxx>
+#include <TopLoc_Location.hxx>
+#include <V3d_Viewer.hxx>
+#include <V3d_View.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(AIS_AnimationObject, AIS_Animation)
+
+//=============================================================================
+//function : Constructor
+//purpose  :
+//=============================================================================
+AIS_AnimationObject::AIS_AnimationObject (const TCollection_AsciiString& theAnimationName,
+                                          const Handle(AIS_InteractiveContext)& theContext,
+                                          const Handle(AIS_InteractiveObject)&  theObject,
+                                          const gp_Trsf& theTrsfStart,
+                                          const gp_Trsf& theTrsfEnd)
+: AIS_Animation (theAnimationName),
+  myContext  (theContext),
+  myObject   (theObject),
+  myTrsfLerp (theTrsfStart, theTrsfEnd)
+{
+  //
+}
+
+//=============================================================================
+//function : update
+//purpose  :
+//=============================================================================
+void AIS_AnimationObject::update (const AIS_AnimationProgress& theProgress)
+{
+  if (myObject.IsNull())
+  {
+    return;
+  }
+
+  gp_Trsf aTrsf;
+  myTrsfLerp.Interpolate (theProgress.LocalNormalized, aTrsf);
+  if (!myContext.IsNull())
+  {
+    myContext->SetLocation (myObject, aTrsf);
+    invalidateViewer();
+  }
+  else
+  {
+    myObject->SetLocalTransformation (aTrsf);
+  }
+}
+
+//=============================================================================
+//function : invalidateViewer
+//purpose  :
+//=============================================================================
+void AIS_AnimationObject::invalidateViewer()
+{
+  if (myContext.IsNull())
+  {
+    return;
+  }
+
+  const Standard_Boolean isImmediate = myContext->CurrentViewer()->ZLayerSettings (myObject->ZLayer()).IsImmediate();
+  if (!isImmediate)
+  {
+    myContext->CurrentViewer()->Invalidate();
+    return;
+  }
+
+  // Invalidate immediate view only if it is going out of z-fit range.
+  // This might be sub-optimal performing this for each animated objects in case of many animated objects.
+  for (V3d_ListOfView::Iterator aDefViewIter = myContext->CurrentViewer()->DefinedViewIterator();
+       aDefViewIter.More(); aDefViewIter.Next())
+  {
+    const Handle(V3d_View)& aView = aDefViewIter.Value();
+    const Bnd_Box aMinMaxBox  = aView->View()->MinMaxValues (Standard_False);
+    const Bnd_Box aGraphicBox = aView->View()->MinMaxValues (Standard_True);
+    Standard_Real aZNear = 0.0;
+    Standard_Real aZFar  = 0.0;
+    if (aView->Camera()->ZFitAll (aDefViewIter.Value()->AutoZFitScaleFactor(), aMinMaxBox, aGraphicBox, aZNear, aZFar))
+    {
+      if (aZNear < aView->Camera()->ZNear()
+       || aZFar  > aView->Camera()->ZFar())
+      {
+        aDefViewIter.Value()->Invalidate();
+      }
+    }
+  }
+}
diff --git a/src/AIS/AIS_AnimationObject.hxx b/src/AIS/AIS_AnimationObject.hxx
new file mode 100644 (file)
index 0000000..5202c23
--- /dev/null
@@ -0,0 +1,60 @@
+// Created by: Anastasia BORISOVA
+// Copyright (c) 2016 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _AIS_AnimationObject_HeaderFile
+#define _AIS_AnimationObject_HeaderFile
+
+#include <AIS_Animation.hxx>
+#include <AIS_InteractiveContext.hxx>
+#include <gp_TrsfNLerp.hxx>
+
+//! Animation defining object transformation.
+class AIS_AnimationObject : public AIS_Animation
+{
+  DEFINE_STANDARD_RTTIEXT(AIS_AnimationObject, AIS_Animation)
+public:
+
+  //! Constructor with initialization.
+  //! Note that start/end transformations specify exactly local transformation of the object,
+  //! not the transformation to be applied to existing local transformation.
+  //! @param theAnimationName animation identifier
+  //! @param theContext       interactive context where object have been displayed
+  //! @param theObject        object to apply local transformation
+  //! @param theTrsfStart     local transformation at the start of animation (e.g. theObject->LocalTransformation())
+  //! @param theTrsfEnd       local transformation at the end   of animation
+  Standard_EXPORT AIS_AnimationObject (const TCollection_AsciiString& theAnimationName,
+                                       const Handle(AIS_InteractiveContext)& theContext,
+                                       const Handle(AIS_InteractiveObject)&  theObject,
+                                       const gp_Trsf& theTrsfStart,
+                                       const gp_Trsf& theTrsfEnd);
+
+protected:
+
+  //! Update the progress.
+  Standard_EXPORT virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE;
+
+  //! Invalidate the viewer for proper update.
+  Standard_EXPORT void invalidateViewer();
+
+protected:
+
+  Handle(AIS_InteractiveContext) myContext;   //!< context where object is displayed
+  Handle(AIS_InteractiveObject)  myObject;    //!< presentation object to set location
+  gp_TrsfNLerp                   myTrsfLerp;  //!< interpolation tool
+
+};
+
+DEFINE_STANDARD_HANDLE(AIS_AnimationObject, AIS_Animation)
+
+#endif // _AIS_AnimationObject_HeaderFile
diff --git a/src/AIS/AIS_AnimationTimer.cxx b/src/AIS/AIS_AnimationTimer.cxx
new file mode 100644 (file)
index 0000000..8d5d962
--- /dev/null
@@ -0,0 +1,74 @@
+// Created by: Kirill Gavrilov
+// Copyright (c) 2016 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <AIS_AnimationTimer.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(AIS_AnimationTimer, Standard_Transient)
+
+//=============================================================================
+//function : Pause
+//purpose  :
+//=============================================================================
+void AIS_AnimationTimer::Pause()
+{
+  myTimer.Stop();
+  myTimerFrom += myTimer.ElapsedTime() * myTimerSpeed;
+  myTimer.Reset();
+}
+
+//=============================================================================
+//function : Stop
+//purpose  :
+//=============================================================================
+void AIS_AnimationTimer::Stop()
+{
+  myTimer.Stop();
+  myTimer.Reset();
+  myTimerFrom = 0.0;
+}
+
+//=============================================================================
+//function : SetPlaybackSpeed
+//purpose  :
+//=============================================================================
+void AIS_AnimationTimer::SetPlaybackSpeed (const Standard_Real theSpeed)
+{
+  if (!myTimer.IsStarted())
+  {
+    myTimerSpeed = theSpeed;
+    return;
+  }
+
+  myTimer.Stop();
+  myTimerFrom += myTimer.ElapsedTime() * myTimerSpeed;
+  myTimer.Reset();
+  myTimerSpeed = theSpeed;
+  myTimer.Start();
+}
+
+//=============================================================================
+//function : SetPlaybackSpeed
+//purpose  :
+//=============================================================================
+void AIS_AnimationTimer::Seek (const Standard_Real theTime)
+{
+  const Standard_Boolean isStarted = myTimer.IsStarted();
+  myTimer.Stop();
+  myTimer.Reset();
+  myTimerFrom = theTime;
+  if (isStarted)
+  {
+    myTimer.Start();
+  }
+}
diff --git a/src/AIS/AIS_AnimationTimer.hxx b/src/AIS/AIS_AnimationTimer.hxx
new file mode 100644 (file)
index 0000000..14add51
--- /dev/null
@@ -0,0 +1,74 @@
+// Created by: Kirill Gavrilov
+// Copyright (c) 2016 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _AIS_AnimationTimer_HeaderFile
+#define _AIS_AnimationTimer_HeaderFile
+
+#include <OSD_Timer.hxx>
+#include <Standard_Transient.hxx>
+#include <Standard_Type.hxx>
+
+//! Auxiliary class defining the animation timer.
+class AIS_AnimationTimer : public Standard_Transient
+{
+  DEFINE_STANDARD_RTTIEXT(AIS_Animation, Standard_Transient)
+public:
+
+  //! Empty constructor.
+  AIS_AnimationTimer() : myTimerFrom (0.0), myTimerSpeed (1.0) {}
+
+  //! Return elapsed time in seconds.
+  Standard_Real ElapsedTime() const
+  {
+    return myTimerFrom + myTimer.ElapsedTime() * myTimerSpeed;
+  }
+
+  //! Return playback speed coefficient (1.0 means normal speed).
+  Standard_Real PlaybackSpeed() const { return myTimerSpeed; }
+
+  //! Setup playback speed coefficient.
+  Standard_EXPORT void SetPlaybackSpeed (const Standard_Real theSpeed);
+
+  //! Return true if timer has been started.
+  Standard_Boolean IsStarted() const
+  {
+    return myTimer.IsStarted();
+  }
+
+  //! Start the timer.
+  void Start()
+  {
+    myTimer.Start();
+  }
+
+  //! Pause the timer.
+  Standard_EXPORT void Pause();
+
+  //! Stop the timer.
+  Standard_EXPORT void Stop();
+
+  //! Seek the timer to specified position.
+  Standard_EXPORT void Seek (const Standard_Real theTime);
+
+protected:
+
+  OSD_Timer     myTimer;
+  Standard_Real myTimerFrom;
+  Standard_Real myTimerSpeed;
+
+};
+
+DEFINE_STANDARD_HANDLE(AIS_AnimationTimer, Standard_Transient)
+
+#endif // _AIS_AnimationTimer_HeaderFile
index 83089b8..70708ac 100644 (file)
@@ -2376,11 +2376,15 @@ void AIS_InteractiveContext::ClearGlobal (const Handle(AIS_InteractiveObject)& t
     aDefViewIter.Value()->View()->ChangeHiddenObjects()->Remove (theIObj.get());
   }
 
-  if (!myLastinMain.IsNull() && myLastinMain->IsSameSelectable (theIObj))
-    myLastinMain.Nullify();
-  if (!myLastPicked.IsNull() && myLastPicked->IsSameSelectable (theIObj))
-    myLastPicked.Nullify();
-  myMainPM->ClearImmediateDraw();
+  if (!myLastinMain.IsNull())
+  {
+    if (myLastinMain->IsSameSelectable (theIObj)
+     || myLastPicked->IsSameSelectable(theIObj))
+    {
+      myLastinMain.Nullify();
+      myMainPM->ClearImmediateDraw();
+    }
+  }
 
   if (theToUpdateviewer && aStatus->GraphicStatus() == AIS_DS_Displayed)
   {
index 254e329..aa6d72c 100644 (file)
@@ -1,5 +1,13 @@
 AIS.cxx
 AIS.hxx
+AIS_Animation.cxx
+AIS_Animation.hxx
+AIS_AnimationTimer.cxx
+AIS_AnimationTimer.hxx
+AIS_AnimationCamera.cxx
+AIS_AnimationCamera.hxx
+AIS_AnimationObject.cxx
+AIS_AnimationObject.hxx
 AIS_AngleDimension.cxx
 AIS_AngleDimension.hxx
 AIS_AttributeFilter.cxx
index f9f5c03..e46988d 100644 (file)
 // Alternatively, this file may be used under the terms of Open CASCADE
 // commercial license or contractual agreement.
 
-#include <gp_Pln.hxx>
-#include <Standard_ShortReal.hxx>
-
 #include <Graphic3d_Camera.hxx>
+
+#include <gp_Pln.hxx>
+#include <gp_QuaternionNLerp.hxx>
+#include <gp_QuaternionSLerp.hxx>
 #include <Graphic3d_Vec4.hxx>
 #include <Graphic3d_WorldViewProjState.hxx>
-
+#include <NCollection_Sequence.hxx>
+#include <Standard_ShortReal.hxx>
 #include <Standard_Atomic.hxx>
 #include <Standard_Assert.hxx>
 
-#include <NCollection_Sequence.hxx>
-
-
 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_Camera,Standard_Transient)
 
 namespace
@@ -61,6 +60,16 @@ namespace
     Standard_Real aExp = Floor (aLogRadix);
     return FLT_EPSILON * Pow (FLT_RADIX, aExp);
   }
+
+  //! Convert camera definition to Ax3
+  gp_Ax3 cameraToAx3 (const Graphic3d_Camera& theCamera)
+  {
+    const gp_Dir aBackDir(gp_Vec(theCamera.Center(), theCamera.Eye()));
+    const gp_Dir anXAxis (theCamera.Up().Crossed (aBackDir));
+    const gp_Dir anYAxis (aBackDir      .Crossed (anXAxis));
+    const gp_Dir aZAxis  (anXAxis       .Crossed (anYAxis));
+    return gp_Ax3 (gp_Pnt (0.0, 0.0, 0.0), aZAxis, anXAxis);
+  }
 }
 
 // =======================================================================
@@ -1298,3 +1307,84 @@ bool Graphic3d_Camera::ZFitAll (const Standard_Real theScaleFactor,
   theZFar  = aZFar;
   return true;
 }
+
+//=============================================================================
+//function : Interpolate
+//purpose  :
+//=============================================================================
+template<>
+Standard_EXPORT void NCollection_Lerp<Handle(Graphic3d_Camera)>::Interpolate (const double theT,
+                                                                              Handle(Graphic3d_Camera)& theCamera) const
+{
+  if (Abs (theT - 1.0) < Precision::Confusion())
+  {
+    // just copy end-point transformation
+    theCamera->Copy (myEnd);
+    return;
+  }
+
+  theCamera->Copy (myStart);
+  if (Abs (theT - 0.0) < Precision::Confusion())
+  {
+    return;
+  }
+
+  // apply rotation
+  {
+    gp_Ax3 aCamStart = cameraToAx3 (*myStart);
+    gp_Ax3 aCamEnd   = cameraToAx3 (*myEnd);
+    gp_Trsf aTrsfStart, aTrsfEnd;
+    aTrsfStart.SetTransformation (aCamStart, gp::XOY());
+    aTrsfEnd  .SetTransformation (aCamEnd,   gp::XOY());
+
+    gp_Quaternion aRotStart = aTrsfStart.GetRotation();
+    gp_Quaternion aRotEnd   = aTrsfEnd  .GetRotation();
+    gp_Quaternion aRotDelta = aRotEnd * aRotStart.Inverted();
+    gp_Quaternion aRot = gp_QuaternionNLerp::Interpolate (gp_Quaternion(), aRotDelta, theT);
+    gp_Trsf aTrsfRot;
+    aTrsfRot.SetRotation (aRot);
+    theCamera->Transform (aTrsfRot);
+  }
+
+  // apply translation
+  {
+    gp_XYZ aCenter  = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Center().XYZ(), myEnd->Center().XYZ(), theT);
+    gp_XYZ anEye    = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Eye().XYZ(),    myEnd->Eye().XYZ(),    theT);
+    gp_XYZ anAnchor = aCenter;
+    Standard_Real aKc = 0.0;
+
+    const Standard_Real aDeltaCenter = myStart->Center().Distance (myEnd->Center());
+    const Standard_Real aDeltaEye    = myStart->Eye()   .Distance (myEnd->Eye());
+    if (aDeltaEye <= gp::Resolution())
+    {
+      anAnchor = anEye;
+      aKc = 1.0;
+    }
+    else if (aDeltaCenter > gp::Resolution())
+    {
+      aKc = aDeltaCenter / (aDeltaCenter + aDeltaEye);
+
+      const gp_XYZ anAnchorStart = NCollection_Lerp<gp_XYZ>::Interpolate (myStart->Center().XYZ(), myStart->Eye().XYZ(), aKc);
+      const gp_XYZ anAnchorEnd   = NCollection_Lerp<gp_XYZ>::Interpolate (myEnd  ->Center().XYZ(), myEnd  ->Eye().XYZ(), aKc);
+      anAnchor = NCollection_Lerp<gp_XYZ>::Interpolate (anAnchorStart, anAnchorEnd, theT);
+    }
+
+    const gp_Vec        aDirEyeToCenter     = theCamera->Direction();
+    const Standard_Real aDistEyeCenterStart = myStart->Eye().Distance (myStart->Center());
+    const Standard_Real aDistEyeCenterEnd   = myEnd  ->Eye().Distance (myEnd  ->Center());
+    const Standard_Real aDistEyeCenter      = NCollection_Lerp<Standard_Real>::Interpolate (aDistEyeCenterStart, aDistEyeCenterEnd, theT);
+    aCenter = anAnchor + aDirEyeToCenter.XYZ() * aDistEyeCenter * aKc;
+    anEye   = anAnchor - aDirEyeToCenter.XYZ() * aDistEyeCenter * (1.0 - aKc);
+
+    theCamera->SetCenter (aCenter);
+    theCamera->SetEye    (anEye);
+  }
+
+  // apply scaling
+  if (Abs(myStart->Scale() - myEnd->Scale()) > Precision::Confusion()
+   && myStart->IsOrthographic())
+  {
+    const Standard_Real aScale = NCollection_Lerp<Standard_Real>::Interpolate (myStart->Scale(), myEnd->Scale(), theT);
+    theCamera->SetScale (aScale);
+  }
+}
index bc710d3..93b7cdb 100644 (file)
@@ -21,6 +21,7 @@
 #include <Graphic3d_Mat4.hxx>
 #include <Graphic3d_Vec3.hxx>
 #include <Graphic3d_WorldViewProjState.hxx>
+#include <NCollection_Lerp.hxx>
 
 #include <gp_Dir.hxx>
 #include <gp_Pnt.hxx>
@@ -665,4 +666,26 @@ public:
 
 DEFINE_STANDARD_HANDLE (Graphic3d_Camera, Standard_Transient)
 
+//! Linear interpolation tool for camera orientation and position.
+//! This tool interpolates camera parameters scale, eye, center, rotation (up and direction vectors) independently.
+//!
+//! Eye/Center interpolation is performed through defining an anchor point in-between Center and Eye.
+//! The anchor position is defined as point near to the camera point which has smaller translation part.
+//! The main idea is to keep the distance between Center and Eye
+//! (which will change if Center and Eye translation will be interpolated independently).
+//! E.g.:
+//!  - When both Center and Eye are moved at the same vector -> both will be just translated by straight line
+//!  - When Center is not moved -> camera Eye    will move around Center through arc
+//!  - When Eye    is not moved -> camera Center will move around Eye    through arc
+//!  - When both Center and Eye are move by different vectors -> transformation will be something in between,
+//!    and will try interpolate linearly the distance between Center and Eye.
+//!
+//! This transformation might be not in line with user expectations.
+//! In this case, application might define intermediate camera positions for interpolation
+//! or implement own interpolation logic.
+template<>
+Standard_EXPORT void NCollection_Lerp<Handle(Graphic3d_Camera)>::Interpolate (const double theT,
+                                                                              Handle(Graphic3d_Camera)& theResult) const;
+typedef NCollection_Lerp<Handle(Graphic3d_Camera)> Graphic3d_CameraLerp;
+
 #endif
index 32fe100..7027ac5 100755 (executable)
@@ -46,6 +46,7 @@ NCollection_IncAllocator.cxx
 NCollection_IncAllocator.hxx
 NCollection_IndexedDataMap.hxx
 NCollection_IndexedMap.hxx
+NCollection_Lerp.hxx
 NCollection_List.hxx
 NCollection_ListNode.hxx
 NCollection_LocalArray.hxx
diff --git a/src/NCollection/NCollection_Lerp.hxx b/src/NCollection/NCollection_Lerp.hxx
new file mode 100644 (file)
index 0000000..3453a05
--- /dev/null
@@ -0,0 +1,71 @@
+// Created by: Kirill GAVRILOV
+// Copyright (c) 2016 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _NCollection_Lerp_HeaderFile
+#define _NCollection_Lerp_HeaderFile
+
+//! Simple linear interpolation tool (also known as mix() in GLSL).
+//! The main purpose of this template class is making interpolation routines more readable.
+template<class T>
+class NCollection_Lerp
+{
+public:
+  //! Compute interpolated value between two values.
+  //! @param theStart first  value
+  //! @param theEnd   second value
+  //! @param theT normalized interpolation coefficient within [0, 1] range,
+  //!             with 0 pointing to theStart and 1 to theEnd.
+  static T Interpolate (const T& theStart,
+                        const T& theEnd,
+                        double theT)
+  {
+    T aResult;
+    NCollection_Lerp aLerp (theStart, theEnd);
+    aLerp.Interpolate (theT, aResult);
+    return aResult;
+  }
+
+public:
+
+  //! Empty constructor
+  NCollection_Lerp() : myStart(), myEnd() {}
+
+  //! Main constructor.
+  NCollection_Lerp (const T& theStart, const T& theEnd)
+  {
+    Init (theStart, theEnd);
+  }
+
+  //! Initialize values.
+  void Init (const T& theStart, const T& theEnd)
+  {
+    myStart = theStart;
+    myEnd   = theEnd;
+  }
+
+  //! Compute interpolated value between two values.
+  //! @param theT normalized interpolation coefficient within [0, 1] range,
+  //!             with 0 pointing to first value and 1 to the second value.
+  //! @param theResult [out] interpolated value
+  void Interpolate (double theT, T& theResult) const
+  {
+    theResult = (1.0 - theT) * myStart + theT * myEnd;
+  }
+
+private:
+  T myStart;
+  T myEnd;
+};
+
+#endif // _NCollection_Lerp_HeaderFile
index 4c8c77b..8942d61 100644 (file)
@@ -48,7 +48,10 @@ public:
   //! process (all threads, and completed children) is measured.
   Standard_EXPORT OSD_Chronometer(const Standard_Boolean ThisThreadOnly = Standard_False);
   Standard_EXPORT virtual ~OSD_Chronometer();
-  
+
+  //! Return true if timer has been started.
+  Standard_Boolean IsStarted() const { return !Stopped; }
+
   //! Stops and Reinitializes the Chronometer.
   Standard_EXPORT virtual void Reset();
   
index 93ca383..412a7ac 100644 (file)
@@ -104,6 +104,18 @@ static void Compute (Standard_Real     Time,
 
 //=======================================================================
 //function : Reset
+//purpose  :
+//=======================================================================
+
+void OSD_Timer::Reset (const Standard_Real theTimeElapsedSec)
+{
+  TimeStart = 0.0;
+  TimeCumul = theTimeElapsedSec;
+  OSD_Chronometer::Reset();
+}
+
+//=======================================================================
+//function : Reset
 //purpose  : 
 //=======================================================================
 
index 3d6162e..5ff9e8a 100644 (file)
@@ -44,11 +44,13 @@ public:
 
   DEFINE_STANDARD_ALLOC
 
-  
   //! Builds a Chronometer initialized and stopped.
   Standard_EXPORT OSD_Timer();
-  
-  //! Stops and reinitializes the timer.
+
+  //! Stops and reinitializes the timer with specified elapsed time.
+  Standard_EXPORT void Reset (const Standard_Real theTimeElapsedSec);
+
+  //! Stops and reinitializes the timer with zero elapsed time.
   Standard_EXPORT virtual void Reset() Standard_OVERRIDE;
   
   //! Shows both the elapsed time and CPU time on the standard output
@@ -74,29 +76,11 @@ public:
   //! Returns elapsed time in seconds.
   Standard_EXPORT Standard_Real ElapsedTime() const;
 
-
-
-
-protected:
-
-
-
-
-
 private:
 
-
-
   Standard_Real TimeStart;
   Standard_Real TimeCumul;
 
-
 };
 
-
-
-
-
-
-
 #endif // _OSD_Timer_HeaderFile
index 1e72250..9bed1e9 100644 (file)
@@ -895,6 +895,9 @@ public:
   //! the camera approach.
   Standard_EXPORT const Handle(Graphic3d_Camera)& Camera() const;
 
+  //! Return default camera.
+  const Handle(Graphic3d_Camera)& DefaultCamera() const { return myDefaultCamera; }
+
   //! Returns current rendering parameters and effect settings.
   //! By default it returns default parameters of current viewer.
   //! To define view-specific settings use method V3d_View::ChangeRenderingParams().
index 7eb042d..c49692c 100644 (file)
@@ -303,7 +303,7 @@ Standard_Boolean ViewerTest::Display (const TCollection_AsciiString&       theNa
     Handle(AIS_InteractiveObject) anOldObj = Handle(AIS_InteractiveObject)::DownCast (aMap.Find2 (theName));
     if (!anOldObj.IsNull())
     {
-      aCtx->Remove (anOldObj, Standard_True);
+      aCtx->Remove (anOldObj, theObject.IsNull() && theToUpdate);
     }
     aMap.UnBind2 (theName);
   }
@@ -3973,125 +3973,6 @@ static int VPerf(Draw_Interpretor& di, Standard_Integer , const char** argv) {
   return 0;
 }
 
-
-//==================================================================================
-// Function : VAnimation
-//==================================================================================
-static int VAnimation (Draw_Interpretor& di, Standard_Integer argc, const char** argv) {
-  if (argc != 5) {
-    di<<"Use: "<<argv[0]<<" CrankArmFile CylinderHeadFile PropellerFile EngineBlockFile\n";
-    return 1;
-  }
-
-  Standard_Real thread = 4;
-  Standard_Real angleA=0;
-  Standard_Real angleB;
-  Standard_Real X;
-  gp_Ax1 Ax1(gp_Pnt(0,0,0),gp_Vec(0,0,1));
-
-  BRep_Builder B;
-  TopoDS_Shape CrankArm;
-  TopoDS_Shape CylinderHead;
-  TopoDS_Shape Propeller;
-  TopoDS_Shape EngineBlock;
-
-  //BRepTools::Read(CrankArm,"/dp_26/Indus/ege/assemblage/CrankArm.rle",B);
-  //BRepTools::Read(CylinderHead,"/dp_26/Indus/ege/assemblage/CylinderHead.rle",B);
-  //BRepTools::Read(Propeller,"/dp_26/Indus/ege/assemblage/Propeller.rle",B);
-  //BRepTools::Read(EngineBlock,"/dp_26/Indus/ege/assemblage/EngineBlock.rle",B);
-  BRepTools::Read(CrankArm,argv[1],B);
-  BRepTools::Read(CylinderHead,argv[2],B);
-  BRepTools::Read(Propeller,argv[3],B);
-  BRepTools::Read(EngineBlock,argv[4],B);
-
-  if (CrankArm.IsNull() || CylinderHead.IsNull() || Propeller.IsNull() || EngineBlock.IsNull()) {di<<" Syntaxe error:loading failure.\n";}
-
-
-  OSD_Timer myTimer;
-  myTimer.Start();
-
-  Handle(AIS_Shape) myAisCylinderHead = new AIS_Shape (CylinderHead);
-  Handle(AIS_Shape) myAisEngineBlock  = new AIS_Shape (EngineBlock);
-  Handle(AIS_Shape) myAisCrankArm     = new AIS_Shape (CrankArm);
-  Handle(AIS_Shape) myAisPropeller    = new AIS_Shape (Propeller);
-
-  GetMapOfAIS().Bind(myAisCylinderHead,"a");
-  GetMapOfAIS().Bind(myAisEngineBlock,"b");
-  GetMapOfAIS().Bind(myAisCrankArm,"c");
-  GetMapOfAIS().Bind(myAisPropeller,"d");
-
-  myAisCylinderHead->SetMutable (Standard_True);
-  myAisEngineBlock ->SetMutable (Standard_True);
-  myAisCrankArm    ->SetMutable (Standard_True);
-  myAisPropeller   ->SetMutable (Standard_True);
-
-  TheAISContext()->SetColor (myAisCylinderHead, Quantity_NOC_INDIANRED);
-  TheAISContext()->SetColor (myAisEngineBlock,  Quantity_NOC_RED);
-  TheAISContext()->SetColor (myAisPropeller,    Quantity_NOC_GREEN);
-
-  TheAISContext()->Display (myAisCylinderHead, Standard_False);
-  TheAISContext()->Display (myAisEngineBlock,  Standard_False);
-  TheAISContext()->Display (myAisCrankArm,     Standard_False);
-  TheAISContext()->Display (myAisPropeller,    Standard_False);
-
-  TheAISContext()->Deactivate(myAisCylinderHead);
-  TheAISContext()->Deactivate(myAisEngineBlock );
-  TheAISContext()->Deactivate(myAisCrankArm    );
-  TheAISContext()->Deactivate(myAisPropeller   );
-
-  // Boucle de mouvement
-  for (Standard_Real myAngle = 0;angleA<2*M_PI*10.175 ;myAngle++) {
-
-    angleA = thread*myAngle*M_PI/180;
-    X = Sin(angleA)*3/8;
-    angleB = atan(X / Sqrt(-X * X + 1));
-    Standard_Real decal(25*0.6);
-
-
-    //Build a transformation on the display
-    gp_Trsf aPropellerTrsf;
-    aPropellerTrsf.SetRotation(Ax1,angleA);
-    TheAISContext()->SetLocation(myAisPropeller,aPropellerTrsf);
-
-    gp_Ax3 base(gp_Pnt(3*decal*(1-Cos(angleA)),-3*decal*Sin(angleA),0),gp_Vec(0,0,1),gp_Vec(1,0,0));
-    gp_Trsf aCrankArmTrsf;
-    aCrankArmTrsf.SetTransformation(   base.Rotated(gp_Ax1(gp_Pnt(3*decal,0,0),gp_Dir(0,0,1)),angleB));
-    TheAISContext()->SetLocation(myAisCrankArm,aCrankArmTrsf);
-
-    TheAISContext()->UpdateCurrentViewer();
-  }
-
-  TopoDS_Shape myNewCrankArm  =myAisCrankArm ->Shape().Located( myAisCrankArm ->Transformation() );
-  TopoDS_Shape myNewPropeller =myAisPropeller->Shape().Located( myAisPropeller->Transformation() );
-
-  myAisCrankArm ->ResetTransformation();
-  myAisPropeller->ResetTransformation();
-
-  myAisCrankArm  -> Set(myNewCrankArm );
-  myAisPropeller -> Set(myNewPropeller);
-
-  TheAISContext()->Activate(myAisCylinderHead,0);
-  TheAISContext()->Activate(myAisEngineBlock,0 );
-  TheAISContext()->Activate(myAisCrankArm ,0   );
-  TheAISContext()->Activate(myAisPropeller ,0  );
-
-  myTimer.Stop();
-  myTimer.Show();
-  myTimer.Start();
-
-  TheAISContext()->Redisplay(myAisCrankArm ,Standard_False);
-  TheAISContext()->Redisplay(myAisPropeller,Standard_False);
-
-  TheAISContext()->UpdateCurrentViewer();
-  a3DView()->Redraw();
-
-  myTimer.Stop();
-  myTimer.Show();
-
-  return 0;
-
-}
-
 //==============================================================================
 //function : VShading
 //purpose  : Sharpen or roughten the quality of the shading
@@ -5763,10 +5644,6 @@ void ViewerTest::Commands(Draw_Interpretor& theCommands)
       "\n\t\t: Tests the animation of an object along a predefined trajectory.",
       __FILE__,VPerf,group);
 
-  theCommands.Add("vanimation",
-                 "vanimation CrankArmFile CylinderHeadFile PropellerFile EngineBlockFile",
-                 __FILE__,VAnimation,group);
-
   theCommands.Add("vsetshading",
       "vsetshading  : vsetshading name Quality(default=0.0008) "
       "\n\t\t: Sets deflection coefficient that defines the quality of the shape representation in the shading mode.",
index 2d6db65..62307d4 100644 (file)
@@ -70,8 +70,9 @@ Standard_Boolean ViewerTest_AutoUpdater::parseRedrawMode (const TCollection_Asci
 //=======================================================================
 void ViewerTest_AutoUpdater::Invalidate()
 {
-  myContext.Nullify();
-  if (myWasAutoUpdate)
+  myToUpdate = ViewerTest_AutoUpdater::RedrawMode_Suppressed;
+  if (myWasAutoUpdate
+  && !myView.IsNull())
   {
     myView->SetImmediateUpdate (myWasAutoUpdate);
   }
@@ -83,16 +84,34 @@ void ViewerTest_AutoUpdater::Invalidate()
 //=======================================================================
 void ViewerTest_AutoUpdater::Update()
 {
-  if (myContext.IsNull())
+  if (!myView.IsNull())
   {
-    return;
+    myView->SetImmediateUpdate (myWasAutoUpdate);
   }
 
-  // update the screen and redraw the view
-  myView->SetImmediateUpdate (myWasAutoUpdate);
-  if ((myWasAutoUpdate && myToUpdate != ViewerTest_AutoUpdater::RedrawMode_Suppressed)
-    || myToUpdate == ViewerTest_AutoUpdater::RedrawMode_Forced)
+  switch (myToUpdate)
   {
-    myContext->UpdateCurrentViewer();
+    case ViewerTest_AutoUpdater::RedrawMode_Suppressed:
+    {
+      return;
+    }
+    case ViewerTest_AutoUpdater::RedrawMode_Auto:
+    {
+      if (!myWasAutoUpdate)
+      {
+        return;
+      }
+    }
+    case ViewerTest_AutoUpdater::RedrawMode_Forced:
+    {
+      if (!myContext.IsNull())
+      {
+        myContext->UpdateCurrentViewer();
+      }
+      else if (!myView.IsNull())
+      {
+        myView->Redraw();
+      }
+    }
   }
 }
index 15a7f9f..10e5dfd 100644 (file)
@@ -78,6 +78,7 @@
 #include <AIS_Trihedron.hxx>
 #include <AIS_Axis.hxx>
 #include <gp_Trsf.hxx>
+#include <gp_Quaternion.hxx>
 #include <TopLoc_Location.hxx>
 
 #include <HLRAlgo_Projector.hxx>
@@ -2491,12 +2492,15 @@ static int VDrawText (Draw_Interpretor& theDI,
   Handle(AIS_TextLabel)      aTextPrs;
   ViewerTest_AutoUpdater     anAutoUpdater (aContext, ViewerTest::CurrentView());
 
+  Standard_Boolean isNewPrs = Standard_False;
   if (GetMapOfAIS().IsBound2 (aName))
   {
-    aTextPrs  = Handle(AIS_TextLabel)::DownCast (GetMapOfAIS().Find2 (aName));
+    aTextPrs = Handle(AIS_TextLabel)::DownCast (GetMapOfAIS().Find2 (aName));
   }
-  else
+
+  if (aTextPrs.IsNull())
   {
+    isNewPrs = Standard_True;
     aTextPrs = new AIS_TextLabel();
     aTextPrs->SetFont ("Courier");
   }
@@ -2851,7 +2855,15 @@ static int VDrawText (Draw_Interpretor& theDI,
   {
     aContext->SetTransformPersistence (aTextPrs, Handle(Graphic3d_TransformPers)());
   }
-  ViewerTest::Display (aName, aTextPrs, Standard_False);
+
+  if (isNewPrs)
+  {
+    ViewerTest::Display (aName, aTextPrs, Standard_False);
+  }
+  else
+  {
+    aContext->Redisplay (aTextPrs, Standard_False, Standard_True);
+  }
   return 0;
 }
 
@@ -3699,12 +3711,47 @@ static int VDrawPArray (Draw_Interpretor& di, Standard_Integer argc, const char*
   return 0;
 }
 
+namespace
+{
+  //! Auxiliary function for parsing translation vector - either 2D or 3D.
+  static Standard_Integer parseTranslationVec (Standard_Integer theArgNb,
+                                               const char**     theArgVec,
+                                               gp_Vec&          theVec)
+  {
+    if (theArgNb < 2)
+    {
+      return 0;
+    }
+
+    TCollection_AsciiString anX (theArgVec[0]);
+    TCollection_AsciiString anY (theArgVec[1]);
+    if (!anX.IsRealValue()
+     || !anY.IsRealValue())
+    {
+      return 0;
+    }
+
+    theVec.SetX (anX.RealValue());
+    theVec.SetY (anY.RealValue());
+    if (theArgNb >= 3)
+    {
+      TCollection_AsciiString anZ (theArgVec[2]);
+      if (anZ.IsRealValue())
+      {
+        theVec.SetZ (anZ.RealValue());
+        return 3;
+      }
+    }
+    return 2;
+  }
+}
+
 //=======================================================================
 //function : VSetLocation
 //purpose  : Change location of AIS interactive object
 //=======================================================================
 
-static Standard_Integer VSetLocation (Draw_Interpretor& /*di*/,
+static Standard_Integer VSetLocation (Draw_Interpretor& theDI,
                                       Standard_Integer  theArgNb,
                                       const char**      theArgVec)
 {
@@ -3716,221 +3763,330 @@ static Standard_Integer VSetLocation (Draw_Interpretor& /*di*/,
     return 1;
   }
 
-  TCollection_AsciiString aName;
-  gp_Vec aLocVec;
-  Standard_Boolean isSetLoc = Standard_False;
-
-  Standard_Integer anArgIter = 1;
-  for (; anArgIter < theArgNb; ++anArgIter)
+  Standard_Boolean toPrintInfo = Standard_True;
+  Handle(AIS_InteractiveObject) anObj;
+  TCollection_AsciiString aCmdName (theArgVec[0]);
+  aCmdName.LowerCase();
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
   {
-    Standard_CString anArg = theArgVec[anArgIter];
-    if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
+    TCollection_AsciiString anArg = theArgVec[anArgIter];
+    anArg.LowerCase();
+    if (anUpdateTool.parseRedrawMode (anArg))
     {
       continue;
     }
-    else if (aName.IsEmpty())
+    else if (anObj.IsNull())
     {
-      aName = anArg;
+      const TCollection_AsciiString aName (theArgVec[anArgIter]);
+      const ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
+      if (aMap.IsBound2 (aName))
+      {
+        anObj = Handle(AIS_InteractiveObject)::DownCast (aMap.Find2 (aName));
+      }
+      if (anObj.IsNull())
+      {
+        std::cout << "Error: object '" << aName << "' is not displayed!\n";
+        return 1;
+      }
     }
-    else if (!isSetLoc)
+    else if (anArg == "-reset")
+    {
+      toPrintInfo = Standard_False;
+      aContext->SetLocation (anObj, gp_Trsf());
+    }
+    else if (anArg == "-copyfrom"
+          || anArg == "-copy")
     {
-      isSetLoc = Standard_True;
       if (anArgIter + 1 >= theArgNb)
       {
-        std::cout << "Error: syntax error at '" << anArg << "'\n";
+        std::cout << "Syntax error at '" << anArg << "'\n";
         return 1;
       }
-      aLocVec.SetX (Draw::Atof (theArgVec[anArgIter++]));
-      aLocVec.SetY (Draw::Atof (theArgVec[anArgIter]));
-      if (anArgIter + 1 < theArgNb)
+
+      const TCollection_AsciiString aName2 (theArgVec[anArgIter + 1]);
+      const ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
+      Handle(AIS_InteractiveObject) anObj2;
+      if (aMap.IsBound2 (aName2))
+      {
+        anObj2 = Handle(AIS_InteractiveObject)::DownCast (aMap.Find2 (aName2));
+      }
+      if (anObj2.IsNull())
       {
-        aLocVec.SetZ (Draw::Atof (theArgVec[++anArgIter]));
+        std::cout << "Error: object '" << aName2 << "' is not displayed!\n";
+        return 1;
       }
+
+      ++anArgIter;
+      aContext->SetLocation (anObj, anObj2->LocalTransformation());
     }
-    else
+    else if (anArg == "-rotate")
     {
-      std::cout << "Error: unknown argument '" << anArg << "'\n";
-      return 1;
-    }
-  }
-
-  // find object
-  const ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
-  Handle(AIS_InteractiveObject) anIObj;
-  if (aMap.IsBound2 (aName))
-  {
-    anIObj = Handle(AIS_InteractiveObject)::DownCast (aMap.Find2 (aName));
-  }
-  if (anIObj.IsNull())
-  {
-    std::cout << "Error: object '" << aName << "' is not displayed!\n";
-    return 1;
-  }
-
-  gp_Trsf aTrsf;
-  aTrsf.SetTranslation (aLocVec);
-  TopLoc_Location aLocation (aTrsf);
-  aContext->SetLocation (anIObj, aLocation);
-  return 0;
-}
-
-//=======================================================================
-//function : TransformPresentation
-//purpose  : Change transformation of AIS interactive object
-//=======================================================================
-static Standard_Integer LocalTransformPresentation (Draw_Interpretor& /*theDi*/,
-                                                    Standard_Integer theArgNb,
-                                                    const char** theArgVec)
-{
-  if (theArgNb <= 1)
-  {
-    std::cout << "Error: too few arguments.\n";
-    return 1;
-  }
-
-  Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext();
-  ViewerTest_AutoUpdater anUpdateTool(aContext, ViewerTest::CurrentView());
-  if (aContext.IsNull())
-  {
-    std::cout << "Error: no active view!\n";
-    return 1;
-  }
-
-  gp_Trsf aTrsf;
-  Standard_Integer aLast = theArgNb;
-  const char* aName = theArgVec[0];
-
-  Standard_Boolean isReset = Standard_False;
-  Standard_Boolean isMove = Standard_False;
+      toPrintInfo = Standard_False;
+      if (anArgIter + 7 >= theArgNb)
+      {
+        std::cout << "Syntax error at '" << anArg << "'\n";
+        return 1;
+      }
 
-  // Prefix 'vloc'
-  aName += 4;
+      gp_Trsf aTrsf;
+      aTrsf.SetRotation (gp_Ax1 (gp_Pnt (Draw::Atof (theArgVec[anArgIter + 1]),
+                                         Draw::Atof (theArgVec[anArgIter + 2]),
+                                         Draw::Atof (theArgVec[anArgIter + 3])),
+                                 gp_Vec (Draw::Atof (theArgVec[anArgIter + 4]),
+                                         Draw::Atof (theArgVec[anArgIter + 5]),
+                                         Draw::Atof (theArgVec[anArgIter + 6]))),
+                                         Draw::Atof (theArgVec[anArgIter + 7]) * (M_PI / 180.0));
+      anArgIter += 7;
 
-  if (!strcmp (aName, "reset"))
-  {
-    isReset = Standard_True;
-  }
-  else if (!strcmp (aName, "move"))
-  {
-    if (theArgNb < 3)
-    {
-      std::cout << "Error: too few arguments.\n";
-      return 1;
+      aTrsf = anObj->LocalTransformation() * aTrsf;
+      aContext->SetLocation (anObj, aTrsf);
     }
-
-    const ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
-
-    Handle(AIS_InteractiveObject) anIObj;
-    if (aMap.IsBound2 (theArgVec[theArgNb - 1]))
+    else if (anArg == "-translate")
     {
-      anIObj = Handle(AIS_InteractiveObject)::DownCast (aMap.Find2 (theArgVec[theArgNb - 1]));
-    }
+      toPrintInfo = Standard_False;
+      gp_Vec aLocVec;
+      Standard_Integer aNbParsed = parseTranslationVec (theArgNb - anArgIter - 1, theArgVec + anArgIter + 1, aLocVec);
+      anArgIter += aNbParsed;
+      if (aNbParsed == 0)
+      {
+        std::cout << "Syntax error at '" << anArg << "'\n";
+        return 1;
+      }
 
-    if (anIObj.IsNull())
-    {
-      std::cout << "Error: object '" << theArgVec[theArgNb - 1] << "' is not displayed!\n";
-      return 1;
+      gp_Trsf aTrsf;
+      aTrsf.SetTranslationPart (aLocVec);
+      aTrsf = anObj->LocalTransformation() * aTrsf;
+      aContext->SetLocation (anObj, aTrsf);
     }
+    else if (anArg == "-scale"
+          || anArg == "-setscale")
+    {
+      toPrintInfo = Standard_False;
+      gp_XYZ aScaleLoc;
+      Standard_Real aScale = 1.0;
+      Standard_Boolean toPrintScale = Standard_True;
+      Standard_Boolean hasScaleLoc  = Standard_False;
+      if (anArgIter + 4 < theArgNb)
+      {
+        TCollection_AsciiString aScaleArgs[4] =
+        {
+          TCollection_AsciiString (theArgVec[anArgIter + 1]),
+          TCollection_AsciiString (theArgVec[anArgIter + 2]),
+          TCollection_AsciiString (theArgVec[anArgIter + 3]),
+          TCollection_AsciiString (theArgVec[anArgIter + 4])
+        };
+        Standard_Integer aScaleArgIter = 0;
+        for (; aScaleArgIter < 4; ++aScaleArgIter)
+        {
+          if (!aScaleArgs[aScaleArgIter].IsRealValue())
+          {
+            break;
+          }
+        }
+        if (aScaleArgIter == 4)
+        {
+          aScaleLoc.SetCoord (aScaleArgs[0].RealValue(), aScaleArgs[1].RealValue(), aScaleArgs[2].RealValue());
+          aScale = aScaleArgs[3].RealValue();
+          anArgIter += 4;
+          toPrintScale = Standard_False;
+          hasScaleLoc  = Standard_True;
+        }
+        else if (aScaleArgIter >= 1)
+        {
+          aScale = aScaleArgs[0].RealValue();
+          ++anArgIter;
+          toPrintScale = Standard_False;
+        }
+      }
+      else if (anArgIter + 1 < theArgNb)
+      {
+        TCollection_AsciiString aScaleArg (theArgVec[anArgIter + 1]);
+        if (aScaleArg.IsRealValue())
+        {
+          aScale = aScaleArg.RealValue();
+          ++anArgIter;
+          toPrintScale = Standard_False;
+        }
+      }
+
+      if (toPrintScale)
+      {
+        if (anArg == "-setscale")
+        {
+          std::cout << "Syntax error at '" << anArg << "'\n";
+          return 1;
+        }
 
-    isMove = Standard_True;
+        char aText[1024];
+        Sprintf (aText, "%g ", anObj->LocalTransformation().ScaleFactor());
+        theDI << aText;
+        continue;
+      }
 
-    aTrsf = anIObj->Transformation();
-    aLast = theArgNb - 1;
-  }
-  else if (!strcmp (aName, "translate"))
-  {
-    if (theArgNb < 5)
-    {
-      std::cout << "Error: too few arguments.\n";
-      return 1;
+      if (anArg == "-setscale")
+      {
+        gp_Trsf aTrsf = anObj->LocalTransformation();
+        if (hasScaleLoc)
+        {
+          aTrsf.SetScale (aScaleLoc, aScale);
+        }
+        else
+        {
+          aTrsf.SetScaleFactor (aScale);
+        }
+        aContext->SetLocation (anObj, aTrsf);
+      }
+      else
+      {
+        gp_Trsf aTrsf;
+        if (hasScaleLoc)
+        {
+          aTrsf.SetScale (aScaleLoc, aScale);
+          aTrsf = anObj->LocalTransformation() * aTrsf;
+        }
+        else
+        {
+          aTrsf = anObj->LocalTransformation();
+          aTrsf.SetScaleFactor (aTrsf.ScaleFactor() * aScale);
+        }
+        aContext->SetLocation (anObj, aTrsf);
+      }
     }
-    aTrsf.SetTranslation (gp_Vec (Draw::Atof (theArgVec[theArgNb - 3]),
-                                  Draw::Atof (theArgVec[theArgNb - 2]),
-                                  Draw::Atof (theArgVec[theArgNb - 1])));
-    aLast = theArgNb - 3;
-  }
-  else if (!strcmp (aName, "rotate"))
-  {
-    if (theArgNb < 9)
+    else if (anArg == "-mirror")
     {
-      std::cout << "Error: too few arguments.\n";
-      return 1;
-    }
-
-    aTrsf.SetRotation (
-      gp_Ax1 (gp_Pnt (Draw::Atof (theArgVec[theArgNb - 7]),
-                      Draw::Atof (theArgVec[theArgNb - 6]),
-                      Draw::Atof (theArgVec[theArgNb - 5])),
-              gp_Vec (Draw::Atof (theArgVec[theArgNb - 4]),
-                      Draw::Atof (theArgVec[theArgNb - 3]),
-                      Draw::Atof (theArgVec[theArgNb - 2]))),
-      Draw::Atof (theArgVec[theArgNb - 1]) * (M_PI / 180.0));
+      toPrintInfo = Standard_False;
+      if (anArgIter + 6 >= theArgNb)
+      {
+        std::cout << "Syntax error at '" << anArg << "'\n";
+        return 1;
+      }
 
-    aLast = theArgNb - 7;
-  }
-  else if (!strcmp (aName, "mirror"))
-  {
-    if (theArgNb < 8)
-    {
-      std::cout << "Error: too few arguments.\n";
-      return 1;
+      gp_Trsf aTrsf;
+      aTrsf.SetMirror (gp_Ax2 (gp_Pnt (Draw::Atof(theArgVec[theArgNb - 6]),
+                                       Draw::Atof(theArgVec[theArgNb - 5]),
+                                       Draw::Atof(theArgVec[theArgNb - 4])),
+                               gp_Vec (Draw::Atof(theArgVec[theArgNb - 3]),
+                                       Draw::Atof(theArgVec[theArgNb - 2]),
+                                       Draw::Atof(theArgVec[theArgNb - 1]))));
+      anArgIter += 6;
+      aTrsf = anObj->LocalTransformation() * aTrsf;
+      aContext->SetLocation (anObj, aTrsf);
     }
-
-    aTrsf.SetMirror (gp_Ax2 (gp_Pnt (Draw::Atof(theArgVec[theArgNb - 6]),
-                                     Draw::Atof(theArgVec[theArgNb - 5]),
-                                     Draw::Atof(theArgVec[theArgNb - 4])),
-                             gp_Vec (Draw::Atof(theArgVec[theArgNb - 3]),
-                                     Draw::Atof(theArgVec[theArgNb - 2]),
-                                     Draw::Atof(theArgVec[theArgNb - 1]))));
-    aLast = theArgNb - 6;
-  }
-  else if (!strcmp (aName, "scale"))
-  {
-    if (theArgNb < 6)
+    else if (anArg == "-setrotation"
+          || anArg == "-rotation")
     {
-      std::cout << "Error: too few arguments.\n";
-      return 1;
-    }
+      toPrintInfo = Standard_False;
+      if (anArgIter + 4 < theArgNb)
+      {
+        TCollection_AsciiString aQuatArgs[4] =
+        {
+          TCollection_AsciiString (theArgVec[anArgIter + 1]),
+          TCollection_AsciiString (theArgVec[anArgIter + 2]),
+          TCollection_AsciiString (theArgVec[anArgIter + 3]),
+          TCollection_AsciiString (theArgVec[anArgIter + 4])
+        };
+        Standard_Integer aQuatArgIter = 0;
+        for (; aQuatArgIter < 4; ++aQuatArgIter)
+        {
+          if (!aQuatArgs[aQuatArgIter].IsRealValue())
+          {
+            break;
+          }
+        }
 
-    aTrsf.SetScale (gp_Pnt (Draw::Atof(theArgVec[theArgNb - 4]),
-                            Draw::Atof(theArgVec[theArgNb - 3]),
-                            Draw::Atof(theArgVec[theArgNb - 2])),
-                    Draw::Atof(theArgVec[theArgNb - 1]));
-    aLast = theArgNb - 4;
-  }
+        if (aQuatArgIter == 4)
+        {
+          anArgIter += 4;
+          const gp_Quaternion aQuat (aQuatArgs[0].RealValue(),
+                                     aQuatArgs[1].RealValue(),
+                                     aQuatArgs[2].RealValue(),
+                                     aQuatArgs[3].RealValue());
+          gp_Trsf aTrsf = anObj->LocalTransformation();
+          aTrsf.SetRotation (aQuat);
+          aContext->SetLocation (anObj, aTrsf);
+          continue;
+        }
+        else if (anArg == "-setrotation")
+        {
+          std::cout << "Syntax error at '" << anArg << "'\n";
+          return 1;
+        }
+      }
 
-  for (Standard_Integer anIdx = 1; anIdx < aLast; anIdx++)
-  {
-    // find object
-    const ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS();
-    Handle(AIS_InteractiveObject) anIObj;
-    if (aMap.IsBound2 (theArgVec[anIdx]))
-    {
-      anIObj = Handle(AIS_InteractiveObject)::DownCast (aMap.Find2 (theArgVec[anIdx]));
+      char aText[1024];
+      const gp_Quaternion aQuat = anObj->LocalTransformation().GetRotation();
+      Sprintf (aText, "%g %g %g %g ", aQuat.X(), aQuat.Y(), aQuat.Z(), aQuat.W());
+      theDI << aText;
     }
-    if (anIObj.IsNull())
+    else if (anArg == "-setlocation"
+          || anArg == "-location")
     {
-      std::cout << "Error: object '" << theArgVec[anIdx] << "' is not displayed!\n";
-      return 1;
-    }
-    
-    if (isReset)
-    {
-      // aTrsf already identity
+      toPrintInfo = Standard_False;
+      gp_Vec aLocVec;
+      Standard_Integer aNbParsed = parseTranslationVec (theArgNb - anArgIter - 1, theArgVec + anArgIter + 1, aLocVec);
+      anArgIter += aNbParsed;
+      if (aNbParsed != 0)
+      {
+        gp_Trsf aTrsf = anObj->LocalTransformation();
+        aTrsf.SetTranslationPart (aLocVec);
+        aContext->SetLocation (anObj, aTrsf);
+      }
+      else if (anArg == "-setlocation")
+      {
+        std::cout << "Syntax error at '" << anArg << "'\n";
+        return 1;
+      }
+
+      char aText[1024];
+      const gp_XYZ aLoc = anObj->LocalTransformation().TranslationPart();
+      Sprintf (aText, "%g %g %g ", aLoc.X(), aLoc.Y(), aLoc.Z());
+      theDI << aText;
     }
-    else if (isMove)
+    else if (aCmdName == "vsetlocation")
     {
-      aTrsf = anIObj->LocalTransformation() * anIObj->Transformation().Inverted() * aTrsf;
+      // compatibility with old syntax
+      gp_Vec aLocVec;
+      Standard_Integer aNbParsed = parseTranslationVec (theArgNb - anArgIter, theArgVec + anArgIter, aLocVec);
+      if (aNbParsed == 0)
+      {
+        std::cout << "Syntax error at '" << anArg << "'\n";
+        return 1;
+      }
+      anArgIter = anArgIter + aNbParsed - 1;
+
+      gp_Trsf aTrsf;
+      aTrsf.SetTranslationPart (aLocVec);
+      aContext->SetLocation (anObj, aTrsf);
+      toPrintInfo = Standard_False;
     }
     else
     {
-      aTrsf = anIObj->LocalTransformation() * aTrsf;
+      std::cout << "Error: unknown argument '" << anArg << "'\n";
+      return 1;
     }
+  }
 
-    TopLoc_Location aLocation (aTrsf);
-    aContext->SetLocation (anIObj, aLocation);
+  if (anObj.IsNull())
+  {
+    std::cout << "Syntax error - wrong number of arguments\n";
+    return 1;
+  }
+  else if (!toPrintInfo)
+  {
+    return 0;
   }
 
+  const gp_Trsf       aTrsf = anObj->LocalTransformation();
+  const gp_XYZ        aLoc  = aTrsf.TranslationPart();
+  const gp_Quaternion aRot  = aTrsf.GetRotation();
+  char aText[4096];
+  Sprintf (aText, "Location: %g %g %g\n"
+                  "Rotation: %g %g %g %g\n"
+                  "Scale:    %g\n",
+                  aLoc.X(), aLoc.Y(), aLoc.Z(),
+                  aRot.X(), aRot.Y(), aRot.Z(), aRot.W(),
+                  aTrsf.ScaleFactor());
+  theDI << aText;
   return 0;
 }
 
@@ -6411,9 +6567,29 @@ void ViewerTest::ObjectCommands(Draw_Interpretor& theCommands)
     "vdrawsphere: vdrawsphere shapeName Fineness [X=0.0 Y=0.0 Z=0.0] [Radius=100.0] [ToShowEdges=0] [ToPrintInfo=1]\n",
     __FILE__,VDrawSphere,group);
 
+  theCommands.Add ("vlocation",
+                "vlocation name"
+      "\n\t\t:   [-reset]"
+      "\n\t\t:   [-copyFrom otherName]"
+      "\n\t\t:   [-translate X Y [Z]]"
+      "\n\t\t:   [-rotate x y z dx dy dz angle]"
+      "\n\t\t:   [-scale [X Y Z] scale]"
+      "\n\t\t:   [-mirror x y z dx dy dz]"
+      "\n\t\t:   [-setLocation X Y [Z]]"
+      "\n\t\t:   [-setRotation QX QY QZ QW]"
+      "\n\t\t:   [-setScale [X Y Z] scale]"
+      "\n\t\t: Object local transformation management:"
+      "\n\t\t:   -reset       reset transformation to identity"
+      "\n\t\t:   -translate   translate object"
+      "\n\t\t:   -rotate      applies rotation to local transformation"
+      "\n\t\t:   -scale       applies scale    to local transformation"
+      "\n\t\t:   -mirror      applies mirror   to local transformation"
+      "\n\t\t:   -setLocation assign object location"
+      "\n\t\t:   -setRotation assign object rotation (quaternion)"
+      "\n\t\t:   -setScale    assign object scale factor",
+        __FILE__, VSetLocation, group);
   theCommands.Add ("vsetlocation",
-                   "vsetlocation [-noupdate|-update] name x y z"
-                   "\n\t\t: Set new location for an interactive object.",
+                   "alias for vlocation",
         __FILE__, VSetLocation, group);
 
   theCommands.Add (
@@ -6562,36 +6738,6 @@ void ViewerTest::ObjectCommands(Draw_Interpretor& theCommands)
                    "\n",
                    __FILE__, VPointCloud, group);
 
-  theCommands.Add("vlocreset",
-    "vlocreset name1 name2 ...\n\t\t  remove object local transformation",
-    __FILE__,
-    LocalTransformPresentation, group);
-
-  theCommands.Add("vlocmove",
-    "vlocmove name1 name2 ... name\n\t\t  set local transform to match transform of 'name'",
-    __FILE__,
-    LocalTransformPresentation, group);
-
-  theCommands.Add("vloctranslate",
-    "vloctranslate name1 name2 ... dx dy dz\n\t\t  applies translation to local transformation",
-    __FILE__,
-    LocalTransformPresentation, group);
-
-  theCommands.Add("vlocrotate",
-    "vlocrotate name1 name2 ... x y z dx dy dz angle\n\t\t  applies rotation to local transformation",
-    __FILE__,
-    LocalTransformPresentation, group);
-
-  theCommands.Add("vlocmirror",
-    "vlocmirror name x y z dx dy dz\n\t\t  applies mirror to local transformation",
-    __FILE__,
-    LocalTransformPresentation, group);
-
-  theCommands.Add("vlocscale",
-    "vlocscale name x y z scale\n\t\t  applies scale to local transformation",
-    __FILE__,
-    LocalTransformPresentation, group);
-
   theCommands.Add("vpriority",
     "vpriority [-noupdate|-update] name [value]\n\t\t  prints or sets the display priority for an object",
     __FILE__,
index d1dca89..df8b73f 100644 (file)
 // commercial license or contractual agreement.
 
 #include <OpenGl_GlCore20.hxx>
+
+#include <AIS_Animation.hxx>
+#include <AIS_AnimationCamera.hxx>
+#include <AIS_AnimationObject.hxx>
 #include <AIS_ColorScale.hxx>
 #include <AIS_Manipulator.hxx>
 #include <AIS_RubberBand.hxx>
@@ -187,6 +191,7 @@ int X_ButtonPress = 0; // Last ButtonPress position
 int Y_ButtonPress = 0;
 Standard_Boolean IsDragged = Standard_False;
 Standard_Boolean DragFirst = Standard_False;
+Standard_Boolean TheIsAnimating = Standard_False;
 
 
 Standard_EXPORT const Handle(AIS_RubberBand)& GetRubberBand()
@@ -1569,6 +1574,12 @@ Standard_Boolean VT_ProcessButton1Press (Standard_Integer ,
                                          Standard_Boolean theToPick,
                                          Standard_Boolean theIsShift)
 {
+  if (TheIsAnimating)
+  {
+    TheIsAnimating = Standard_False;
+    return Standard_False;
+  }
+
   if (theToPick)
   {
     Standard_Real X, Y, Z;
@@ -2497,33 +2508,42 @@ static void OSWindowSetup()
 
 //==============================================================================
 //function : VFit
-
-//purpose  : Fitall, no DRAW arguments
-//Draw arg : No args
+//purpose  :
 //==============================================================================
 
-static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgc, const char** theArgv)
+static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgv)
 {
-  if (theArgc > 2)
+  const Handle(V3d_View) aView = ViewerTest::CurrentView();
+  if (aView.IsNull())
   {
-    std::cout << "Wrong number of arguments! Use: vfit [-selected]" << std::endl;
+    std::cout << "Error: no active viewer!\n";
+    return 1;
   }
 
-  const Handle(V3d_View) aView = ViewerTest::CurrentView();
-
-  if (theArgc == 2)
+  Standard_Boolean toFit = Standard_True;
+  ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
   {
-    TCollection_AsciiString anArg (theArgv[1]);
+    TCollection_AsciiString anArg (theArgv[anArgIter]);
     anArg.LowerCase();
-    if (anArg == "-selected")
+    if (anUpdateTool.parseRedrawMode (anArg))
     {
-      ViewerTest::GetAISContext()->FitSelected (aView);
-      return 0;
+      continue;
+    }
+    else if (anArg == "-selected")
+    {
+      ViewerTest::GetAISContext()->FitSelected (aView, 0.01, Standard_False);
+      toFit = Standard_False;
+    }
+    else
+    {
+      std::cout << "Syntax error at '" << anArg << "'\n";
     }
   }
-  if (aView.IsNull() == Standard_False) {
 
-    aView->FitAll();
+  if (toFit)
+  {
+    aView->FitAll (0.01, Standard_False);
   }
   return 0;
 }
@@ -5981,206 +6001,908 @@ static Standard_Integer VMoveTo (Draw_Interpretor& di,
   return 0;
 }
 
+namespace
+{
+  //! Global map storing all animations registered in ViewerTest.
+  static NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)> ViewerTest_AnimationTimelineMap;
+
+  //! The animation calling the Draw Harness command.
+  class ViewerTest_AnimationProc : public AIS_Animation
+  {
+  public:
+
+    //! Main constructor.
+    ViewerTest_AnimationProc (const TCollection_AsciiString& theAnimationName,
+                              Draw_Interpretor* theDI,
+                              const TCollection_AsciiString& theCommand)
+    : AIS_Animation (theAnimationName),
+      myDrawInter(theDI),
+      myCommand  (theCommand)
+    {
+      //
+    }
+
+  protected:
+
+    //! Evaluate the command.
+    virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE
+    {
+      TCollection_AsciiString aCmd = myCommand;
+      replace (aCmd, "%pts",             TCollection_AsciiString(theProgress.Pts));
+      replace (aCmd, "%localpts",        TCollection_AsciiString(theProgress.LocalPts));
+      replace (aCmd, "%ptslocal",        TCollection_AsciiString(theProgress.LocalPts));
+      replace (aCmd, "%normalized",      TCollection_AsciiString(theProgress.LocalNormalized));
+      replace (aCmd, "%localnormalized", TCollection_AsciiString(theProgress.LocalNormalized));
+      myDrawInter->Eval (aCmd.ToCString());
+    }
+
+    //! Find the keyword in the command and replace it with value.
+    //! @return the position of the keyword to pass value
+    void replace (TCollection_AsciiString&       theCmd,
+                  const TCollection_AsciiString& theKey,
+                  const TCollection_AsciiString& theVal)
+    {
+      TCollection_AsciiString aCmd (theCmd);
+      aCmd.LowerCase();
+      const Standard_Integer aPos = aCmd.Search (theKey);
+      if (aPos == -1)
+      {
+        return;
+      }
+
+      TCollection_AsciiString aPart1, aPart2;
+      Standard_Integer aPart1To = aPos - 1;
+      if (aPart1To >= 1
+       && aPart1To <= theCmd.Length())
+      {
+        aPart1 = theCmd.SubString (1, aPart1To);
+      }
+
+      Standard_Integer aPart2From = aPos + theKey.Length();
+      if (aPart2From >= 1
+       && aPart2From <= theCmd.Length())
+      {
+        aPart2 = theCmd.SubString (aPart2From, theCmd.Length());
+      }
+
+      theCmd = aPart1 + theVal + aPart2;
+    }
+
+  protected:
+
+    Draw_Interpretor*       myDrawInter;
+    TCollection_AsciiString myCommand;
+
+  };
+
+  //! Replace the animation with the new one.
+  static void replaceAnimation (const Handle(AIS_Animation)& theParentAnimation,
+                                Handle(AIS_Animation)&       theAnimation,
+                                const Handle(AIS_Animation)& theAnimationNew)
+  {
+    theAnimationNew->CopyFrom (theAnimation);
+    if (!theParentAnimation.IsNull())
+    {
+      theParentAnimation->Replace (theAnimation, theAnimationNew);
+    }
+    else
+    {
+      ViewerTest_AnimationTimelineMap.UnBind (theAnimationNew->Name());
+      ViewerTest_AnimationTimelineMap.Bind   (theAnimationNew->Name(), theAnimationNew);
+    }
+    theAnimation = theAnimationNew;
+  }
+
+  //! Parse the point.
+  static Standard_Boolean parseXYZ (const char** theArgVec, gp_XYZ& thePnt)
+  {
+    const TCollection_AsciiString anXYZ[3] = { theArgVec[0], theArgVec[1], theArgVec[2] };
+    if (!anXYZ[0].IsRealValue()
+     || !anXYZ[1].IsRealValue()
+     || !anXYZ[2].IsRealValue())
+    {
+      return Standard_False;
+    }
+
+    thePnt.SetCoord (anXYZ[0].RealValue(), anXYZ[1].RealValue(), anXYZ[2].RealValue());
+    return Standard_True;
+  }
+
+  //! Parse the quaternion.
+  static Standard_Boolean parseQuaternion (const char** theArgVec, gp_Quaternion& theQRot)
+  {
+    const TCollection_AsciiString anXYZW[4] = {theArgVec[0], theArgVec[1], theArgVec[2], theArgVec[3]};
+    if (!anXYZW[0].IsRealValue()
+     || !anXYZW[1].IsRealValue()
+     || !anXYZW[2].IsRealValue()
+     || !anXYZW[3].IsRealValue())
+    {
+      return Standard_False;
+    }
+
+    theQRot.Set (anXYZW[0].RealValue(), anXYZW[1].RealValue(), anXYZW[2].RealValue(), anXYZW[3].RealValue());
+    return Standard_True;
+  }
+
+}
+
 //=================================================================================================
 //function : VViewParams
 //purpose  : Gets or sets AIS View characteristics
 //=================================================================================================
 static int VViewParams (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
 {
-  Handle(V3d_View) anAISView = ViewerTest::CurrentView();
-  if (anAISView.IsNull())
+  Handle(V3d_View) aView = ViewerTest::CurrentView();
+  if (aView.IsNull())
   {
     std::cout << theArgVec[0] << ": please initialize or activate view.\n";
     return 1;
   }
 
+  Standard_Boolean toSetProj     = Standard_False;
+  Standard_Boolean toSetUp       = Standard_False;
+  Standard_Boolean toSetAt       = Standard_False;
+  Standard_Boolean toSetEye      = Standard_False;
+  Standard_Boolean toSetScale    = Standard_False;
+  Standard_Boolean toSetSize     = Standard_False;
+  Standard_Boolean toSetCenter2d = Standard_False;
+  Quantity_Factor  aViewScale = aView->Scale();
+  Quantity_Length  aViewSize  = 1.0;
+  Graphic3d_Vec2i  aCenter2d;
+  gp_XYZ aViewProj, aViewUp, aViewAt, aViewEye;
+  aView->Proj (aViewProj.ChangeCoord (1), aViewProj.ChangeCoord (2), aViewProj.ChangeCoord (3));
+  aView->Up   (aViewUp  .ChangeCoord (1), aViewUp  .ChangeCoord (2), aViewUp  .ChangeCoord (3));
+  aView->At   (aViewAt  .ChangeCoord (1), aViewAt  .ChangeCoord (2), aViewAt  .ChangeCoord (3));
+  aView->Eye  (aViewEye .ChangeCoord (1), aViewEye .ChangeCoord (2), aViewEye .ChangeCoord (3));
   if (theArgsNb == 1)
   {
     // print all of the available view parameters
-    Quantity_Factor anAISViewScale = anAISView->Scale();
-
-    Standard_Real anAISViewProjX = 0.0;
-    Standard_Real anAISViewProjY = 0.0;
-    Standard_Real anAISViewProjZ = 0.0;
-    anAISView->Proj (anAISViewProjX, anAISViewProjY, anAISViewProjZ);
-
-    Standard_Real anAISViewUpX = 0.0;
-    Standard_Real anAISViewUpY = 0.0;
-    Standard_Real anAISViewUpZ = 0.0;
-    anAISView->Up (anAISViewUpX, anAISViewUpY, anAISViewUpZ);
-
-    Standard_Real anAISViewAtX = 0.0;
-    Standard_Real anAISViewAtY = 0.0;
-    Standard_Real anAISViewAtZ = 0.0;
-    anAISView->At (anAISViewAtX, anAISViewAtY, anAISViewAtZ);
-
-    Standard_Real anAISViewEyeX = 0.0;
-    Standard_Real anAISViewEyeY = 0.0;
-    Standard_Real anAISViewEyeZ = 0.0;
-    anAISView->Eye (anAISViewEyeX, anAISViewEyeY, anAISViewEyeZ);
-
-    theDi << "Scale of current view: " << anAISViewScale << "\n";
-    theDi << "Proj on X : " << anAISViewProjX << "; on Y: " << anAISViewProjY << "; on Z: " << anAISViewProjZ << "\n";
-    theDi << "Up on X : " << anAISViewUpX << "; on Y: " << anAISViewUpY << "; on Z: " << anAISViewUpZ << "\n";
-    theDi << "At on X : " << anAISViewAtX << "; on Y: " << anAISViewAtY << "; on Z: " << anAISViewAtZ << "\n";
-    theDi << "Eye on X : " << anAISViewEyeX << "; on Y: " << anAISViewEyeY << "; on Z: " << anAISViewEyeZ << "\n";
+    char aText[4096];
+    Sprintf (aText,
+             "Scale: %g\n"
+             "Proj:  %12g %12g %12g\n"
+             "Up:    %12g %12g %12g\n"
+             "At:    %12g %12g %12g\n"
+             "Eye:   %12g %12g %12g\n",
+              aViewScale,
+              aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
+              aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
+              aViewAt.X(),   aViewAt.Y(),   aViewAt.Z(),
+              aViewEye.X(),  aViewEye.Y(),  aViewEye.Z());
+    theDi << aText;
     return 0;
   }
 
-  // -------------------------
-  //  Parse options and values
-  // -------------------------
-
-  NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)> aMapOfKeysByValues;
-  TCollection_AsciiString aParseKey;
-  for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
+  ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
   {
-    TCollection_AsciiString anArg (theArgVec [anArgIt]);
-
-    if (anArg.Value (1) == '-' && !anArg.IsRealValue())
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    if (anUpdateTool.parseRedrawMode (anArg))
     {
-      aParseKey = anArg;
-      aParseKey.Remove (1);
-      aParseKey.UpperCase();
-      aMapOfKeysByValues.Bind (aParseKey, new TColStd_HSequenceOfAsciiString);
       continue;
     }
+    else if (anArg == "-cmd"
+          || anArg == "-command"
+          || anArg == "-args")
+    {
+      char aText[4096];
+      Sprintf (aText,
+               "-scale %g "
+               "-proj %g %g %g "
+               "-up %g %g %g "
+               "-at %g %g %g\n",
+                aViewScale,
+                aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
+                aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
+                aViewAt.X(),   aViewAt.Y(),   aViewAt.Z());
+      theDi << aText;
+    }
+    else if (anArg == "-scale"
+          || anArg == "-size")
+    {
+      if (anArgIter + 1 < theArgsNb
+       && *theArgVec[anArgIter + 1] != '-')
+      {
+        const TCollection_AsciiString aValueArg (theArgVec[anArgIter + 1]);
+        if (aValueArg.IsRealValue())
+        {
+          ++anArgIter;
+          if (anArg == "-scale")
+          {
+            toSetScale = Standard_True;
+            aViewScale = aValueArg.RealValue();
+          }
+          else if (anArg == "-size")
+          {
+            toSetSize = Standard_True;
+            aViewSize = aValueArg.RealValue();
+          }
+          continue;
+        }
+      }
+      if (anArg == "-scale")
+      {
+        theDi << "Scale: " << aView->Scale() << "\n";
+      }
+      else if (anArg == "-size")
+      {
+        Graphic3d_Vec2d aSizeXY;
+        aView->Size (aSizeXY.x(), aSizeXY.y());
+        theDi << "Size: " << aSizeXY.x() << " " << aSizeXY.y() << "\n";
+      }
+    }
+    else if (anArg == "-eye"
+          || anArg == "-at"
+          || anArg == "-up"
+          || anArg == "-proj")
+    {
+      if (anArgIter + 3 < theArgsNb)
+      {
+        gp_XYZ anXYZ;
+        if (parseXYZ (theArgVec + anArgIter + 1, anXYZ))
+        {
+          anArgIter += 3;
+          if (anArg == "-eye")
+          {
+            toSetEye = Standard_True;
+            aViewEye = anXYZ;
+          }
+          else if (anArg == "-at")
+          {
+            toSetAt = Standard_True;
+            aViewAt = anXYZ;
+          }
+          else if (anArg == "-up")
+          {
+            toSetUp = Standard_True;
+            aViewUp = anXYZ;
+          }
+          else if (anArg == "-proj")
+          {
+            toSetProj = Standard_True;
+            aViewProj = anXYZ;
+          }
+          continue;
+        }
+      }
 
-    if (aParseKey.IsEmpty())
+      if (anArg == "-eye")
+      {
+        theDi << "Eye:  " << aViewEye.X() << " " << aViewEye.Y() << " " << aViewEye.Z() << "\n";
+      }
+      else if (anArg == "-at")
+      {
+        theDi << "At:   " << aViewAt.X() << " " << aViewAt.Y() << " " << aViewAt.Z() << "\n";
+      }
+      else if (anArg == "-up")
+      {
+        theDi << "Up:   " << aViewUp.X() << " " << aViewUp.Y() << " " << aViewUp.Z() << "\n";
+      }
+      else if (anArg == "-proj")
+      {
+        theDi << "Proj: " << aViewProj.X() << " " << aViewProj.Y() << " " << aViewProj.Z() << "\n";
+      }
+    }
+    else if (anArg == "-center")
     {
-      std::cout << theArgVec[0] << ": values should be passed with key.\n";
-      std::cout << "Type help for more information.\n";
+      if (anArgIter + 2 < theArgsNb)
+      {
+        const TCollection_AsciiString anX (theArgVec[anArgIter + 1]);
+        const TCollection_AsciiString anY (theArgVec[anArgIter + 2]);
+        if (anX.IsIntegerValue()
+         && anY.IsIntegerValue())
+        {
+          toSetCenter2d = Standard_True;
+          aCenter2d = Graphic3d_Vec2i (anX.IntegerValue(), anY.IntegerValue());
+        }
+      }
+    }
+    else
+    {
+      std::cout << "Syntax error at '" << anArg << "'\n";
       return 1;
     }
+  }
 
-    aMapOfKeysByValues(aParseKey)->Append (anArg);
+  // change view parameters in proper order
+  if (toSetScale)
+  {
+    aView->SetScale (aViewScale);
+  }
+  if (toSetSize)
+  {
+    aView->SetSize (aViewSize);
+  }
+  if (toSetEye)
+  {
+    aView->SetEye (aViewEye.X(), aViewEye.Y(), aViewEye.Z());
+  }
+  if (toSetAt)
+  {
+    aView->SetAt (aViewAt.X(), aViewAt.Y(), aViewAt.Z());
+  }
+  if (toSetProj)
+  {
+    aView->SetProj (aViewProj.X(), aViewProj.Y(), aViewProj.Z());
+  }
+  if (toSetUp)
+  {
+    aView->SetUp (aViewUp.X(), aViewUp.Y(), aViewUp.Z());
+  }
+  if (toSetCenter2d)
+  {
+    aView->SetCenter (aCenter2d.x(), aCenter2d.y());
   }
 
-  // ---------------------------------------------
-  //  Change or print parameters, order plays role
-  // ---------------------------------------------
+  return 0;
+}
 
-  // Check arguments for validity
-  NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)>::Iterator aMapIt (aMapOfKeysByValues);
-  for (; aMapIt.More(); aMapIt.Next())
+//==============================================================================
+//function : VAnimation
+//purpose  :
+//==============================================================================
+static Standard_Integer VAnimation (Draw_Interpretor& theDI,
+                                    Standard_Integer  theArgNb,
+                                    const char**      theArgVec)
+{
+  Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
+  if (theArgNb < 2)
   {
-    const TCollection_AsciiString& aKey = aMapIt.Key();
-    const Handle(TColStd_HSequenceOfAsciiString)& aValues = aMapIt.Value();
-
-    if (!(aKey.IsEqual ("SCALE")  && (aValues->Length() == 1 || aValues->IsEmpty()))
-     && !(aKey.IsEqual ("SIZE")   && (aValues->Length() == 1 || aValues->IsEmpty()))
-     && !(aKey.IsEqual ("EYE")    && (aValues->Length() == 3 || aValues->IsEmpty()))
-     && !(aKey.IsEqual ("AT")     && (aValues->Length() == 3 || aValues->IsEmpty()))
-     && !(aKey.IsEqual ("UP")     && (aValues->Length() == 3 || aValues->IsEmpty()))
-     && !(aKey.IsEqual ("PROJ")   && (aValues->Length() == 3 || aValues->IsEmpty()))
-     && !(aKey.IsEqual ("CENTER") &&  aValues->Length() == 2))
-    {
-      TCollection_AsciiString aLowerKey;
-      aLowerKey  = "-";
-      aLowerKey += aKey;
-      aLowerKey.LowerCase();
-      std::cout << theArgVec[0] << ": " << aLowerKey << " is unknown option, or number of arguments is invalid.\n";
-      std::cout << "Type help for more information.\n";
-      return 1;
+    for (NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)>::Iterator
+         anAnimIter (ViewerTest_AnimationTimelineMap); anAnimIter.More(); anAnimIter.Next())
+    {
+      theDI << anAnimIter.Key() << " " << anAnimIter.Value()->Duration() << " sec\n";
     }
+    return 0;
+  }
+  if (aCtx.IsNull())
+  {
+    std::cout << "Error: no active view\n";
+    return 1;
   }
 
-  Handle(TColStd_HSequenceOfAsciiString) aValues;
+  Standard_Integer anArgIter = 1;
+  TCollection_AsciiString aNameArg (theArgVec[anArgIter++]);
+  if (aNameArg.IsEmpty())
+  {
+    std::cout << "Syntax error: animation name is not defined.\n";
+    return 1;
+  }
+
+  TCollection_AsciiString aNameArgLower = aNameArg;
+  aNameArgLower.LowerCase();
+  if (aNameArgLower == "-reset"
+   || aNameArgLower == "-clear")
+  {
+    ViewerTest_AnimationTimelineMap.Clear();
+    return 0;
+  }
+  else if (aNameArg.Value (1) == '-')
+  {
+    std::cout << "Syntax error: invalid animation name '" << aNameArg  << "'.\n";
+    return 1;
+  }
 
-  // Change view parameters in proper order
-  if (aMapOfKeysByValues.Find ("SCALE", aValues))
+  const char* aNameSplitter = "/";
+  Standard_Integer aSplitPos = aNameArg.Search (aNameSplitter);
+  if (aSplitPos == -1)
   {
-    if (aValues->IsEmpty())
+    aNameSplitter = ".";
+    aSplitPos = aNameArg.Search (aNameSplitter);
+  }
+
+  // find existing or create a new animation by specified name within syntax "parent.child".
+  Handle(AIS_Animation) aRootAnimation, aParentAnimation, anAnimation;
+  for (; !aNameArg.IsEmpty();)
+  {
+    TCollection_AsciiString aNameParent;
+    if (aSplitPos != -1)
     {
-      theDi << "Scale: " << anAISView->Scale() << "\n";
+      if (aSplitPos == aNameArg.Length())
+      {
+        std::cout << "Syntax error: animation name is not defined.\n";
+        return 1;
+      }
+
+      aNameParent = aNameArg.SubString (            1, aSplitPos - 1);
+      aNameArg    = aNameArg.SubString (aSplitPos + 1, aNameArg.Length());
+
+      aSplitPos = aNameArg.Search (aNameSplitter);
     }
     else
     {
-      anAISView->SetScale (aValues->Value(1).RealValue());
+      aNameParent = aNameArg;
+      aNameArg.Clear();
     }
-  }
-  if (aMapOfKeysByValues.Find ("SIZE", aValues))
-  {
-    if (aValues->IsEmpty())
+
+    if (anAnimation.IsNull())
     {
-      Standard_Real aSizeX = 0.0;
-      Standard_Real aSizeY = 0.0;
-      anAISView->Size (aSizeX, aSizeY);
-      theDi << "Size X: " << aSizeX << " Y: " << aSizeY << "\n";
+      if (!ViewerTest_AnimationTimelineMap.Find (aNameParent, anAnimation))
+      {
+        anAnimation = new AIS_Animation (aNameParent);
+        ViewerTest_AnimationTimelineMap.Bind (aNameParent, anAnimation);
+      }
+      aRootAnimation = anAnimation;
     }
     else
     {
-      anAISView->SetSize (aValues->Value(1).RealValue());
+      aParentAnimation = anAnimation;
+      anAnimation = aParentAnimation->Find (aNameParent);
+      if (anAnimation.IsNull())
+      {
+        anAnimation = new AIS_Animation (aNameParent);
+        aParentAnimation->Add (anAnimation);
+      }
     }
   }
-  if (aMapOfKeysByValues.Find ("EYE", aValues))
+
+  if (anArgIter >= theArgNb)
   {
-    if (aValues->IsEmpty())
-    {
-      Standard_Real anEyeX = 0.0;
-      Standard_Real anEyeY = 0.0;
-      Standard_Real anEyeZ = 0.0;
-      anAISView->Eye (anEyeX, anEyeY, anEyeZ);
-      theDi << "Eye X: " << anEyeX << " Y: " << anEyeY << " Z: " << anEyeZ << "\n";
-    }
-    else
+    // just print the list of children
+    for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anAnimIter (anAnimation->Children()); anAnimIter.More(); anAnimIter.Next())
     {
-      anAISView->SetEye (aValues->Value(1).RealValue(), aValues->Value(2).RealValue(), aValues->Value(3).RealValue());
+      theDI << anAnimIter.Value()->Name() << " " << anAnimIter.Value()->Duration() << " sec\n";
     }
+    return 0;
   }
-  if (aMapOfKeysByValues.Find ("AT", aValues))
+
+  Standard_Boolean toPlay = Standard_False;
+  Standard_Real aPlaySpeed     = 1.0;
+  Standard_Real aPlayStartTime = anAnimation->StartPts();
+  Standard_Real aPlayDuration  = anAnimation->Duration();
+  Standard_Real aPlayFrameRate = 0.0;
+  Standard_Boolean isFreeCamera = Standard_False;
+  Standard_Boolean isLockLoop   = Standard_False;
+  Handle(V3d_View) aView = ViewerTest::CurrentView();
+  for (; anArgIter < theArgNb; ++anArgIter)
   {
-    if (aValues->IsEmpty())
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    if (anArg == "-reset"
+     || anArg == "-clear")
     {
-      Standard_Real anAtX = 0.0;
-      Standard_Real anAtY = 0.0;
-      Standard_Real anAtZ = 0.0;
-      anAISView->At (anAtX, anAtY, anAtZ);
-      theDi << "At X: " << anAtX << " Y: " << anAtY << " Z: " << anAtZ << "\n";
+      anAnimation->Clear();
+    }
+    else if (anArg == "-remove"
+          || anArg == "-del"
+          || anArg == "-delete")
+    {
+      if (!aParentAnimation.IsNull())
+      {
+        ViewerTest_AnimationTimelineMap.UnBind (anAnimation->Name());
+      }
+      else
+      {
+        aParentAnimation->Remove (anAnimation);
+      }
+    }
+    else if (anArg == "-play")
+    {
+      toPlay = Standard_True;
+      if (++anArgIter < theArgNb)
+      {
+        if (*theArgVec[anArgIter] == '-')
+        {
+          --anArgIter;
+          continue;
+        }
+        aPlayStartTime = Draw::Atof (theArgVec[anArgIter]);
+
+        if (++anArgIter < theArgNb)
+        {
+          if (*theArgVec[anArgIter] == '-')
+          {
+            --anArgIter;
+            continue;
+          }
+          aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
+        }
+      }
+    }
+    else if (anArg == "-resume")
+    {
+      toPlay = Standard_True;
+      aPlayStartTime = anAnimation->ElapsedTime();
+      if (++anArgIter < theArgNb)
+      {
+        if (*theArgVec[anArgIter] == '-')
+        {
+          --anArgIter;
+          continue;
+        }
+
+        aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
+      }
+    }
+    else if (anArg == "-playspeed"
+          || anArg == "-speed")
+    {
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+      aPlaySpeed = Draw::Atof (theArgVec[anArgIter]);
+    }
+    else if (anArg == "-lock"
+          || anArg == "-lockloop"
+          || anArg == "-playlockloop")
+    {
+      isLockLoop = Standard_True;
+    }
+    else if (anArg == "-freecamera"
+          || anArg == "-playfreecamera"
+          || anArg == "-freelook")
+    {
+      isFreeCamera = Standard_True;
+    }
+    else if (anArg == "-fps")
+    {
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+      aPlayFrameRate = Draw::Atof (theArgVec[anArgIter]);
+    }
+    else if (anArg == "-start"
+          || anArg == "-starttime"
+          || anArg == "-startpts")
+    {
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+
+      anAnimation->SetStartPts (Draw::Atof (theArgVec[anArgIter]));
+      aRootAnimation->UpdateTotalDuration();
+    }
+    else if (anArg == "-end"
+          || anArg == "-endtime"
+          || anArg == "-endpts")
+    {
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+
+      anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]) - anAnimation->StartPts());
+      aRootAnimation->UpdateTotalDuration();
+    }
+    else if (anArg == "-dur"
+          || anArg == "-duration")
+    {
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+
+      anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]));
+      aRootAnimation->UpdateTotalDuration();
+    }
+    else if (anArg == "-command"
+          || anArg == "-cmd"
+          || anArg == "-invoke"
+          || anArg == "-eval"
+          || anArg == "-proc")
+    {
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+
+      Handle(ViewerTest_AnimationProc) aCmdAnimation = new ViewerTest_AnimationProc (anAnimation->Name(), &theDI, theArgVec[anArgIter]);
+      replaceAnimation (aParentAnimation, anAnimation, aCmdAnimation);
+    }
+    else if (anArg == "-objecttrsf"
+          || anArg == "-objectransformation"
+          || anArg == "-objtransformation"
+          || anArg == "-objtrsf"
+          || anArg == "-object"
+          || anArg == "-obj")
+    {
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+
+      TCollection_AsciiString anObjName (theArgVec[anArgIter]);
+      const ViewerTest_DoubleMapOfInteractiveAndName& aMapOfAIS = GetMapOfAIS();
+      if (!aMapOfAIS.IsBound2 (anObjName))
+      {
+        std::cout << "Syntax error: wrong object name at " << anArg << "\n";
+        return 1;
+      }
+
+      Handle(AIS_InteractiveObject) anObject = Handle(AIS_InteractiveObject)::DownCast (aMapOfAIS.Find2 (anObjName));
+      gp_Trsf       aTrsfs   [2] = { anObject->LocalTransformation(), anObject->LocalTransformation() };
+      gp_Quaternion aRotQuats[2] = { aTrsfs[0].GetRotation(),         aTrsfs[1].GetRotation() };
+      gp_XYZ        aLocPnts [2] = { aTrsfs[0].TranslationPart(),     aTrsfs[1].TranslationPart() };
+      Standard_Real aScales  [2] = { aTrsfs[0].ScaleFactor(),         aTrsfs[1].ScaleFactor() };
+      Standard_Boolean isTrsfSet = Standard_False;
+      Standard_Integer aTrsfArgIter = anArgIter + 1;
+      for (; aTrsfArgIter < theArgNb; ++aTrsfArgIter)
+      {
+        TCollection_AsciiString aTrsfArg (theArgVec[aTrsfArgIter]);
+        aTrsfArg.LowerCase();
+        const Standard_Integer anIndex = aTrsfArg.EndsWith ("1") ? 0 : 1;
+        if (aTrsfArg.StartsWith ("-rotation")
+         || aTrsfArg.StartsWith ("-rot"))
+        {
+          isTrsfSet = Standard_True;
+          if (aTrsfArgIter + 4 >= theArgNb
+          || !parseQuaternion (theArgVec + aTrsfArgIter + 1, aRotQuats[anIndex]))
+          {
+            std::cout << "Syntax error at " << aTrsfArg << ".\n";
+            return 1;
+          }
+          aTrsfArgIter += 4;
+        }
+        else if (aTrsfArg.StartsWith ("-location")
+              || aTrsfArg.StartsWith ("-loc"))
+        {
+          isTrsfSet = Standard_True;
+          if (aTrsfArgIter + 3 >= theArgNb
+          || !parseXYZ (theArgVec + aTrsfArgIter + 1, aLocPnts[anIndex]))
+          {
+            std::cout << "Syntax error at " << aTrsfArg << ".\n";
+            return 1;
+          }
+          aTrsfArgIter += 3;
+        }
+        else if (aTrsfArg.StartsWith ("-scale"))
+        {
+          isTrsfSet = Standard_True;
+          if (++aTrsfArgIter >= theArgNb)
+          {
+            std::cout << "Syntax error at " << aTrsfArg << ".\n";
+            return 1;
+          }
+
+          const TCollection_AsciiString aScaleStr (theArgVec[aTrsfArgIter]);
+          if (!aScaleStr.IsRealValue())
+          {
+            std::cout << "Syntax error at " << aTrsfArg << ".\n";
+            return 1;
+          }
+          aScales[anIndex] = aScaleStr.RealValue();
+        }
+        else
+        {
+          anArgIter = aTrsfArgIter - 1;
+          break;
+        }
+      }
+      if (!isTrsfSet)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+      else if (aTrsfArgIter >= theArgNb)
+      {
+        anArgIter = theArgNb;
+      }
+
+      aTrsfs[0].SetRotation        (aRotQuats[0]);
+      aTrsfs[1].SetRotation        (aRotQuats[1]);
+      aTrsfs[0].SetTranslationPart (aLocPnts[0]);
+      aTrsfs[1].SetTranslationPart (aLocPnts[1]);
+      aTrsfs[0].SetScaleFactor     (aScales[0]);
+      aTrsfs[1].SetScaleFactor     (aScales[1]);
+
+      Handle(AIS_AnimationObject) anObjAnimation = new AIS_AnimationObject (anAnimation->Name(), aCtx, anObject, aTrsfs[0], aTrsfs[1]);
+      replaceAnimation (aParentAnimation, anAnimation, anObjAnimation);
+    }
+    else if (anArg == "-viewtrsf"
+          || anArg == "-view")
+    {
+      Handle(AIS_AnimationCamera) aCamAnimation = Handle(AIS_AnimationCamera)::DownCast (anAnimation);
+      if (aCamAnimation.IsNull())
+      {
+        aCamAnimation = new AIS_AnimationCamera (anAnimation->Name(), aView);
+        replaceAnimation (aParentAnimation, anAnimation, aCamAnimation);
+      }
+
+      Handle(Graphic3d_Camera) aCams[2] =
+      {
+        new Graphic3d_Camera (aCamAnimation->View()->Camera()),
+        new Graphic3d_Camera (aCamAnimation->View()->Camera())
+      };
+
+      Standard_Boolean isTrsfSet = Standard_False;
+      Standard_Integer aViewArgIter = anArgIter + 1;
+      for (; aViewArgIter < theArgNb; ++aViewArgIter)
+      {
+        TCollection_AsciiString aViewArg (theArgVec[aViewArgIter]);
+        aViewArg.LowerCase();
+        const Standard_Integer anIndex = aViewArg.EndsWith("1") ? 0 : 1;
+        if (aViewArg.StartsWith ("-scale"))
+        {
+          isTrsfSet = Standard_True;
+          if (++aViewArgIter >= theArgNb)
+          {
+            std::cout << "Syntax error at " << anArg << ".\n";
+            return 1;
+          }
+
+          const TCollection_AsciiString aScaleStr (theArgVec[aViewArgIter]);
+          if (!aScaleStr.IsRealValue())
+          {
+            std::cout << "Syntax error at " << aViewArg << ".\n";
+            return 1;
+          }
+          Standard_Real aScale = aScaleStr.RealValue();
+          aScale = aCamAnimation->View()->DefaultCamera()->Scale() / aScale;
+          aCams[anIndex]->SetScale (aScale);
+        }
+        else if (aViewArg.StartsWith ("-eye")
+              || aViewArg.StartsWith ("-center")
+              || aViewArg.StartsWith ("-at")
+              || aViewArg.StartsWith ("-up"))
+        {
+          isTrsfSet = Standard_True;
+          gp_XYZ anXYZ;
+          if (aViewArgIter + 3 >= theArgNb
+          || !parseXYZ (theArgVec + aViewArgIter + 1, anXYZ))
+          {
+            std::cout << "Syntax error at " << aViewArg << ".\n";
+            return 1;
+          }
+          aViewArgIter += 3;
+
+          if (aViewArg.StartsWith ("-eye"))
+          {
+            aCams[anIndex]->SetEye (anXYZ);
+          }
+          else if (aViewArg.StartsWith ("-center")
+                || aViewArg.StartsWith ("-at"))
+          {
+            aCams[anIndex]->SetCenter (anXYZ);
+          }
+          else if (aViewArg.StartsWith ("-up"))
+          {
+            aCams[anIndex]->SetUp (anXYZ);
+          }
+        }
+        else
+        {
+          anArgIter = aViewArgIter - 1;
+          break;
+        }
+      }
+      if (!isTrsfSet)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+      else if (aViewArgIter >= theArgNb)
+      {
+        anArgIter = theArgNb;
+      }
+
+      aCamAnimation->SetCameraStart(aCams[0]);
+      aCamAnimation->SetCameraEnd  (aCams[1]);
     }
     else
     {
-      anAISView->SetAt (aValues->Value(1).RealValue(), aValues->Value(2).RealValue(), aValues->Value(3).RealValue());
+      std::cout << "Syntax error at " << anArg << ".\n";
+      return 1;
     }
   }
-  if (aMapOfKeysByValues.Find ("PROJ", aValues))
+
+  if (!toPlay)
   {
-    if (aValues->IsEmpty())
+    return 0;
+  }
+
+  // Start animation timeline and process frame updating.
+  TheIsAnimating = Standard_True;
+  const Standard_Boolean wasImmediateUpdate = aView->SetImmediateUpdate (Standard_False);
+  Handle(Graphic3d_Camera) aCameraBack = new Graphic3d_Camera (aView->Camera());
+  anAnimation->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True);
+  if (isFreeCamera)
+  {
+    aView->Camera()->Copy (aCameraBack);
+  }
+
+  const Standard_Real anUpperPts = aPlayStartTime + aPlayDuration;
+  if (aPlayFrameRate < Precision::Confusion())
+  {
+    while (!anAnimation->IsStopped())
     {
-      Standard_Real aProjX = 0.0;
-      Standard_Real aProjY = 0.0;
-      Standard_Real aProjZ = 0.0;
-      anAISView->Proj (aProjX, aProjY, aProjZ);
-      theDi << "Proj X: " << aProjX << " Y: " << aProjY << " Z: " << aProjZ << "\n";
+      aCameraBack->Copy (aView->Camera());
+      const Standard_Real aPts = anAnimation->UpdateTimer();
+      if (isFreeCamera)
+      {
+        aView->Camera()->Copy (aCameraBack);
+      }
+
+      if (aPts >= anUpperPts)
+      {
+        anAnimation->Pause();
+        break;
+      }
+
+      if (aView->IsInvalidated())
+      {
+        aView->Redraw();
+      }
+      else
+      {
+        aView->RedrawImmediate();
+      }
+
+      if (!isLockLoop)
+      {
+        // handle user events
+        theDI.Eval ("after 1 set waiter 1");
+        theDI.Eval ("vwait waiter");
+      }
+      if (!TheIsAnimating)
+      {
+        anAnimation->Pause();
+        theDI << aPts;
+        break;
+      }
+    }
+
+    if (aView->IsInvalidated())
+    {
+      aView->Redraw();
     }
     else
     {
-      anAISView->SetProj (aValues->Value(1).RealValue(), aValues->Value(2).RealValue(), aValues->Value(3).RealValue());
+      aView->RedrawImmediate();
     }
   }
-  if (aMapOfKeysByValues.Find ("UP", aValues))
+  else
   {
-    if (aValues->IsEmpty())
+    Standard_Real aMaxFPS = 0.0;
+
+    // Manage frame-rated animation here
+    Standard_Real aPts = aPlayStartTime;
+    while (aPts <= anUpperPts)
     {
-      Standard_Real anUpX = 0.0;
-      Standard_Real anUpY = 0.0;
-      Standard_Real anUpZ = 0.0;
-      anAISView->Up (anUpX, anUpY, anUpZ);
-      theDi << "Up X: " << anUpX << " Y: " << anUpY << " Z: " << anUpZ << "\n";
+      if (!anAnimation->Update (aPts))
+      {
+        break;
+      }
+
+      Standard_Real aProgress = anAnimation->ElapsedTime();
+      Standard_Real aNextRatedPts = aPts + 1.0 / aPlayFrameRate;
+      Standard_Real aPrevPts = aPts;
+      aPts = aNextRatedPts <  aProgress ? aNextRatedPts : aProgress;
+      Standard_Real aCurrentFPS = 1.0 / (aPts - aPrevPts);
+      if (aMaxFPS < aCurrentFPS)
+      {
+        aMaxFPS = aCurrentFPS;
+      }
+    }
+
+    if (aView->IsInvalidated())
+    {
+      aView->Redraw();
     }
     else
     {
-      anAISView->SetUp (aValues->Value(1).RealValue(), aValues->Value(2).RealValue(), aValues->Value(3).RealValue());
+      aView->RedrawImmediate();
     }
-  }
-  if (aMapOfKeysByValues.Find ("CENTER", aValues))
-  {
-    anAISView->SetCenter (aValues->Value(1).IntegerValue(), aValues->Value(2).IntegerValue());
+    anAnimation->Stop();
+    theDI << aMaxFPS;
   }
 
+  aView->SetImmediateUpdate (wasImmediateUpdate);
+  TheIsAnimating = Standard_False;
   return 0;
 }
 
+
 //=======================================================================
 //function : VChangeSelected
 //purpose  : Adds the shape to selection or remove one from it
@@ -9411,8 +10133,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
   theCommands.Add("vpick" ,
     "vpick           : vpick X Y Z [shape subshape] ( all variables as string )",
     VPick,group);
-  theCommands.Add("vfit"    ,
-    "vfit or <F> [-selected]"
+  theCommands.Add("vfit",
+    "vfit or <F> [-selected] [-noupdate]"
     "\n\t\t: [-selected] fits the scene according to bounding box of currently selected objects",
     __FILE__,VFit,group);
   theCommands.Add ("vfitarea",
@@ -9662,22 +10384,73 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "vmoveto x y"
     "- emulates cursor movement to pixel postion (x,y)",
     __FILE__, VMoveTo, group);
-  theCommands.Add ("vviewparams", "vviewparams usage:\n"
-    "- vviewparams\n"
-    "- vviewparams [-scale [s]] [-eye [x y z]] [-at [x y z]] [-up [x y z]]\n"
-    "              [-proj [x y z]] [-center x y] [-size sx]\n"
-    "-   Gets or sets current view parameters.\n"
-    "-   If called without arguments, all view parameters are printed.\n"
-    "-   The options are:\n"
-    "      -scale [s]    : prints or sets viewport relative scale.\n"
-    "      -eye [x y z]  : prints or sets eye location.\n"
-    "      -at [x y z]   : prints or sets center of look.\n"
-    "      -up [x y z]   : prints or sets direction of up vector.\n"
-    "      -proj [x y z] : prints or sets direction of look.\n"
-    "      -center x y   : sets location of center of the screen in pixels.\n"
-    "      -size [sx]    : prints viewport projection width and height sizes\n"
-    "                    : or changes the size of its maximum dimension.\n",
+  theCommands.Add ("vviewparams",
+              "vviewparams [-args] [-scale [s]]"
+      "\n\t\t:             [-eye [x y z]] [-at [x y z]] [-up [x y z]]"
+      "\n\t\t:             [-proj [x y z]] [-center x y] [-size sx]"
+      "\n\t\t: Manage current view parameters or prints all"
+      "\n\t\t: current values when called without argument."
+      "\n\t\t:   -scale [s]    prints or sets viewport relative scale"
+      "\n\t\t:   -eye  [x y z] prints or sets eye location"
+      "\n\t\t:   -at   [x y z] prints or sets center of look"
+      "\n\t\t:   -up   [x y z] prints or sets direction of up vector"
+      "\n\t\t:   -proj [x y z] prints or sets direction of look"
+      "\n\t\t:   -center x y   sets location of center of the screen in pixels"
+      "\n\t\t:   -size [sx]    prints viewport projection width and height sizes"
+      "\n\t\t:                 or changes the size of its maximum dimension"
+      "\n\t\t:   -args         prints vviewparams arguments for restoring current view",
     __FILE__, VViewParams, group);
+
+  theCommands.Add("vanimation", "Alias for vanim",
+    __FILE__, VAnimation, group);
+
+  theCommands.Add("vanim",
+            "List existing animations:"
+    "\n\t\t:  vanim"
+    "\n\t\t: Animation playback:"
+    "\n\t\t:  vanim name -play|-resume [playFrom [playDuration]]"
+    "\n\t\t:            [-speed Coeff] [-freeLook] [-lockLoop]"
+    "\n\t\t:   -speed    playback speed (1.0 is normal speed)"
+    "\n\t\t:   -freeLook skip camera animations"
+    "\n\t\t:   -lockLoop disable any interactions"
+    "\n\t\t:"
+    "\n\t\t: Animation definition:"
+    "\n\t\t:  vanim Name/sub/name [-clear] [-delete]"
+    "\n\t\t:        [start TimeSec] [duration TimeSec]"
+    "\n\t\t:"
+    "\n\t\t: Animation name defined in path-style (anim/name or anim.name)"
+    "\n\t\t: specifies nested animations."
+    "\n\t\t: There is no syntax to explicitly add new animation,"
+    "\n\t\t: and all non-existing animations within the name will be"
+    "\n\t\t: implicitly created on first use (including parents)."
+    "\n\t\t:"
+    "\n\t\t: Each animation might define the SINGLE action (see below),"
+    "\n\t\t: like camera transition, object transformation or custom callback."
+    "\n\t\t: Child animations can be used for defining concurrent actions."
+    "\n\t\t:"
+    "\n\t\t: Camera animation:"
+    "\n\t\t:  vanim name -view [-eye1 X Y Z] [-eye2 X Y Z]"
+    "\n\t\t:                   [-at1  X Y Z] [-at2  X Y Z]"
+    "\n\t\t:                   [-up1  X Y Z] [-up2  X Y Z]"
+    "\n\t\t:                   [-scale1 Scale] [-scale2 Scale]"
+    "\n\t\t:   -eyeX   camera Eye positions pair (start and end)"
+    "\n\t\t:   -atX    camera Center positions pair"
+    "\n\t\t:   -upX    camera Up directions pair"
+    "\n\t\t:   -scaleX camera Scale factors pair"
+    "\n\t\t: Object animation:"
+    "\n\t\t:  vanim name -object [-loc1 X Y Z] [-loc2 X Y Z]"
+    "\n\t\t:                     [-rot1 QX QY QZ QW] [-rot2 QX QY QZ QW]"
+    "\n\t\t:                     [-scale1 Scale] [-scale2 Scale]"
+    "\n\t\t:   -locX   object Location points pair (translation)"
+    "\n\t\t:   -rotX   object Orientations pair (quaternions)"
+    "\n\t\t:   -scaleX object Scale factors pair (quaternions)"
+    "\n\t\t: Custom callback:"
+    "\n\t\t:  vanim name -invoke \"Command Arg1 Arg2 %Pts %LocalPts %Normalized ArgN\""
+    "\n\t\t:   %Pts        overall animation presentation timestamp"
+    "\n\t\t:   %LocalPts   local animation timestamp"
+    "\n\t\t:   %Normalized local animation normalized value in range 0..1"
+    __FILE__, VAnimation, group);
+
   theCommands.Add("vchangeselected",
     "vchangeselected shape"
     "- adds to shape to selection or remove one from it",
index 859d37a..b715338 100644 (file)
@@ -98,6 +98,7 @@ gp_Trsf2d.cxx
 gp_Trsf2d.hxx
 gp_Trsf2d.lxx
 gp_TrsfForm.hxx
+gp_TrsfNLerp.hxx
 gp_Vec.cxx
 gp_Vec.hxx
 gp_Vec.lxx
index 00924e9..42be792 100644 (file)
 
 #include <gp_Quaternion.hxx>
 
-/**
- * Class perform linear interpolation (approximate rotation interpolation),
- * result quaternion nonunit, its length lay between. sqrt(2)/2  and 1.0
- */
+//! Class perform linear interpolation (approximate rotation interpolation),
+//! result quaternion nonunit, its length lay between. sqrt(2)/2  and 1.0
 class gp_QuaternionNLerp
 {
+public:
+
+  //! Compute interpolated quaternion between two quaternions.
+  //! @param theStart first  quaternion
+  //! @param theEnd   second quaternion
+  //! @param theT normalized interpolation coefficient within 0..1 range,
+  //!             with 0 pointing to theStart and 1 to theEnd.
+  static gp_Quaternion Interpolate (const gp_Quaternion& theQStart,
+                                    const gp_Quaternion& theQEnd,
+                                    Standard_Real theT)
+  {
+    gp_Quaternion aResult;
+    gp_QuaternionNLerp aLerp (theQStart, theQEnd);
+    aLerp.Interpolate (theT, aResult);
+    return aResult;
+  }
 
 public:
 
+  //! Empty constructor,
   gp_QuaternionNLerp() {}
 
+  //! Constructor with initialization.
   gp_QuaternionNLerp (const gp_Quaternion& theQStart, const gp_Quaternion& theQEnd)
   {
     Init (theQStart, theQEnd);
   }
 
+  //! Initialize the tool with Start and End values.
   void Init (const gp_Quaternion& theQStart, const gp_Quaternion& theQEnd)
   {
     InitFromUnit (theQStart.Normalized(), theQEnd.Normalized());
   }
 
+  //! Initialize the tool with Start and End unit quaternions.
   void InitFromUnit (const gp_Quaternion& theQStart, const gp_Quaternion& theQEnd)
   {
     myQStart = theQStart;
@@ -55,16 +73,6 @@ public:
     theResultQ = myQStart + myQEnd * theT;
   }
 
-  static gp_Quaternion Interpolate (const gp_Quaternion& theQStart,
-                                    const gp_Quaternion& theQEnd,
-                                    Standard_Real theT)
-  {
-    gp_Quaternion aResultQ;
-    gp_QuaternionNLerp aNLerp (theQStart, theQEnd);
-    aNLerp.Interpolate (theT, aResultQ);
-    return aResultQ;
-  }
-
 private:
 
   gp_Quaternion myQStart;
index efe6534..9893f78 100644 (file)
 
 #include <gp_Quaternion.hxx>
 
-/**
- * Perform Spherical Linear Interpolation of the quaternions,
- * return unit length quaternion.
- */
+//! Perform Spherical Linear Interpolation of the quaternions,
+//! return unit length quaternion.
 class gp_QuaternionSLerp
 {
+public:
+
+  //! Compute interpolated quaternion between two quaternions.
+  //! @param theStart first  quaternion
+  //! @param theEnd   second quaternion
+  //! @param theT normalized interpolation coefficient within 0..1 range,
+  //!             with 0 pointing to theStart and 1 to theEnd.
+  static gp_Quaternion Interpolate (const gp_Quaternion& theQStart,
+                                    const gp_Quaternion& theQEnd,
+                                    Standard_Real theT)
+  {
+    gp_Quaternion aResult;
+    gp_QuaternionSLerp aLerp (theQStart, theQEnd);
+    aLerp.Interpolate (theT, aResult);
+    return aResult;
+  }
 
 public:
 
+  //! Empty constructor,
   gp_QuaternionSLerp() {}
 
+  //! Constructor with initialization.
   gp_QuaternionSLerp (const gp_Quaternion& theQStart, const gp_Quaternion& theQEnd)
   {
     Init (theQStart, theQEnd);
   }
 
+  //! Initialize the tool with Start and End values.
   void Init (const gp_Quaternion& theQStart, const gp_Quaternion& theQEnd)
   {
     InitFromUnit (theQStart.Normalized(), theQEnd.Normalized());
   }
 
+  //! Initialize the tool with Start and End unit quaternions.
   void InitFromUnit (const gp_Quaternion& theQStart, const gp_Quaternion& theQEnd)
   {
     myQStart = theQStart;
diff --git a/src/gp/gp_TrsfNLerp.hxx b/src/gp/gp_TrsfNLerp.hxx
new file mode 100644 (file)
index 0000000..dcf26b1
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright (c) 2016 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _gp_TrsfNLerp_HeaderFile
+#define _gp_TrsfNLerp_HeaderFile
+
+#include <gp_Trsf.hxx>
+#include <gp_QuaternionNLerp.hxx>
+#include <NCollection_Lerp.hxx>
+#include <Precision.hxx>
+
+//! Linear interpolation tool for transformation defined by gp_Trsf.
+//!
+//! In general case, there is a no well-defined interpolation between arbitrary transformations,
+//! because desired transient values might vary depending on application needs.
+//!
+//! This tool performs independent interpolation of three logical
+//! transformation parts - rotation (using gp_QuaternionNLerp), translation and scale factor.
+//! Result of such interpolation might be not what application expects,
+//! thus this tool might be considered for simple cases or for interpolating between small intervals.
+template<> class NCollection_Lerp<gp_Trsf>
+{
+public:
+
+  //! Empty constructor
+  NCollection_Lerp() {}
+
+  //! Main constructor.
+  NCollection_Lerp (const gp_Trsf& theStart, const gp_Trsf& theEnd)
+  {
+    Init (theStart, theEnd);
+  }
+
+  //! Initialize values.
+  void Init (const gp_Trsf& theStart, const gp_Trsf& theEnd)
+  {
+    myTrsfStart = theStart;
+    myTrsfEnd   = theEnd;
+    myLocLerp  .Init (theStart.TranslationPart(), theEnd.TranslationPart());
+    myRotLerp  .Init (theStart.GetRotation(),     theEnd.GetRotation());
+    myScaleLerp.Init (theStart.ScaleFactor(),     theEnd.ScaleFactor());
+  }
+
+  //! Compute interpolated value between two values.
+  //! @param theT normalized interpolation coefficient within [0, 1] range,
+  //!             with 0 pointing to first value and 1 to the second value.
+  //! @param theResult [out] interpolated value
+  void Interpolate (double theT, gp_Trsf& theResult) const
+  {
+    if (Abs (theT - 0.0) < Precision::Confusion())
+    {
+      theResult = myTrsfStart;
+      return;
+    }
+    else if (Abs (theT - 1.0) < Precision::Confusion())
+    {
+      theResult = myTrsfEnd;
+      return;
+    }
+
+    gp_XYZ aLoc;
+    gp_Quaternion aRot;
+    Standard_Real aScale = 1.0;
+    myLocLerp  .Interpolate (theT, aLoc);
+    myRotLerp  .Interpolate (theT, aRot);
+    myScaleLerp.Interpolate (theT, aScale);
+    theResult = gp_Trsf();
+    theResult.SetRotation (aRot);
+    theResult.SetTranslationPart (aLoc);
+    theResult.SetScaleFactor (aScale);
+  }
+
+private:
+  NCollection_Lerp<gp_XYZ>        myLocLerp;
+  NCollection_Lerp<Standard_Real> myScaleLerp;
+  gp_QuaternionNLerp              myRotLerp;
+  gp_Trsf                         myTrsfStart;
+  gp_Trsf                         myTrsfEnd;
+};
+
+typedef NCollection_Lerp<gp_Trsf> gp_TrsfNLerp;
+
+#endif // _gp_TrsfNLerp_HeaderFile
index 451488e..f74eef4 100644 (file)
@@ -23,7 +23,7 @@ set aNb 1000
 # display as copies
 eval compound [lrepeat $aNb s] ss
 explode ss
-for {set i 1} {$i <= $aNb} {incr i} { vloadselection ss_${i}; vsetlocation -noupdate ss_${i} 0 0 s }
+for {set i 1} {$i <= $aNb} {incr i} { vloadselection ss_${i}; vsetlocation -noupdate ss_${i} ${i} 0 0 }
 vfit
 set aMemSel1  [meminfo h]
 vclear
index 20c19db..85c14da 100644 (file)
@@ -14,27 +14,27 @@ vdisplay b1
 vconnectto b2 6 0 0 b1
 box b3 7 1 1
 vdisplay b3
-vloctranslate b3 0 4 0
+vlocation b3 -translate 0 4 0
 vconnect z 0 0 0 b1 b2 b3
 
 vconnect z1 0 0 0 z
-vloctranslate z1 10 0 0
+vlocation z1 -translate 10 0 0
 
 vconnect z2 0 10 0 z
-vlocrotate z2 0 0 0 1 0 0 90
+vlocation z2 -rotate 0 0 0 1 0 0 90
 
 vconnect z3 -10 0 0 z
-vlocscale z3 0 0 0 0.5
+vlocation z3 -scale 0 0 0 0.5
 
 vconnect z4 0 0 0 z
-vlocmove z4 z3
+vlocation z4 -copyFrom z3
 
 psphere sp 3
 vdisplay sp
-vlocmove sp z3
-vlocreset sp
+vlocation sp -copyFrom z3
+vlocation sp -reset
 
-vlocmirror z 0 -0.5 0 0 1 0
+vlocation z -mirror 0 -0.5 0 0 1 0
 vfit
 
 vdump $imagedir/${casename}.png
index 8b1bbbe..31e3367 100644 (file)
@@ -27,7 +27,7 @@ set aNb 1000
 # display as copies
 eval compound [lrepeat $aNb s] ss
 explode ss
-for {set i 1} {$i <= $aNb} {incr i} { vdisplay -noupdate ss_${i}; vsetlocation -noupdate ss_${i} 0 0 s }
+for {set i 1} {$i <= $aNb} {incr i} { vdisplay -noupdate ss_${i}; vsetlocation -noupdate ss_${i} ${i} 0 0 }
 vfit
 set aMemDisp1  [meminfo h]
 vclear
index 36ea93d..8854b47 100755 (executable)
@@ -19,7 +19,7 @@ vdisplay b
 
 vfit
 
-vlocrotate b 0 0 0 0 0 1 50
+vlocation b -rotate 0 0 0 0 0 1 50
 
 vmoveto 380 50
 checkcolor 380 50 0.87450981140136719 0 0.12156862765550613
diff --git a/tests/v3d/anim/objects b/tests/v3d/anim/objects
new file mode 100644 (file)
index 0000000..92a5f0c
--- /dev/null
@@ -0,0 +1,34 @@
+puts "=================================="
+puts "Viewer animation - animate object moving"
+puts "=================================="
+
+pload MODELING VISUALIZATION
+
+vclear
+vinit View1
+vaxo
+
+psphere s 50
+box b1 -50 -50 0 100 100 100
+vdisplay -dispMode 1 b1 s
+
+vviewparams -scale 2.499 -proj 0.546611 -0.600024 -0.584114 -up -0.411832 0.414728 -0.811415 -at -5.3425 -2.983 49.216
+
+vanimation anim -clear
+vanimation anim/obj1 -objectTrsf b1 -loc1 0 0 0 -loc2 -100 0 -100 -start 0 -duration 2
+vanimation anim/obj2 -objectTrsf s  -loc1 0 0 0 -loc2  100 0  100 -start 1 -duration 2
+
+vanimation anim -play 0.0 0.0
+vdump $imagedir/${casename}_0.png
+
+vanimation anim -play 1.0 0.0
+vdump $imagedir/${casename}_1.png
+
+vanimation anim -play 2.0 0.0
+vdump $imagedir/${casename}_2.png
+
+if {[vreadpixel 270  20 rgb name] != "DARKGOLDENROD3"} { puts "Error: Box moving result is wrong!" }
+if {[vreadpixel 120 255 rgb name] != "DARKGOLDENROD4"} { puts "Error: Sphere moving result is wrong!" }
+
+puts "Put the following command to start interactive animation:"
+puts "    vanimation anim -play"
diff --git a/tests/v3d/anim/propeller b/tests/v3d/anim/propeller
new file mode 100644 (file)
index 0000000..dfbe491
--- /dev/null
@@ -0,0 +1,116 @@
+puts "=================================="
+puts "Viewer animation - Propeller animation"
+puts "Regressions should be detected visually"
+puts "=================================="
+
+pload MODELING VISUALIZATION
+restore [locate_data_file occ/CrankArm.rle]     a
+restore [locate_data_file occ/CylinderHead.rle] h
+restore [locate_data_file occ/Propeller.rle]    p
+restore [locate_data_file occ/EngineBlock.rle]  e
+
+vclear
+vinit name=View1 width=912 height=512
+vzbufftrihedron
+vcamera -persp -fovy 60
+vdisplay -dispMode 1 -mutable a h p e
+vfit
+vsetcolor p GREEN
+vsetcolor e RED
+vsetcolor h PURPLE
+
+vanimation anim -clear
+
+# custom callback
+proc drawAnimLabels    {thePts}        { vdrawtext lab "Current PTS: $thePts sec" -2d -persPos -1 1 30 -noupdate }
+#proc drawAnimPropeller {theLocalPts}   { set aVal 0.0; if { $theLocalPts >= 1.0 && $theLocalPts <= 1.5 } { set aVal 0.9 }; vaspects -noupdate p -setTransparency $aVal }
+proc drawAnimProp1     {theNormalized} { vaspects -noupdate p -setTransparency [expr $theNormalized * 0.9] }
+proc drawAnimProp2     {theNormalized} { vaspects -noupdate p -setTransparency [expr (1.0 - $theNormalized) * 0.9] }
+vanimation anim/cmd/1 -start 0   -dur 2.0 -cmd "drawAnimLabels %pts"
+#vanimation anim/cmd/2 -start 0   -dur 2.0 -cmd "drawAnimPropeller %localPts"
+vanimation anim/cmd/2 -start 1.0  -dur 0.1 -cmd "drawAnimProp1 %localNormalized"
+vanimation anim/cmd/3 -start 1.5  -dur 0.1 -cmd "drawAnimProp2 %localNormalized"
+
+# camera animation
+vanimation anim/cam/1 -start 0   -dur 0.5 -view -up1 -0.408248   0.408248 0.816497  -up2 -0.70394    0.70394 -0.094542  -at1 0 0 -52.5 -at2 0 0 -52.5                 -eye1 718.333 -718.333 665.833 -eye2 -83.1757 83.1757 1186.12 -scale1 0.736953 -scale2 1.3
+vanimation anim/cam/2 -start 0.5 -dur 0.5 -view -up1 -0.70394    0.70394 -0.094542  -up2 -0.0582751 -0.996311 0.0629907 -at1 0 0 -52.5 -at2 0 0 -52.5                 -eye1 -83.1757 83.1757 1186.12 -eye2 -83.1757 83.1757 1186.12 -scale1 1.3 -scale2 2.5
+vanimation anim/cam/3 -start 1.0 -dur 0.5 -view -up1 -0.0582751 -0.996311 0.0629907 -up2 -0.0757833 -0.103462 0.991742  -at1 0 0 -52.5 -at2 0 0 -52.5                 -eye1 -83.1757 83.1757 1186.12 -eye2  57.3134 1235.7  80.7922 -scale1 2.5 -scale2 5.0
+vanimation anim/cam/4 -start 1.5 -dur 0.5 -view -up1 -0.0757833 -0.103462 0.991742  -up2 -0.0757833 -0.103462 0.991742  -at1 0 0 -52.5 -at2 85.6748 -3.38673 -57.9416 -eye1  57.3134 1235.7  80.7922 -eye2  142.989 1232.32 75.3506 -scale1 5.0 -scale2 2.0
+
+# propeller animation
+vanimation anim/p/1  -start 0   -dur 0.5 -objectTrsf p -rot1 0 0 0 1                -rot2 0 0 0.707107 0.707107
+vanimation anim/p/2  -start 0.5 -dur 0.5 -objectTrsf p -rot1 0 0 0.707107 0.707107  -rot2 0 0 1 6.12323e-17
+vanimation anim/p/3  -start 1.0 -dur 0.5 -objectTrsf p -rot1 0 0 1 6.12323e-17      -rot2 0 0 -0.707107 0.707107
+vanimation anim/p/4  -start 1.5 -dur 0.5 -objectTrsf p -rot1 0 0 -0.707107 0.707107 -rot2 0 0 0 1
+
+# arm animation
+vanimation anim/a/1  -start 0 -dur 0.03125 -objectTrsf a -rot1 0 0 0 1 -rot2 0 0 -0.0183813 0.999831 -loc1 0 0 0 -loc2 -0.186279 6.06481 -0
+vanimation anim/a/2  -start 0.03125 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.0183813 0.999831 -rot2 0 0 -0.036604 0.99933 -loc1 -0.186279 6.06481 -0 -loc2 -0.744076 12.0712 -0
+vanimation anim/a/3  -start 0.0625 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.036604 0.99933 -rot2 0 0 -0.0545094 0.998513 -loc1 -0.744076 12.0712 -0 -loc2 -1.67027 17.9614 -0
+vanimation anim/a/4  -start 0.09375 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.0545094 0.998513 -rot2 0 0 -0.0719395 0.997409 -loc1 -1.67027 17.9614 -0 -loc2 -2.95964 23.6785 -0
+vanimation anim/a/5  -start 0.125 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.0719395 0.997409 -rot2 0 0 -0.0887369 0.996055 -loc1 -2.95964 23.6785 -0 -loc2 -4.60486 29.1677 -0
+vanimation anim/a/6  -start 0.15625 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.0887369 0.996055 -rot2 0 0 -0.104746 0.994499 -loc1 -4.60486 29.1677 -0 -loc2 -6.59642 34.3759 -0
+vanimation anim/a/7  -start 0.1875 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.104746 0.994499 -rot2 0 0 -0.119812 0.992797 -loc1 -6.59642 34.3759 -0 -loc2 -8.92259 39.2531 -0
+vanimation anim/a/8  -start 0.21875 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.119812 0.992797 -rot2 0 0 -0.133785 0.99101 -loc1 -8.92259 39.2531 -0 -loc2 -11.5693 43.7522 -0
+vanimation anim/a/9  -start 0.25 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.133785 0.99101 -rot2 0 0 -0.146521 0.989208 -loc1 -11.5693 43.7522 -0 -loc2 -14.5202 47.83 -0
+vanimation anim/a/10 -start 0.28125 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.146521 0.989208 -rot2 0 0 -0.157881 0.987458 -loc1 -14.5202 47.83 -0 -loc2 -17.756 51.4472 -0
+vanimation anim/a/11 -start 0.3125 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.157881 0.987458 -rot2 0 0 -0.167737 0.985832 -loc1 -17.756 51.4472 -0 -loc2 -21.2549 54.5689 -0
+vanimation anim/a/12 -start 0.34375 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.167737 0.985832 -rot2 0 0 -0.175973 0.984395 -loc1 -21.2549 54.5689 -0 -loc2 -24.9922 57.165 -0
+vanimation anim/a/13 -start 0.375 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.175973 0.984395 -rot2 0 0 -0.182491 0.983208 -loc1 -24.9922 57.165 -0 -loc2 -28.9399 59.2107 -0
+vanimation anim/a/14 -start 0.40625 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.182491 0.983208 -rot2 0 0 -0.187207 0.98232 -loc1 -28.9399 59.2107 -0 -loc2 -33.0668 60.6861 -0
+vanimation anim/a/15 -start 0.4375 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.187207 0.98232 -rot2 0 0 -0.190062 0.981772 -loc1 -33.0668 60.6861 -0 -loc2 -37.3381 61.5771 -0
+vanimation anim/a/16 -start 0.46875 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.190062 0.981772 -rot2 0 0 -0.191017 0.981587 -loc1 -37.3381 61.5771 -0 -loc2 -41.7161 61.875 -0
+vanimation anim/a/17 -start 0.5 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.191017 0.981587 -rot2 0 0 -0.190062 0.981772 -loc1 -41.7161 61.875 -0 -loc2 -46.1597 61.5771 -0
+vanimation anim/a/18 -start 0.53125 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.190062 0.981772 -rot2 0 0 -0.187207 0.98232 -loc1 -46.1597 61.5771 -0 -loc2 -50.6249 60.6861 -0
+vanimation anim/a/19 -start 0.5625 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.187207 0.98232 -rot2 0 0 -0.182491 0.983208 -loc1 -50.6249 60.6861 -0 -loc2 -55.0656 59.2107 -0
+vanimation anim/a/20 -start 0.59375 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.182491 0.983208 -rot2 0 0 -0.175973 0.984395 -loc1 -55.0656 59.2107 -0 -loc2 -59.4338 57.165 -0
+vanimation anim/a/21 -start 0.625 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.175973 0.984395 -rot2 0 0 -0.167737 0.985832 -loc1 -59.4338 57.165 -0 -loc2 -63.6806 54.5689 -0
+vanimation anim/a/22 -start 0.65625 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.167737 0.985832 -rot2 0 0 -0.157881 0.987458 -loc1 -63.6806 54.5689 -0 -loc2 -67.7573 51.4472 -0
+vanimation anim/a/23 -start 0.6875 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.157881 0.987458 -rot2 0 0 -0.146521 0.989208 -loc1 -67.7573 51.4472 -0 -loc2 -71.6155 47.83 -0
+vanimation anim/a/24 -start 0.71875 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.146521 0.989208 -rot2 0 0 -0.133785 0.99101 -loc1 -71.6155 47.83 -0 -loc2 -75.2089 43.7522 -0
+vanimation anim/a/25 -start 0.75 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.133785 0.99101 -rot2 0 0 -0.119812 0.992797 -loc1 -75.2089 43.7522 -0 -loc2 -78.4935 39.2531 -0
+vanimation anim/a/26 -start 0.78125 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.119812 0.992797 -rot2 0 0 -0.104746 0.994499 -loc1 -78.4935 39.2531 -0 -loc2 -81.4287 34.3759 -0
+vanimation anim/a/27 -start 0.8125 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.104746 0.994499 -rot2 0 0 -0.0887369 0.996055 -loc1 -81.4287 34.3759 -0 -loc2 -83.9778 29.1677 -0
+vanimation anim/a/28 -start 0.84375 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.0887369 0.996055 -rot2 0 0 -0.0719395 0.997409 -loc1 -83.9778 29.1677 -0 -loc2 -86.1088 23.6785 -0
+vanimation anim/a/29 -start 0.875 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.0719395 0.997409 -rot2 0 0 -0.0545094 0.998513 -loc1 -86.1088 23.6785 -0 -loc2 -87.7949 17.9614 -0
+vanimation anim/a/30 -start 0.90625 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.0545094 0.998513 -rot2 0 0 -0.036604 0.99933 -loc1 -87.7949 17.9614 -0 -loc2 -89.0148 12.0712 -0
+vanimation anim/a/31 -start 0.9375 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.036604 0.99933 -rot2 0 0 -0.0183813 0.999831 -loc1 -89.0148 12.0712 -0 -loc2 -89.7529 6.06481 -0
+vanimation anim/a/32 -start 0.96875 -dur 0.03125 -objectTrsf a -rot1 0 0 -0.0183813 0.999831 -rot2 0 0 -2.29621e-17 1 -loc1 -89.7529 6.06481 -0 -loc2 -90 7.5775e-15 -0
+vanimation anim/a/33 -start 1 -dur 0.03125 -objectTrsf a -rot1 0 0 -2.29621e-17 1 -rot2 0 0 0.0183813 0.999831 -loc1 -90 7.5775e-15 -0 -loc2 -89.7529 -6.06481 -0
+vanimation anim/a/34 -start 1.03125 -dur 0.03125 -objectTrsf a -rot1 0 0 0.0183813 0.999831 -rot2 0 0 0.036604 0.99933 -loc1 -89.7529 -6.06481 -0 -loc2 -89.0148 -12.0712 -0
+vanimation anim/a/35 -start 1.0625 -dur 0.03125 -objectTrsf a -rot1 0 0 0.036604 0.99933 -rot2 0 0 0.0545094 0.998513 -loc1 -89.0148 -12.0712 -0 -loc2 -87.7949 -17.9614 -0
+vanimation anim/a/36 -start 1.09375 -dur 0.03125 -objectTrsf a -rot1 0 0 0.0545094 0.998513 -rot2 0 0 0.0719395 0.997409 -loc1 -87.7949 -17.9614 -0 -loc2 -86.1088 -23.6785 -0
+vanimation anim/a/37 -start 1.125 -dur 0.03125 -objectTrsf a -rot1 0 0 0.0719395 0.997409 -rot2 0 0 0.0887369 0.996055 -loc1 -86.1088 -23.6785 -0 -loc2 -83.9778 -29.1677 -0
+vanimation anim/a/38 -start 1.15625 -dur 0.03125 -objectTrsf a -rot1 0 0 0.0887369 0.996055 -rot2 0 0 0.104746 0.994499 -loc1 -83.9778 -29.1677 -0 -loc2 -81.4287 -34.3759 -0
+vanimation anim/a/39 -start 1.1875 -dur 0.03125 -objectTrsf a -rot1 0 0 0.104746 0.994499 -rot2 0 0 0.119812 0.992797 -loc1 -81.4287 -34.3759 -0 -loc2 -78.4935 -39.2531 -0
+vanimation anim/a/40 -start 1.21875 -dur 0.03125 -objectTrsf a -rot1 0 0 0.119812 0.992797 -rot2 0 0 0.133785 0.99101 -loc1 -78.4935 -39.2531 -0 -loc2 -75.2089 -43.7522 -0
+vanimation anim/a/41 -start 1.25 -dur 0.03125 -objectTrsf a -rot1 0 0 0.133785 0.99101 -rot2 0 0 0.146521 0.989208 -loc1 -75.2089 -43.7522 -0 -loc2 -71.6155 -47.83 -0
+vanimation anim/a/42 -start 1.28125 -dur 0.03125 -objectTrsf a -rot1 0 0 0.146521 0.989208 -rot2 0 0 0.157881 0.987458 -loc1 -71.6155 -47.83 -0 -loc2 -67.7573 -51.4472 -0
+vanimation anim/a/43 -start 1.3125 -dur 0.03125 -objectTrsf a -rot1 0 0 0.157881 0.987458 -rot2 0 0 0.167737 0.985832 -loc1 -67.7573 -51.4472 -0 -loc2 -63.6806 -54.5689 -0
+vanimation anim/a/44 -start 1.34375 -dur 0.03125 -objectTrsf a -rot1 0 0 0.167737 0.985832 -rot2 0 0 0.175973 0.984395 -loc1 -63.6806 -54.5689 -0 -loc2 -59.4338 -57.165 -0
+vanimation anim/a/45 -start 1.375 -dur 0.03125 -objectTrsf a -rot1 0 0 0.175973 0.984395 -rot2 0 0 0.182491 0.983208 -loc1 -59.4338 -57.165 -0 -loc2 -55.0656 -59.2107 -0
+vanimation anim/a/46 -start 1.40625 -dur 0.03125 -objectTrsf a -rot1 0 0 0.182491 0.983208 -rot2 0 0 0.187207 0.98232 -loc1 -55.0656 -59.2107 -0 -loc2 -50.6249 -60.6861 -0
+vanimation anim/a/47 -start 1.4375 -dur 0.03125 -objectTrsf a -rot1 0 0 0.187207 0.98232 -rot2 0 0 0.190062 0.981772 -loc1 -50.6249 -60.6861 -0 -loc2 -46.1597 -61.5771 -0
+vanimation anim/a/48 -start 1.46875 -dur 0.03125 -objectTrsf a -rot1 0 0 0.190062 0.981772 -rot2 0 0 0.191017 0.981587 -loc1 -46.1597 -61.5771 -0 -loc2 -41.7161 -61.875 -0
+vanimation anim/a/49 -start 1.5 -dur 0.03125 -objectTrsf a -rot1 0 0 0.191017 0.981587 -rot2 0 0 0.190062 0.981772 -loc1 -41.7161 -61.875 -0 -loc2 -37.3381 -61.5771 -0
+vanimation anim/a/50 -start 1.53125 -dur 0.03125 -objectTrsf a -rot1 0 0 0.190062 0.981772 -rot2 0 0 0.187207 0.98232 -loc1 -37.3381 -61.5771 -0 -loc2 -33.0668 -60.6861 -0
+vanimation anim/a/51 -start 1.5625 -dur 0.03125 -objectTrsf a -rot1 0 0 0.187207 0.98232 -rot2 0 0 0.182491 0.983208 -loc1 -33.0668 -60.6861 -0 -loc2 -28.9399 -59.2107 -0
+vanimation anim/a/52 -start 1.59375 -dur 0.03125 -objectTrsf a -rot1 0 0 0.182491 0.983208 -rot2 0 0 0.175973 0.984395 -loc1 -28.9399 -59.2107 -0 -loc2 -24.9922 -57.165 -0
+vanimation anim/a/53 -start 1.625 -dur 0.03125 -objectTrsf a -rot1 0 0 0.175973 0.984395 -rot2 0 0 0.167737 0.985832 -loc1 -24.9922 -57.165 -0 -loc2 -21.2549 -54.5689 -0
+vanimation anim/a/54 -start 1.65625 -dur 0.03125 -objectTrsf a -rot1 0 0 0.167737 0.985832 -rot2 0 0 0.157881 0.987458 -loc1 -21.2549 -54.5689 -0 -loc2 -17.756 -51.4472 -0
+vanimation anim/a/55 -start 1.6875 -dur 0.03125 -objectTrsf a -rot1 0 0 0.157881 0.987458 -rot2 0 0 0.146521 0.989208 -loc1 -17.756 -51.4472 -0 -loc2 -14.5202 -47.83 -0
+vanimation anim/a/56 -start 1.71875 -dur 0.03125 -objectTrsf a -rot1 0 0 0.146521 0.989208 -rot2 0 0 0.133785 0.99101 -loc1 -14.5202 -47.83 -0 -loc2 -11.5693 -43.7522 -0
+vanimation anim/a/57 -start 1.75 -dur 0.03125 -objectTrsf a -rot1 0 0 0.133785 0.99101 -rot2 0 0 0.119812 0.992797 -loc1 -11.5693 -43.7522 -0 -loc2 -8.92259 -39.2531 -0
+vanimation anim/a/58 -start 1.78125 -dur 0.03125 -objectTrsf a -rot1 0 0 0.119812 0.992797 -rot2 0 0 0.104746 0.994499 -loc1 -8.92259 -39.2531 -0 -loc2 -6.59642 -34.3759 -0
+vanimation anim/a/59 -start 1.8125 -dur 0.03125 -objectTrsf a -rot1 0 0 0.104746 0.994499 -rot2 0 0 0.0887369 0.996055 -loc1 -6.59642 -34.3759 -0 -loc2 -4.60486 -29.1677 -0
+vanimation anim/a/60 -start 1.84375 -dur 0.03125 -objectTrsf a -rot1 0 0 0.0887369 0.996055 -rot2 0 0 0.0719395 0.997409 -loc1 -4.60486 -29.1677 -0 -loc2 -2.95964 -23.6785 -0
+vanimation anim/a/61 -start 1.875 -dur 0.03125 -objectTrsf a -rot1 0 0 0.0719395 0.997409 -rot2 0 0 0.0545094 0.998513 -loc1 -2.95964 -23.6785 -0 -loc2 -1.67027 -17.9614 -0
+vanimation anim/a/62 -start 1.90625 -dur 0.03125 -objectTrsf a -rot1 0 0 0.0545094 0.998513 -rot2 0 0 0.036604 0.99933 -loc1 -1.67027 -17.9614 -0 -loc2 -0.744076 -12.0712 -0
+vanimation anim/a/63 -start 1.9375 -dur 0.03125 -objectTrsf a -rot1 0 0 0.036604 0.99933 -rot2 0 0 0.0183813 0.999831 -loc1 -0.744076 -12.0712 -0 -loc2 -0.186279 -6.06481 -0
+vanimation anim/a/64 -start 1.96875 -dur 0.03125 -objectTrsf a -rot1 0 0 0.0183813 0.999831 -rot2 0 0 4.59243e-17 1 -loc1 -0.186279 -6.06481 -0 -loc2 3.79627e-31 -1.5155e-14 -0
+
+# take screenshots in non-interactive mode
+for {set i 0} {$i <= 10} {incr i} { vanimation anim -play [expr 2.0 * $i / 10] 0; set anIndex [format "%02d" $i]; vdump $imagedir/${casename}_$anIndex.png }
+
+puts "Put the following command to start interactive animation:"
+puts "    vanimation anim -play -playSpeed 0.2"
diff --git a/tests/v3d/anim/rotate b/tests/v3d/anim/rotate
new file mode 100644 (file)
index 0000000..ab16eb6
--- /dev/null
@@ -0,0 +1,34 @@
+puts "=================================="
+puts "Viewer animation - rotate the view camera"
+puts "=================================="
+
+pload MODELING VISUALIZATION
+
+vclear
+vinit View1
+vaxo
+vzbufftrihedron
+
+box b1 -50 -50 0 100 100 100
+vdisplay -noupdate -dispMode 1 b1
+vfit -noupdate
+
+# Animation simulates the following rotation:
+# vrotate 2 0 0
+vanimation anim -clear
+vanimation anim/movecam -view -at1 0 0 50 -at2 0 0 50 -eye1 100 -100 150 -eye2 -153 -70 8 -duration 3
+
+vanimation anim -play 0.0 0.0
+if {[vreadpixel 306 280 rgb name] != "DARKGOLDENROD3" || [vreadpixel 325 280 rgb name] != "DARKGOLDENROD3"} { puts "Error: Camera rotate result is wrong!" }
+vdump $imagedir/${casename}_0.png
+
+vanimation anim -play 1.0 0.0
+if {[vreadpixel 306 280 rgb name] != "DARKORANGE4"    || [vreadpixel 325 280 rgb name] != "BLACK"}          { puts "Error: Camera rotate result is wrong!" }
+vdump $imagedir/${casename}_1.png
+
+vanimation anim -play 2.0 0.0
+if {[vreadpixel 306 280 rgb name] != "GOLDENROD2"     || [vreadpixel 325 280 rgb name] != "GOLDENROD2"}     { puts "Error: Camera rotate result is wrong!" }
+vdump $imagedir/${casename}_2.png
+
+puts "Put the following command to start interactive animation:"
+puts "    vanimation anim -play"
diff --git a/tests/v3d/anim/scale b/tests/v3d/anim/scale
new file mode 100644 (file)
index 0000000..5037f82
--- /dev/null
@@ -0,0 +1,33 @@
+puts "=================================="
+puts "Viewer animation - scale the view camera"
+puts "=================================="
+
+pload MODELING VISUALIZATION
+
+vclear
+vinit View1
+vaxo
+vzbufftrihedron
+
+box b1 -50 -50 0 100 100 100
+vdisplay -noupdate -dispMode 1 b1
+vfit -noupdate
+vzoom 0.2
+
+vanimation anim -clear
+vanimation anim/zoom -view -scale1 1.2 -scale2 4.8 -duration 2
+
+vanimation anim -play 0.0 0.0
+if {[vreadpixel 230 220 rgb name] != "DARKGOLDENROD3" || [vreadpixel 250 220 rgb name] != "BLACK"} { puts "Error: Camera scale result is wrong!" }
+vdump $imagedir/${casename}_0.png
+
+vanimation anim -play 1.0 0.0
+if {[vreadpixel 250 220 rgb name] != "DARKGOLDENROD3" || [vreadpixel 270 220 rgb name] != "BLACK"} { puts "Error: Camera scale result is wrong!" }
+vdump $imagedir/${casename}_1.png
+
+vanimation anim -play 2.0 0.0
+if {[vreadpixel 334 220 rgb name] != "DARKGOLDENROD3" || [vreadpixel 350 220 rgb name] != "BLACK"} { puts "Error: Camera scale result is wrong!" }
+vdump $imagedir/${casename}_2.png
+
+puts "Put the following command to start interactive animation:"
+puts "    vanimation anim -play"
diff --git a/tests/v3d/anim/translate b/tests/v3d/anim/translate
new file mode 100644 (file)
index 0000000..34caf67
--- /dev/null
@@ -0,0 +1,35 @@
+puts "=================================="
+puts "Viewer animation - translate the view camera"
+puts "=================================="
+
+pload MODELING VISUALIZATION
+
+vclear
+vinit View1
+vaxo
+vzbufftrihedron -position right_lower
+
+box b1 -50 -50 0 100 100 100
+vdisplay -noupdate -dispMode 1 b1
+vviewparams -scale 1.156 -up -0.3588 0.3458 0.867 -at 116 355 327 -eye 225 253 413
+
+# Animation simulates the following panning:
+# vpan 200 0
+# vviewparams -scale 1.156 -up -0.3588 0.3458 0.867 -at -174 47 330 -eye -65 -55 415
+vanimation anim -clear
+vanimation anim/movecam -view -at1 116 355 327 -at2 -174 47 330 -eye1 225 253 413 -eye2 -65 -55 415 -duration 2
+
+vanimation anim -play 0.0 0.0
+if {[vreadpixel 60  360 rgb name] != "GOLDENROD3"} { puts "Error: Camera translation result is wrong!" }
+vdump $imagedir/${casename}_0.png
+
+vanimation anim -play 1.0 0.0
+if {[vreadpixel 160 360 rgb name] != "GOLDENROD3"} { puts "Error: Camera translation result is wrong!" }
+vdump $imagedir/${casename}_1.png
+
+vanimation anim -play 2.0 0.0
+if {[vreadpixel 260 360 rgb name] != "GOLDENROD3"} { puts "Error: Camera translation result is wrong!" }
+vdump $imagedir/${casename}_2.png
+
+puts "Put the following command to start interactive animation:"
+puts "    vanimation anim -play"
index 3fbd323..ec78119 100755 (executable)
@@ -1,4 +1,6 @@
-catch { vfit }
+if { [info exists subgroup] && $subgroup != "motion" && $subgroup != "ivtk" } {
+  catch { vfit }
+}
 if { [info exists subgroup] && $subgroup == "raytrace" } {
 
   # dump final image for raytraced visualization tests
index bb50862..778d7df 100644 (file)
@@ -16,3 +16,4 @@
 017 mesh
 018 point_cloud
 019 manipulator
+020 anim
index fed4e92..74f54fb 100755 (executable)
@@ -66,5 +66,5 @@ vsetdispmode 1
 vfit
 
 vrenderparams -rayTrace -reflections
-vlocrotate res 0 0 0 0 0 1 180
+vlocation res -rotate 0 0 0 0 0 1 180
 vfit