简体   繁体   中英

How do I calculate the angle between two points?

I am attempting to create a 2d tile based game in Javascript, and I need to be able to calculate the angle between two points. I am using the atan2 function to find the angle between two points like so:

function getAngleDegrees(fromX, fromY, toX, toY, force360 = true) {
    let deltaX = toX - fromX;
    let deltaY = toY - fromY;
    let radians = Math.atan2(deltaY, deltaX);
    let degrees = (radians * 180) / Math.PI;
    if (force360) {
      while (degrees >= 360) degrees -= 360;
      while (degrees < 0) degrees += 360;
    }
    return degrees;
  }

However, this isn't providing me with the correct result. I have checked the code for logic or math errors and can't find any. No matter what points I input to this function the result will be off by many degrees.

I have created a JS fiddle to visualize the problem:

https://jsfiddle.net/fa6o7wdy/40/

If anyone knows how I can fix my angle function to provide the correct result please help!

Edit:

Here is a picture of the problem:

https://imgur.com/a/OXDCOux

Based on the photo sample you provide, for getting the desired angle you want with current Math.atan() function, you want to reverse first and then rotate the angle by 90 degrees couter clockwise

function getAngleDegrees(fromX,fromY,toX,toY,force360 = true) {
  let deltaX = fromX-toX; 
  let deltaY = fromY-toY; // reverse
  let radians = Math.atan2(deltaY, deltaX)
  let degrees = (radians * 180) / Math.PI - 90; // rotate
  if (force360) {
     while (degrees >= 360) degrees -= 360;
     while (degrees < 0) degrees += 360;
  }
  console.log('angle to degree:',{deltaX,deltaY,radians,degrees})
  return degrees;
}

or simply + 90 degrees to this line without changing deltaX and deltaY

let degrees = (radians * 180) / Math.PI + 90; // rotate

Note: I haven't test out all possible edge cases

 const inBlk = document.createElement('i') , getXY = (p,xy) => Number(p.split('-')[xy==='x'?0:1]) ; for(let i=0;i<100;i++) // build Grid { let nI = inBlk.cloneNode() , u1 = i%10 ; nI.textContent = u1+'-'+(i-u1)/10 grid.appendChild(nI) } let points = [ {x:0, y:0, old:null}, {x:0, y:0, old:null}] , pN = 0 ; grid.onclick=e=> { if (!e.target.matches('i')) return let elm = e.target.textContent points[pN].x = getXY(elm, 'x') points[pN].y = getXY(elm, 'y') if (points[pN].old ) points[pN].old.classList.remove('color_0', 'color_1') points[pN].old = e.target points[pN].old.classList.add(`color_${pN}` ) pN = ++pN %2 if (pN==0) angle.textContent = ` angle: ${getAngleDegrees(points[0],points[1])}°` } function getAngleDegrees( from, to, force360 =true) { let deltaX = from.x - to.x , deltaY = from.y - to.y // reverse , radians = Math.atan2(deltaY, deltaX) , degrees = (radians * 180) / Math.PI - 90 // rotate ; if (force360) { while (degrees >= 360) degrees -= 360; while (degrees < 0) degrees += 360; } return degrees.toFixed(2) }
 :root { --sz-hw: 26px; } #grid { font-family: 'Courier New', Courier, monospace; font-size : 10px; margin : calc( var(--sz-hw) /2); } #grid i { display : block; float : left; width : var(--sz-hw); height : var(--sz-hw); border : 1px solid grey; text-align : center; margin : 2px; line-height: var(--sz-hw); cursor : pointer; } #grid i:nth-child(10n-9) {clear: both; } .color_0 { background-color: lightcoral; } .color_1 { background-color: lightgreen; } #angle { padding: calc( var(--sz-hw) /2) 0 0 calc( var(--sz-hw) *13.4); }
 <p id="grid"></p> <h4 id="angle">angle: ?</h4>

Your code is working correctly, it's just that you have a bit of confusion in your coordinate system.

The angle between 2 points is relative to where you measure from. By subtracting P2 from P1, you're making the angle relative to your starting point. Thus, atan2 is giving you the clockwise angle relative to the X axis.

Traditionally, the X axis is the starting point for rotations, so a horizontal line has an angle of 0:

x = 1;
y = 0;
angle = atan2(y, x) // Equals 0

You've got your grid with Y+ going down, so as Y becomes positive, you'll get clockwise angles from the x-axis.

x = 0;
y = 1;
angle = atan2(y, x) // Equals PI/2, or 90deg

If this is confusing with Y+ going down, you may want to rethink your grid so that Y+ goes up instead.

PS: Good luck on your game!

DeltaX toX and fromX needed to be swapped around, same goes for DeltaY. Also, I've subtracted 90 to angle, in order to make 0 degree being North.

The % (mod) operator does same job as your 2 x while loop.

function getAngleDegrees(fromX,fromY,toX,toY,force360 = true) {
    let deltaX = fromX - toX;
    let deltaY = fromY - toY;
    let radians = Math.atan2(deltaY, deltaX)
    let degrees = ((radians * 180) / Math.PI) - 90;
    if (force360) {
       degrees  = (degrees + 360) % 360;
    }
    console.log('angle to degree:',{deltaX,deltaY,radians,degrees})
    return degrees;
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM