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 <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 )
{
}

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 )
{
}

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

Article Rating
Subscribe
Notify of