Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Gradual Rotation To A Set Angle

4.00/5 (1 vote)
27 May 2015MIT2 min read 5.9K   21  
Development of an algorithm to gradually change an angular setting and stop it at a particular angle.

Introduction

The nature of angles has caused me grief in many of my creative efforts. An angle of 350 degrees can sometimes be considered more than and sometimes less than an angle of say 10 degrees!

Recently, I needed to increment an angle by a variable amount and then stop it in the desired direction. While this should be a trivial problem, something in my brain prevents me from finding a simple solution.

This tip shows one solution to the problem in JavaScript, but the algorithm should be easily understood and transferred to any language.

Background

I needed to code to have a little animated sprite run to one end of the screen and to then gradually turn around and run back again. He would then do the same at the other end of the screen.

In my JavaScript code below, we see the animation update routine:

JavaScript
var manTargetDirection = 0;
var manDirection = 0;

function runningManUpdate(img, dt) {
  // img is the sprite object of a man running
  // dt is the time since the last update in seconds
  // check limits of the sprite
  if(img.vel.x > 0) {
    // man is running from left to right
    if(img.pos.x > (window.innerWidth*3/4)) {
      // set new target direction
      manTargetDirection = 180;
    }
  } else {
    // man is running from right to left
    if(img.pos.x < (window.innerWidth/4)) {
      // set new target direction;
      manTargetDirection = 0;
    }
  }
  // check if direction is in transition
  if(manDirection != manTargetDirection) {
    // yes, so rotate by 20 degrees per second
    manDirection = rotateTo(manDirection,20*dt,manTargetDirection);
  }
  var cos = Math.cos(manDirection*Math.PI/180.0);
  img.scale = new Point(2.0*cos,2.0);
  img.vel = new Point(img.speed*cos,0);
}

Nothing deep and meaningful here.

For the function rotateTo, I had wrongly thought the following would do the trick:

JavaScript
function rotateTo(a_old,delta,target) {
  // should return new angle
  var a_new = a_old + delta;
  if ((a_old < target) && (a_new > target))
    return target;
  else
    return a_new;
}

This works well if a_old is numerically less that the target angle. But what if the target is 0 degrees? Then a_old can never be less than the target and so the little running man goes around and around and around... Other strange things can happen - all because the silly angle keeps coming back to zero.

First Working Generic Solution

After much agony, I have come up with this:

JavaScript
function rotateTo(a_old,delta,target) {
  // returns new angle
  var a_new = a_old + delta;
  var t2;
  if(delta > 0) {
    if((target > a_old) && (target <= a_new))
      return target;
    t2 = target + 360;
    if((t2 > a_old) && (t2 <= a_new))
      return target;
  } else {
    if((target < a_old) && (target >= a_new))
      return target;
    t2 = target - 360;
    if((t2 < a_old) && (t2 >= a_new))
      return target;
  }
  return a_new % 360;
}

This solution works for both positive and negative rotation directions. I would very much like to see a simpler solution - but no lambdas please. I would like to think of this as a beginners' article.

Using the Code

The rotcheck.html code has a simple form to check the operation of the function rotateTo(). As you probably know, it should open in any modern browser and can be edited with any text editor. There has to be a more elegant and simple solution to this. I would even be interested to see how it could be done as a PID control loop - those pesky angles going to 2PI and then being zero again must cause problems even there.

License

This article, along with any associated source code and files, is licensed under The MIT License