Because nature of rotation angle, when we interpolate angles we could have some problems. For instance we have angle A0 and A1.
A0 is -170 degree
A1 is 170 degree
If we interpolate A0 to A1 then it will take 340 degree turn to reach the A1.(which is clockwise)
instead we can take 20 degree which is counter-clockwise, it is much faster way to reach A1. To solve this kind of problem we can use wrap angle technique.
// angle in degree
float wrapPI(float angle)
{
float secondTerm = floor((angle + 180.0f) / 360.0f);
return angle - 360.0f * secondTerm;
}
floor is the function which will take same as given input x or highest integer value less than.
As you can see the below video, blue line is the A0(which is base angle) and red line(longer one) is the target angle which is A1. shorter red line is the result of interpolation.
// angle in degree
float wrapPI(float angle)
{
float secondTerm = floor((angle + 180.0f) / 360.0f);
return angle - 360.0f * secondTerm;
}
float baseAngle = 0;
float targetAngle = 90;
float angleRatio = 0.0f;
void Render(HDC hdc)
{
XFORM xForm;
xForm.eM11 = (FLOAT) 1.0;
xForm.eM12 = (FLOAT) 0.0;
xForm.eM21 = (FLOAT) 0.0;
xForm.eM22 = (FLOAT) -1.0;
xForm.eDx = (FLOAT) 300.0;
xForm.eDy = (FLOAT) 300.0;
SetGraphicsMode(hdc, GM_ADVANCED);
SetWorldTransform(hdc, &xForm);
float baseLength = 100;
float targetLength = 80;
float diffAngle = wrapPI(targetAngle - baseAngle);
float angle = baseAngle + (diffAngle * angleRatio);
// draw baseAngle
HPEN bluePen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
HPEN redPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
HGDIOBJ oldPen = nullptr;
oldPen = SelectObject(hdc, bluePen);
MoveToEx(hdc, 0, 0, nullptr);
// convert degree to radian
float baseRadian = baseAngle * 3.14 / 180.0f;
LineTo(hdc, cosf(baseRadian) * baseLength, sinf(baseRadian) * baseLength);
SelectObject(hdc, oldPen);
DeleteObject(bluePen);
oldPen = SelectObject(hdc, redPen);
MoveToEx(hdc, 0, 0, nullptr);
float angleRadian = angle * 3.14 / 180.0f;
float targetRadian = targetAngle * 3.14 / 180.0f;
LineTo(hdc, cosf(targetRadian) * baseLength, sinf(targetRadian) * baseLength);
MoveToEx(hdc, 0, 0, nullptr);
LineTo(hdc, cosf(angleRadian) * targetLength, sinf(angleRadian) * targetLength);
SelectObject(hdc, oldPen);
DeleteObject(redPen);
angleRatio += 0.01f;
if (angleRatio >= 1.0f)
{
// choose another
baseAngle = rand() % 360;
targetAngle = rand() % 360;
angleRatio = 0.0f;
}
}