The angle between two vectors can be calculated by the dot product. We want to find the direction of the rotation.
Here are two different ways to get it done.

1、Compute the value of Sine of the angle, then we can judge it’s clockwise or counterclockwise. The value of Sine of the angle can be calculated by the signed area of the parallelogram formed by the two vectors. Relative post:
CGAL: Area of Parallelogram And Volume Of Triple Vectors

2、Compare the cross vector of the two vectors with a reference axis.



#include <vtkActor.h>
#include <vtkPolyData.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartPointer.h>
#include <vtkTextActor.h>
#include <vtkSphereSource.h>
#include <vtkPlaneSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkPlane.h>
#include <vtkTextProperty.h>
#include <iostream>
#include <QtDebug>
#include <vector>
#include <vtkSTLWriter.h>
#include <vtkSTLReader.h>
#include <QChar>
#include <vtkAxesActor.h>
#include <vtkTransform.h>
#include <vtkTransformFilter.h>

#include "Point.hpp"

#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();


vtkSPtr<vtkTransform> CreatePoseTransfrom(Point fromPos, Point fromXDir, Point fromYDir, Point toPos, Point toXDir, Point toYDir);

/*
*   The interface returns angle in range [-180, 180]
*/
double CalcAngleSigned(Point vec0, Point vec1, vtkSPtr<vtkTransform> posXFM)
{
    //judge rotating direction.
    Point axis( 1, 1, 1 );
    posXFM->TransformVector( axis.point, axis.point );
    auto det = vtkMath::Determinant3x3( vec0.point, vec1.point, axis.point );
    auto sinTheta = det/vec0.Length() / vec1.Length();
    std::cout << "det: " << det << ", sinTheta: " << sinTheta << std::endl;

    vec0.Unit();
    vec1.Unit();
    double radianDelta = vtkMath::AngleBetweenVectors( vec0.point, vec1.point );
    if( sinTheta < 0 )
    {
        radianDelta = -radianDelta;
    }
    double angleDelta = vtkMath::DegreesFromRadians( radianDelta );

    return angleDelta;
}

/*
*   The interface returns angle in range [-180, 180]
*/
double CalcAngleSigned(Point vec0, Point vec1, Point refVec)
{
    //judge rotating direction.
    auto crossVec = vec0^vec1;

    vec0.Unit();
    vec1.Unit();
    double radianDelta = vtkMath::AngleBetweenVectors( vec0.point, vec1.point );
    if( crossVec.Dot( refVec ) < 0 )
    {
        radianDelta = -radianDelta;
    }
    double angleDelta = vtkMath::DegreesFromRadians( radianDelta );

    return angleDelta;
}

/*
*   The interface returns angle in range [0, 180]
*/
double CalcAngleUnSigned(Point v, Point u)
{
    v.Unit();
    u.Unit();

    double temp = v.Dot(u);
    double angle = 0;
    if ( fabs(temp) < 1 )
    {
        angle = acos(v.Dot(u))*180.0 / vtkMath::Pi();
    }
    else if ( fabs(temp - 1) < 1e-5 )
    {
        angle = 0;
    }
    else
    {
        angle = 180;
    }

    return angle;
}

int main(int, char *[])
{
    Point vec[2] = { Point( 1, 0, 1 ), Point( 1, -1, 1 ) };
    auto posXFM = CreatePoseTransfrom( Point(0, 0, 0), Point(1, 0, 0), Point(0, 1, 0),
                         Point(1, 0, 1), Point(1, 0, 1), Point(0, 1, 0) );

    std::cout << "CalcAngleSigned: " << CalcAngleSigned( vec[0], vec[1], posXFM ) << std::endl;
    std::cout << "CalcAngleUnSigned: " << CalcAngleUnSigned( vec[0], vec[1] ) << std::endl;
    std::cout << "CalcAngleSigned: " << CalcAngleSigned( vec[0], vec[1], Point(-1, 0, 1 ) ) << std::endl;
    return EXIT_SUCCESS;
}

vtkSPtr<vtkTransform> CreateLocalTrans(Point origin, Point xDir, Point yDir)
{
    vtkSPtrNew( resultTrans, vtkTransform );
    Point zDir = xDir ^ yDir;
    zDir.Unit();

    double elements1[16] = { xDir[0], xDir[1], xDir[2], 0,
                            yDir[0], yDir[1], yDir[2], 0,
                            zDir[0], zDir[1], zDir[2], 0,
                            0, 0, 0, 1 };

    resultTrans->Concatenate(elements1);     //rotation

    double elements2[16] = { 1, 0, 0, -origin[0],
                             0, 1, 0, -origin[1],
                             0, 0, 1, -origin[2],
                             0, 0, 0, 1 };

    resultTrans->Concatenate(elements2);    //translation
    resultTrans->Update();

    return resultTrans;
}


vtkSPtr<vtkTransform> CreatePoseTransfrom(Point fromPos, Point fromXDir, Point fromYDir, Point toPos, Point toXDir, Point toYDir)
{
    fromXDir.Unit();
    fromYDir.Unit();
    toXDir.Unit();
    toYDir.Unit();

    vtkSmartPointer<vtkTransform> localCoordSystem = CreateLocalTrans(fromPos, fromXDir, fromYDir);
    vtkSmartPointer<vtkTransform> worldCoordSystem = CreateLocalTrans(fromPos, fromXDir, fromYDir);
    worldCoordSystem->Inverse();
    worldCoordSystem->Update();

    Point LocalToPosInFromCoor, LocalToXDirInFromCoor, LocalToYDirInFromCoor;
    localCoordSystem->InternalTransformPoint(toPos.point, LocalToPosInFromCoor.point);
    localCoordSystem->InternalTransformVector(toXDir.point, LocalToXDirInFromCoor.point);
    localCoordSystem->InternalTransformVector(toYDir.point, LocalToYDirInFromCoor.point);
    vtkSmartPointer<vtkTransform> toToPoseXFMInFromCoor = CreateLocalTrans(LocalToPosInFromCoor, LocalToXDirInFromCoor, LocalToYDirInFromCoor);
    toToPoseXFMInFromCoor->Inverse();
    toToPoseXFMInFromCoor->Update();

    //construct pose transform
    vtkSmartPointer<vtkTransform> ResultTrans = vtkSmartPointer<vtkTransform>::New();
    ResultTrans->Concatenate(worldCoordSystem->GetMatrix());
    ResultTrans->Concatenate(toToPoseXFMInFromCoor->GetMatrix());
    ResultTrans->Concatenate(localCoordSystem->GetMatrix());
    ResultTrans->Update();

    return ResultTrans;
}

Output:

det: -1.41421, sinTheta: -0.57735
CalcAngleSigned: -35.2644
CalcAngleUnSigned: 35.2644
CalcAngleSigned: -35.2644
Categories: VTK

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments

Content Summary
: Input your strings, the tool can get a brief summary of the content for you.

X
0
Would love your thoughts, please comment.x
()
x