Use AIS_Animation to create a rotation animation with angle greater than 180 degree

Hi everyone, I don’t know if you have any experience in creating animations using AIS_Animation.

When I used AIS_Animation to create a rotation animation, I specified a starting rotation angle of 0 degrees and a stop rotation angle of 360 degrees to AIS_Shape. The animation time set was 10s. As a result, the AIS_Shape did not rotate in 10s; if I set the starting rotation angle If it is greater than 180 degrees, AIS_Shape can rotate according to the expected rotation process.

I wonder if you can find a solution in occt?

Thank you all.

Matthias K.'s picture

Hi w d,

try to replace your animation by four animations each rotating your model 90° in 2,5 sec and define the starting-time for each by using SetStartPts of AIS_AnimationObject

For the four rotations I use the following quaternion definitions:

gp_Quaternion r1(0.0, 0.0, 0.0, 1.0);
gp_Quaternion r2(0.0, 0.0, 0.707107, 0.707107);
gp_Quaternion r3(0.0, 0.0, 1.0, 6.12323e-17);
gp_Quaternion r4(0.0, 0.0, -0.707107, 0.707107);
jason jiang's picture

hI,I want to achieve a animation of circle movement or arc movement,could you give me a C++ sample code?
Thanks
Jason

w d's picture
//=============================================================================
//function : update
//purpose  :
//=============================================================================
void AIS_AnimationObject_CAD::update(const AIS_AnimationProgress &theProgress) {
    if (myObject.IsNull()) {
        return;
    }
    gp_Trsf aTrsf;

    gp_Trsf trsfMove;
    if (myTranslatePath.IsNull()) {
        gp_XYZ movexyz;
        NCollection_Lerp<gp_XYZ> myLocLerp(gp_XYZ(myStatusStart.translateKeyFrame.mFloatMoveX,
                                                  myStatusStart.translateKeyFrame.mFloatMoveY,
                                                  myStatusStart.translateKeyFrame.mFloatMoveZ),
                                           gp_XYZ(myStatusEnd.translateKeyFrame.mFloatMoveX,
                                                  myStatusEnd.translateKeyFrame.mFloatMoveY,
                                                  myStatusEnd.translateKeyFrame.mFloatMoveZ));
        myLocLerp.Interpolate(theProgress.LocalNormalized, movexyz);
        trsfMove.SetTranslationPart(movexyz);
    } else {
        Standard_Real translate;
        NCollection_Lerp<Standard_Real> myTranslateLerp(0,myTranslatePathLength);
        myTranslateLerp.Interpolate(theProgress.LocalNormalized, translate);
        GeomAdaptor_Curve GAC;
        GAC.Load(myTranslatePath);
        GCPnts_AbscissaPoint abscissaPoint(GAC,translate,GAC.FirstParameter());
        trsfMove.SetTranslation(myCenterPnt, myTranslatePath->Value(abscissaPoint.Parameter()));
    }

    Standard_Real scale;
    NCollection_Lerp<Standard_Real> myScaleLerp(myStatusStart.scaleKeyFrame.mFloatScaleX,
                                                myStatusEnd.scaleKeyFrame.mFloatScaleX);
    myScaleLerp.Interpolate(theProgress.LocalNormalized, scale);
    gp_Trsf trsfScale;
    trsfScale.SetScaleFactor(scale);

    gp_Trsf trsfRotate;
    if (myStatusEnd.rotateKeyFrame.mAnimationRotateType == ANIMATION_ROTATE_TYPE_Direction) {
        gp_Trsf starttrsf_rotate;
        gp_Trsf starttrsf_rotateX;
        gp_Trsf starttrsf_rotateY;
        gp_Trsf starttrsf_rotateZ;
        starttrsf_rotateX.SetRotation(gp_Ax1(gpPntCenter, gp_Dir(gpVecx)),
                                      myStatusStart.rotateKeyFrame.mFloatRotateX * DEGREETORADIUS);
        starttrsf_rotateY.SetRotation(gp_Ax1(gpPntCenter, gp_Dir(gpVecy)),
                                      myStatusStart.rotateKeyFrame.mFloatRotateY * DEGREETORADIUS);
        starttrsf_rotateZ.SetRotation(gp_Ax1(gpPntCenter, gp_Dir(gpVecz)),
                                      myStatusStart.rotateKeyFrame.mFloatRotateZ * DEGREETORADIUS);
        starttrsf_rotate = starttrsf_rotateX.Multiplied(starttrsf_rotateY).Multiplied(
                starttrsf_rotateZ);

        gp_Trsf endtrsf_rotate;
        gp_Trsf endtrsf_rotateX;
        gp_Trsf endtrsf_rotateY;
        gp_Trsf endtrsf_rotateZ;
        endtrsf_rotateX.SetRotation(gp_Ax1(gpPntCenter, gp_Dir(gpVecx)),
                                    myStatusEnd.rotateKeyFrame.mFloatRotateX * DEGREETORADIUS);
        endtrsf_rotateY.SetRotation(gp_Ax1(gpPntCenter, gp_Dir(gpVecy)),
                                    myStatusEnd.rotateKeyFrame.mFloatRotateY * DEGREETORADIUS);
        endtrsf_rotateZ.SetRotation(gp_Ax1(gpPntCenter, gp_Dir(gpVecz)),
                                    myStatusEnd.rotateKeyFrame.mFloatRotateZ * DEGREETORADIUS);
        endtrsf_rotate = endtrsf_rotateX.Multiplied(endtrsf_rotateY).Multiplied(endtrsf_rotateZ);

        gp_QuaternionNLerp rotateLerp(starttrsf_rotate.GetRotation(), endtrsf_rotate.GetRotation());

        Standard_Real anInner = starttrsf_rotate.GetRotation().Dot(endtrsf_rotate.GetRotation());
        gp_Quaternion quaternion;
        rotateLerp.Interpolate(theProgress.LocalNormalized, quaternion);

        gp_Quaternion theResultQ = starttrsf_rotate.GetRotation() +
                                   (endtrsf_rotate.GetRotation() - starttrsf_rotate.GetRotation())
                                   * theProgress.LocalNormalized;

        Standard_Real vl = Sqrt(quaternion.X() * quaternion.X() + quaternion.Y() * quaternion.Y() +
                                quaternion.Z() * quaternion.Z());
        gp_Vec theAxis;
        Standard_Real theAngle;
        quaternion.GetVectorAndAngle(theAxis, theAngle);
        gp_EulerSequence theOrder = gp_EulerSequence::gp_Extrinsic_XYZ;
        Standard_Real theAlpha;
        Standard_Real theBeta;
        Standard_Real theGamma;
        quaternion.GetEulerAngles(theOrder, theAlpha, theBeta, theGamma);
        trsfRotate.SetRotation(gp_Ax1(myCenterPnt, theAxis), theAngle);

        Standard_Real rotateanglex = myStatusStart.rotateKeyFrame.mFloatRotateX +
                                     (myStatusEnd.rotateKeyFrame.mFloatRotateX -
                                      myStatusStart.rotateKeyFrame.mFloatRotateX) *
                                     theProgress.LocalNormalized;
        Standard_Real rotateangley = myStatusStart.rotateKeyFrame.mFloatRotateY +
                                     (myStatusEnd.rotateKeyFrame.mFloatRotateY -
                                      myStatusStart.rotateKeyFrame.mFloatRotateY) *
                                     theProgress.LocalNormalized;
        Standard_Real rotateanglez = myStatusStart.rotateKeyFrame.mFloatRotateZ +
                                     (myStatusEnd.rotateKeyFrame.mFloatRotateZ -
                                      myStatusStart.rotateKeyFrame.mFloatRotateZ) *
                                     theProgress.LocalNormalized;
        gp_Trsf trsfrotatex;
        trsfrotatex.SetRotation(gp_Ax1(myCenterPnt, gpVecx), rotateanglex * DEGREETORADIUS);
        gp_Trsf trsfrotatey;
        trsfrotatey.SetRotation(gp_Ax1(myCenterPnt, gpVecy), rotateangley * DEGREETORADIUS);
        gp_Trsf trsfrotatez;
        trsfrotatez.SetRotation(gp_Ax1(myCenterPnt, gpVecz), rotateanglez * DEGREETORADIUS);
        trsfrotatex.Multiply(trsfrotatey);
        trsfrotatex.Multiply(trsfrotatez);
        trsfRotate = trsfrotatex;
    } else if (myStatusEnd.rotateKeyFrame.mAnimationRotateType == ANIMATION_ROTATE_TYPE_Target) {
        gp_Pnt center = myCenterPnt.Transformed(trsfMove);
        gp_Dir dir(gp_Vec(center, myTargetPnt));
        gp_Quaternion quaternion;
        quaternion.SetRotation(gp::DX(), dir);
        gp_Vec theAxis;
        Standard_Real theAngle;
        quaternion.GetVectorAndAngle(theAxis, theAngle);
        trsfRotate.SetRotation(gp_Ax1(myCenterPnt, theAxis), theAngle);
    } else {
        gp_Trsf starttrsf_rotate;
        starttrsf_rotate.SetRotation(gp_Ax1(maxisLin.Location(), maxisLin.Direction()),
                                     myStatusStart.rotateKeyFrame.mFloatRotateAxis *
                                     DEGREETORADIUS);
        gp_Trsf endtrsf_rotate;
        endtrsf_rotate.SetRotation(gp_Ax1(maxisLin.Location(), maxisLin.Direction()),
                                   myStatusEnd.rotateKeyFrame.mFloatRotateAxis * DEGREETORADIUS);

        gp_QuaternionNLerp rotateLerp(starttrsf_rotate.GetRotation(), endtrsf_rotate.GetRotation());

        gp_Quaternion quaternion;
        rotateLerp.Interpolate(theProgress.LocalNormalized, quaternion);
        gp_Vec theAxis;
        Standard_Real theAngle;
        quaternion.GetVectorAndAngle(theAxis, theAngle);
        trsfRotate.SetRotation(gp_Ax1(maxisLin.Location(), maxisLin.Direction()), theAngle);

        Standard_Real rotateangle = myStatusStart.rotateKeyFrame.mFloatRotateAxis +
                                    (myStatusEnd.rotateKeyFrame.mFloatRotateAxis -
                                     myStatusStart.rotateKeyFrame.mFloatRotateAxis) *
                                    theProgress.LocalNormalized;
        trsfRotate.SetRotation(gp_Ax1(maxisLin.Location(), maxisLin.Direction()),
                               rotateangle * DEGREETORADIUS);
    }

    aTrsf.PreMultiply(trsfScale);
    aTrsf.PreMultiply(trsfRotate);
    aTrsf.PreMultiply(trsfMove);

    if (!myContext.IsNull()) {
        myContext->SetLocation(myObject, aTrsf);
        invalidateViewer();
    } else {
        myObject->SetLocalTransformation(aTrsf);
    }
}

The first thing to do is to clarify the implementation logic of AIS's animation function.

The principle of rotating around a certain center point is to move and rotate at the same time.

Therefore, it is necessary to calculate the translation transformation and the rotation transformation.

AIS_AnimationObject_CAD is a subclass of  AIS_AnimationObject_CAD.

myTranslatePath is a move path.

ANIMATION_ROTATE_TYPE_Direction: the object rotate around a axis

ANIMATION_ROTATE_TYPE_Target: the object rotate torward a target