Get angle in terms of 360 degrees

Growler picture Growler · Jan 30, 2015 · Viewed 9.4k times · Source

I would like to get an angle in terms of 360 degrees... for my game, I need to know which direction the player is heading in...

enter image description here

The code here gets the proper angles, but only in terms of 90 degree increments: (meaning, when I click in upper left quadrant, I get angle from 0 to 90 degrees... bottom left is 0 to -90 degrees, etc...)

enter image description here

    var dY = this.pos.y-e.gameY;            //opposite
    var dX = this.pos.x-e.gameX;            //adjacent
    var dist = Math.sqrt((dY*dY)+(dX*dX));  //hypotenuse
    var sin = dY/dist;                      //opposite over hypotenuse
    var radians = Math.asin(sin);
    var degrees = radians*(180/Math.PI);    //convert from radians to degrees
    this.calculatedAngle = degrees;     

How can I get it in terms of 360 degrees?


Here is another example: The top two represent the issue... when I click in the upper/lower left quadrant, it keeps drawing a right triangle from the x axis...

I need it to be like the lower 2 pictures, where it keeps drawing the angle around:

enter image description here

Answer

Joseph Myers picture Joseph Myers · Jan 30, 2015

You can do this directly from the coordinates, without computing extra information like the hypotenuse, by using the atan2 function, which was designed in the early days of FORTRAN for situations exactly like yours.

Note two important things:

  1. that the atan2 function has been created to automatically handle all but one case of the many possible cases, and
  2. it will output a range of (-PI, PI].

The case where both coordinates are (0, 0) is left undefined (all angles are equivalent when the magnitude of a vector is zero), so I'm arbitrarily setting the angle to zero degrees in that case. And in order to obtain the desired range, some simple logic and addition is needed.

var Vx = this.pos.x - e.gameX;
var Vy = this.pos.y - e.gameY;

var radians;

if (Vx || Vy) {
    radians = Math.atan2(Vy, Vx);
} else {
    radians = 0;
}

if (radians < 0) {
    radians += 2*Math.PI;
}

var degrees = radians * 180 / Math.PI;

this.calculatedAngle = degrees;

The result will be an angle defined for all cases and within the range [0, 360°), as desired.

Example

function showDegrees(e, svg) {
	var rectangle = svg.getBoundingClientRect();
	var targetX = (rectangle.left + rectangle.right)/2;
	var targetY = (rectangle.top + rectangle.bottom)/2;
	var Vx = Math.round(e.clientX - targetX);
	var Vy = Math.round(targetY - e.clientY);
	var radians = Math.atan2(Vy, Vx);
	if (radians < 0) radians += 2*Math.PI;
	var degrees = Math.round(radians*180/Math.PI);
	var textBox = document.getElementById('showdegrees');
	textBox.innerHTML = degrees + '&deg;' + ' (' + Vx + ', ' + Vy + ')';
	textBox.setAttribute('x', Math.round(100 + Vx));
	textBox.setAttribute('y', Math.round(100 - Vy));
}
<svg width="200" height="200" viewBox="0 0 200 200" onmousemove="showDegrees(evt, this)">
<text x="0" y="0" fill="red" style="font-size: 12px"  id="showdegrees">Info</text>
<line x1="100" y1="0" x2="100" y2="200" style="stroke: black; stroke-width: 1" />
<line x1="0" y1="100" x2="200" y2="100" style="stroke: black; stroke-width: 1" />
</svg>