0

For this to keep it simple I'm going to be using Euler angles and degrees.

Say I have an angle of 45 degrees. And I want to change the angle to 315 over time. This should take the shortest path to get the target angle. This the case above the shortest path would involve going through 0 degrees to get to 315. I already have a basis for the function below. This however, will not work for angles.

public static final float approach(float current, float goal, float delta) {

    final float difference = goal - current;

    if (difference > delta) return current + delta;
    if (difference < -delta) return current - delta;

    return goal;

}

Here's an image to make the problem seem more clear. https://drive.google.com/file/d/0B4AZGzr3HML0cThORExNMHFEYlE/view

1 Answers1

0

I want to start from scratch to make sure I'm understanding what you're asking.
So for the

 approach() 
function- parameter "current" indicates the current angle. Parameter "goal" indicates the desired angle. And parameter "delta" indicates the time (assuming seconds) that the angle has to reach it's "goal".

Now, to calculate the shortest path to the angle you can simply do something like this:

if(current + (360 - goal) <= 180) // If goal is 180° away it will rotate to the right automatically.
   // ... Rotate to the right
else
   // ... Rotate to the left

We can test that actually works, because if we take your required values (current = 45, goal = 315) and perform the calculation above we should turn right.

45 + (360 - 315) <= 180
45 + 45 <= 180
90 <= 180, true.
We turn it right.

Now it's just a matter of calculating the rotation amount based on delta. This one is fairly simple.
I'll declare "totalAngle" as a variable to keep track of the difference between the current angle and destination angle. I'll assign this variable in the if/else code blocks. I'll also declare a boolean to help me keep track of what direction I need to rotate.

boolean rotateRight;
float totalAngle;

if(current + (360 - goal) <= 180) {
   totalAngle = current + (360 - goal);
   rotateRight = true;
}
else {
   totalAngle = goal - current;
   rotateRight = false;
}

Now assuming that it rotates once per second, I will take the totalAngle and divide it by the amount of seconds passed (aka "delta" parameter). Then I modify the "current" parameter, and return it.

current -= rotateRight ? (totalAngle / delta) : -(total / delta);

The end function should look something like this:

public static float approach(float current, float goal, float delta) {
   boolean rotateRight;
   float totalAngle;

   if(current + (360 - goal) <= 180) {
      totalAngle = current + (360 - goal);
      rotateRight = true;
   }
   else {
      totalAngle = goal - current;
      rotateRight = false;
   }

   current -= rotateRight ? (totalAngle / delta) : -(totalAngle / delta);
   return current;
}

Edit: If the shortest path is actually the longest, assume that "current - (360 - goal) <= 180" is a left rotation, not a right & vise versa.

  • Thanks! This works for the most part! Sorry that I didn't make the approach() function very clear. The delta parameter in the function actually is the amount of degrees I want to rotate towards the target angle. However your implementation should be easy to adjust for this. – ASasseCreations Feb 15 '17 at 04:45
  • No problem! Glad I could help :) – Expert Thinker El Rey Feb 16 '17 at 00:39