When using AIS_AnimationObject, linear interpolation is performed from one gp_Trsf transformation to another.
But when an object rotates around a specific axis, the object moves not along a linear trajectory,
but along a circle. Therefore, a separate class AIS_AnimationAxisRotation was created that
allows to animate rotation around a specific axis.
Test case tests/v3d/bugs/bug32570 was added.
--- /dev/null
+// Copyright (c) 2023 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_AnimationAxisRotation.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(AIS_AnimationAxisRotation, AIS_BaseAnimationObject)
+
+//=============================================================================
+//function : Constructor
+//purpose :
+//=============================================================================
+AIS_AnimationAxisRotation::AIS_AnimationAxisRotation (const TCollection_AsciiString& theAnimationName,
+ const Handle(AIS_InteractiveContext)& theContext,
+ const Handle(AIS_InteractiveObject)& theObject,
+ const gp_Ax1& theAxis,
+ const Standard_Real theAngleStart,
+ const Standard_Real theAngleEnd)
+: AIS_BaseAnimationObject (theAnimationName, theContext, theObject),
+ myRotAxis (theAxis),
+ myAngleStart (theAngleStart),
+ myAngleEnd (theAngleEnd)
+{
+ //
+}
+
+//=============================================================================
+//function : update
+//purpose :
+//=============================================================================
+void AIS_AnimationAxisRotation::update (const AIS_AnimationProgress& theProgress)
+{
+ if (myObject.IsNull())
+ {
+ return;
+ }
+
+ gp_Trsf aTrsf;
+ Standard_Real aCurrentAngle = (1.0 - theProgress.LocalNormalized) * myAngleStart + theProgress.LocalNormalized * myAngleEnd;
+ aTrsf.SetRotation (myRotAxis, aCurrentAngle);
+ updateTrsf (aTrsf);
+}
--- /dev/null
+// Copyright (c) 2023 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_AnimationAxisRotation_HeaderFile
+#define _AIS_AnimationAxisRotation_HeaderFile
+
+#include <AIS_BaseAnimationObject.hxx>
+#include <gp_TrsfNLerp.hxx>
+
+//! Animation defining object transformation.
+class AIS_AnimationAxisRotation : public AIS_BaseAnimationObject
+{
+ DEFINE_STANDARD_RTTIEXT(AIS_AnimationAxisRotation, AIS_BaseAnimationObject)
+public:
+
+ //! Constructor with initialization.
+ //! @param[in] theAnimationName animation identifier
+ //! @param[in] theContext interactive context where object have been displayed
+ //! @param[in] theObject object to apply rotation
+ //! @param[in] theAxis rotation axis
+ //! @param[in] theAngleStart rotation angle at the start of animation
+ //! @param[in] theAngleEnd rotation angle at the end of animation
+ Standard_EXPORT AIS_AnimationAxisRotation (const TCollection_AsciiString& theAnimationName,
+ const Handle(AIS_InteractiveContext)& theContext,
+ const Handle(AIS_InteractiveObject)& theObject,
+ const gp_Ax1& theAxis,
+ const Standard_Real theAngleStart,
+ const Standard_Real theAngleEnd);
+
+protected:
+
+ //! Update the progress.
+ Standard_EXPORT virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE;
+
+private:
+
+ gp_Ax1 myRotAxis; //!< rotation axis
+ Standard_Real myAngleStart; //!< start angle for rotation
+ Standard_Real myAngleEnd; //!< end angle for rotation
+
+};
+
+#endif // _AIS_AnimationAxisRotation_HeaderFile
#include <AIS_AnimationObject.hxx>
-#include <AIS_InteractiveContext.hxx>
-#include <V3d_View.hxx>
-
-IMPLEMENT_STANDARD_RTTIEXT(AIS_AnimationObject, AIS_Animation)
+IMPLEMENT_STANDARD_RTTIEXT(AIS_AnimationObject, AIS_BaseAnimationObject)
//=============================================================================
//function : Constructor
const Handle(AIS_InteractiveObject)& theObject,
const gp_Trsf& theTrsfStart,
const gp_Trsf& theTrsfEnd)
-: AIS_Animation (theAnimationName),
- myContext (theContext),
- myObject (theObject),
+: AIS_BaseAnimationObject (theAnimationName, theContext, theObject),
myTrsfLerp (theTrsfStart, theTrsfEnd)
{
//
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();
- }
- }
- }
+ updateTrsf (aTrsf);
}
#ifndef _AIS_AnimationObject_HeaderFile
#define _AIS_AnimationObject_HeaderFile
-#include <AIS_Animation.hxx>
-#include <AIS_InteractiveContext.hxx>
+#include <AIS_BaseAnimationObject.hxx>
#include <gp_TrsfNLerp.hxx>
//! Animation defining object transformation.
-class AIS_AnimationObject : public AIS_Animation
+class AIS_AnimationObject : public AIS_BaseAnimationObject
{
- DEFINE_STANDARD_RTTIEXT(AIS_AnimationObject, AIS_Animation)
+ DEFINE_STANDARD_RTTIEXT(AIS_AnimationObject, AIS_BaseAnimationObject)
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
+ //! @param[in] theAnimationName animation identifier
+ //! @param[in] theContext interactive context where object have been displayed
+ //! @param[in] theObject object to apply local transformation
+ //! @param[in] theTrsfStart local transformation at the start of animation (e.g. theObject->LocalTransformation())
+ //! @param[in] 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,
//! Update the progress.
Standard_EXPORT virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE;
- //! Invalidate the viewer for proper update.
- Standard_EXPORT void invalidateViewer();
+private:
-protected:
-
- Handle(AIS_InteractiveContext) myContext; //!< context where object is displayed
- Handle(AIS_InteractiveObject) myObject; //!< presentation object to set location
- gp_TrsfNLerp myTrsfLerp; //!< interpolation tool
+ gp_TrsfNLerp myTrsfLerp; //!< interpolation tool
};
-DEFINE_STANDARD_HANDLE(AIS_AnimationObject, AIS_Animation)
-
#endif // _AIS_AnimationObject_HeaderFile
--- /dev/null
+// Copyright (c) 2023 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_BaseAnimationObject.hxx>
+
+#include <V3d_View.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(AIS_BaseAnimationObject, AIS_Animation)
+
+//=============================================================================
+//function : Constructor
+//purpose :
+//=============================================================================
+AIS_BaseAnimationObject::AIS_BaseAnimationObject (const TCollection_AsciiString& theAnimationName,
+ const Handle(AIS_InteractiveContext)& theContext,
+ const Handle(AIS_InteractiveObject)& theObject)
+: AIS_Animation (theAnimationName),
+ myContext (theContext),
+ myObject (theObject)
+{
+ //
+}
+
+//=============================================================================
+//function : updateTrsf
+//purpose :
+//=============================================================================
+void AIS_BaseAnimationObject::updateTrsf (const gp_Trsf& theTrsf)
+{
+ if (!myContext.IsNull())
+ {
+ myContext->SetLocation (myObject, theTrsf);
+ invalidateViewer();
+ }
+ else
+ {
+ myObject->SetLocalTransformation (theTrsf);
+ }
+}
+
+//=============================================================================
+//function : invalidateViewer
+//purpose :
+//=============================================================================
+void AIS_BaseAnimationObject::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();
+ }
+ }
+ }
+}
--- /dev/null
+// Copyright (c) 2023 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_BaseAnimationObject_HeaderFile
+#define _AIS_BaseAnimationObject_HeaderFile
+
+#include <AIS_Animation.hxx>
+#include <AIS_InteractiveContext.hxx>
+
+//! Animation defining object transformation.
+class AIS_BaseAnimationObject : public AIS_Animation
+{
+ DEFINE_STANDARD_RTTIEXT(AIS_BaseAnimationObject, AIS_Animation)
+protected:
+
+ //! Constructor with initialization.
+ //! @param[in] theAnimationName animation identifier
+ //! @param[in] theContext interactive context where object have been displayed
+ //! @param[in] theObject object to apply local transformation
+ Standard_EXPORT AIS_BaseAnimationObject (const TCollection_AsciiString& theAnimationName,
+ const Handle(AIS_InteractiveContext)& theContext,
+ const Handle(AIS_InteractiveObject)& theObject);
+
+ //! Update the transformation.
+ Standard_EXPORT void updateTrsf (const gp_Trsf& theTrsf);
+
+private:
+
+ //! 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
+
+};
+
+#endif // _AIS_BaseAnimationObject_HeaderFile
AIS_Animation.cxx
AIS_Animation.hxx
AIS_AnimationTimer.hxx
+AIS_AnimationAxisRotation.cxx
+AIS_AnimationAxisRotation.hxx
AIS_AnimationCamera.cxx
AIS_AnimationCamera.hxx
AIS_AnimationObject.cxx
AIS_Axis.hxx
AIS_BadEdgeFilter.cxx
AIS_BadEdgeFilter.hxx
+AIS_BaseAnimationObject.cxx
+AIS_BaseAnimationObject.hxx
AIS_C0RegularityFilter.cxx
AIS_C0RegularityFilter.hxx
AIS_CameraFrustum.cxx
#include <ViewerTest.hxx>
+#include <AIS_AnimationAxisRotation.hxx>
#include <AIS_AnimationCamera.hxx>
#include <AIS_AnimationObject.hxx>
#include <AIS_Axis.hxx>
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;
+
+ gp_Ax1 anAxis;
+ Standard_Real anAngles[2] = { 0.0, 0.0 };
+ Standard_Boolean isAxisRotationSet = Standard_False;
+
Standard_Integer aTrsfArgIter = anArgIter + 1;
for (; aTrsfArgIter < theArgNb; ++aTrsfArgIter)
{
}
aScales[anIndex] = aScaleStr.RealValue();
}
+ else if (aTrsfArg == "-axis")
+ {
+ isAxisRotationSet = Standard_True;
+ gp_XYZ anOrigin, aDirection;
+ if (aTrsfArgIter + 6 >= theArgNb
+ || !parseXYZ (theArgVec + aTrsfArgIter + 1, anOrigin)
+ || !parseXYZ (theArgVec + aTrsfArgIter + 4, aDirection))
+ {
+ Message::SendFail() << "Syntax error at " << aTrsfArg;
+ return 1;
+ }
+ anAxis.SetLocation (anOrigin);
+ anAxis.SetDirection (aDirection);
+ aTrsfArgIter += 6;
+ }
+ else if (aTrsfArg.StartsWith ("-ang"))
+ {
+ isAxisRotationSet = Standard_True;
+ if (++aTrsfArgIter >= theArgNb)
+ {
+ Message::SendFail() << "Syntax error at " << aTrsfArg;
+ return 1;
+ }
+
+ const TCollection_AsciiString anAngleStr (theArgVec[aTrsfArgIter]);
+ if (!anAngleStr.IsRealValue (Standard_True))
+ {
+ Message::SendFail() << "Syntax error at " << aTrsfArg;
+ return 1;
+ }
+ anAngles[anIndex] = anAngleStr.RealValue();
+ }
else
{
anArgIter = aTrsfArgIter - 1;
break;
}
}
- if (!isTrsfSet)
+ if (!isTrsfSet && !isAxisRotationSet)
{
Message::SendFail() << "Syntax error at " << anArg;
return 1;
{
anArgIter = theArgNb;
}
+ Handle(AIS_BaseAnimationObject) anObjAnimation;
+ if (isTrsfSet)
+ {
+ 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]);
- 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]);
+ anObjAnimation = new AIS_AnimationObject (anAnimation->Name(), aCtx, anObject, aTrsfs[0], aTrsfs[1]);
+ }
+ else
+ {
+ anObjAnimation = new AIS_AnimationAxisRotation (anAnimation->Name(), aCtx, anObject, anAxis,
+ anAngles[0] * (M_PI / 180.0), anAngles[1] * (M_PI / 180.0));
+ }
replaceAnimation (aParentAnimation, anAnimation, anObjAnimation);
}
else if (anArg == "-viewtrsf"
-rotX object Orientations pair (quaternions)
-scaleX object Scale factors pair (quaternions)
+ vanim name -object [-axis OX OY OZ DX DY DZ] [-ang1 A] [-ang2 A]
+ -axis rotation axis
+ -ang1 start rotation angle in degrees
+ -ang2 end rotation angle in degrees
+
Custom callback:
vanim name -invoke "Command Arg1 Arg2 %Pts %LocalPts %Normalized ArgN"
--- /dev/null
+puts "============"
+puts "0032570: Visualization, AIS_AnimationObject - define rotation around axis"
+puts "============"
+puts ""
+
+pload MODELING VISUALIZATION
+box b1 2 100 100 -preview
+box b2 2 100 100 -preview
+
+vinit View1
+vdisplay b1 -dispMode 0
+vdisplay b2 -dispMode 1
+
+vanimation anim -object b2 -axis 2 100 0 0 0 1 -angle1 0 -angle2 90 -duration 2
+#stop at the middle of the animation (45 degrees)
+vanimation anim -play 1 0
+vanimation anim -stop
+vfit
+vdump ${imagedir}/${casename}.png
+set loc1 [vlocation b2]
+
+vlocation b2 -reset -rotate 2 100 0 0 0 1 45
+set loc2 [vlocation b2]
+
+if {$loc1 != $loc2} { puts "Error: the location at the middle of animation is different from the location after rotating by 45 degrees" }
+
+puts "Put the following command to start interactive animation:"
+puts " vanimation anim -play"