找到角度0-360

时间:2009-11-10 11:03:40

标签: javascript

需要数学问题的帮助: 我需要使用x和y坐标从0度获得真正的角度 我现在正在使用这个:

Math.atan((x2-x1)/(y1-y2))/(Math.PI/180)

/(Math.PI/180)将结果限制在-90到90之间 我需要0-360

注意:我正在使用角度来指示方向:

  • 0 =上
  • 90 =右
  • 135 = 45度右+下
  • 180 =向下
  • 270 =左
  • etc

10 个答案:

答案 0 :(得分:33)

atan函数只给出-pi / 2和+ pi / 2之间的单位圆的一半(x轴上为0),还有另一个库函数可以给出-pi和+ pi之间的整个单位圆,atan2 < / p>

我认为你最好使用atan2来获得正确的象限而不是自己分支,然后像你一样扩展,比如

Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI + 180

在pi上乘以180就是在问题中从弧度到度数的比例(但是通过简化划分除以),+180确保它始终为正,即0-360度而不是-180到180度

答案 1 :(得分:11)

Math.atan将您限制在单位圆上最右边的两个象限。要获得完整的0-360度:

if x < 0 add 180 to the angle
else if y < 0 add 360 to the angle. 

与我的相比,您的坐标系被旋转和反转(并与常规相比)。正x是向右,正y是向上。 0度是向右(x> 0,y = 0,9度是向上(x = 0,y> 0)135度是向上和向左(y> 0,x = -y)等。你的x轴和y轴指向?

答案 2 :(得分:2)

@ jilles de wit和@jk的答案。引导我走上正确的道路,但由于某些原因没有为我的问题提供正确的解决方案,我认为这与原始问题非常相似。

我想在航空导航系统中起床= 0°,右= 90°,下降= 180°,左= 270°。

假设问题是指画布画我达到了这个解决方案:

我首先使用ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2)翻译了画布原点。我还将e.offsetX和e.offsedY减半,我从画布上的鼠标事件中得到了x和y,其坐标系与画布相同。

let radianAngle = Math.atan2(y, x);    // x has the range [-canvas.width/2 ... +canvas.width/2], y is similar
let northUpAngle = radianAngle * 180 / PI + 90;    // convert to degrees and add 90 to shift the angle counterclockwise from it's default "left" = 0°
if (x < 0 && y < 0) {    // check for the top left quadrant
    northUpAngle += 360;    // add 360 to convert the range of the quadrant from [-90...0] to [270...360] (actual ranges may vary due to the way atan2 handles quadrant boundaries)
}
northUpAngle.toFixed(2)    // to avoid getting 360° near the "up" position

使用模运算可能会有更简洁的解决方案,但我找不到它。

答案 3 :(得分:1)

另请注意:

if (y1==y2) {
    if (x1>x2)
        angle = 90;
    else if (x1<x2)
        angle = 270;
    else
        angle = 0;
}

答案 4 :(得分:1)

这里有两种解决方案,一种是使用Math.atan(带相反/相邻的分数),另一种是使用Math.atan2(带两个参数)

具有讽刺意味的是,解决方案使用ES6(ES2015 +)语法编写,因为问题早于此javascript。

请注意,“向右”是0°(= 0弧度);向上是90°(= PI / 2);左侧为180°(PI),向下为270°(PI * 1.5)

angleGivenCoords(coord1,coord2) {
    // given two coords {x,y}, calculate the angle in radians with
    // right being 0° (0 radians)

    if (coord1.x === coord2.x) return (coord1.y > coord2.y ? Math.PI * 0.5 : Math.PI * 1.5)
    if (coord1.y === coord2.y) return (coord1.x > coord2.x ? Math.PI : 0 )

    let opposite = coord2.x - coord1.x
    let adjacent = coord1.y - coord2.y
    let adjustor = ((coord2.x < coord1.x && coord2.y < coord1.y) || (coord2.x < coord1.x && coord2.y > coord1.y)) ?  Math.PI : 0

    let res = Math.atan(opposite/adjacent) + adjustor

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

现在使用Math.atan2。请注意,使用此解决方案,不需要顶部的保护子句(coord1.x === coord2.x,(coord1.y === coord2.y))

  angleGivenCoords(coord1,coord2) {
    // given two coords {x,y}, calculate the angle in radians with
    // left being 0° (0 radians)
    let opposite = coord2.x - coord1.x
    let adjacent = coord1.y - coord2.y
    let res = Math.atan2(adjacent, opposite)
    if (res < 0) { res = res + Math.PI*2  }
    return res ;
  }

(我试图保留三角的“对立”和“相邻”变量名)

请注意,这是我用Jest编写的测试套件。还要注意,我上面的函数返回弧度,而我的代码(此处未显示)具有您期望的简单Trig.degreesToRadians()

 it('for right 0°', () => {
    let coord1 = {x: 500, y: 500},
      coord2 = {x: 600, y: 500}
    expect(Trig.angleGivenCoords(coord1,coord2)).toEqual(Trig.degreesToRadians(0))
  })


  it('for up-right 45°', () => {
    let coord1 = {x: 500, y: 500},
      coord2 = {x: 600, y: 400}
    expect(Trig.angleGivenCoords(coord1,coord2)).toEqual(Trig.degreesToRadians(45))
  })

  it('for 90° up', () => {
    let coord1 = {x: 500, y: 500},
      coord2 = {x: 500, y: 400}
    expect(Trig.angleGivenCoords(coord1,coord2)).toEqual(Trig.degreesToRadians(90))
  })


  it('for 135° up to left', () => {
    let coord1 = {x: 500, y: 500},
      coord2 = {x: 400, y: 400}
    expect(Trig.angleGivenCoords(coord1,coord2)).toEqual(Trig.degreesToRadians(135))
  })

  it('for 180° to left', () => {
    let coord1 = {x: 500, y: 500},
      coord2 = {x: 400, y: 500}
    expect(Trig.angleGivenCoords(coord1,coord2)).toEqual(Trig.degreesToRadians(180))
  })


  it('for 225° to to bottom left', () => {
    let coord1 = {x: 500, y: 500},
      coord2 = {x: 400, y: 600}
    expect(Trig.angleGivenCoords(coord1,coord2)).toEqual(Trig.degreesToRadians(225))
  })

  it('for 270° to the bottom', () => {
    let coord1 = {x: 500, y: 500},
      coord2 = {x: 500, y: 600}
    expect(Trig.angleGivenCoords(coord1,coord2)).toEqual(Trig.degreesToRadians(270))
  })

  it('for 315° to the bottom', () => {
    let coord1 = {x: 500, y: 500},
      coord2 = {x: 600, y: 600}
    expect(Trig.angleGivenCoords(coord1,coord2)).toEqual(Trig.degreesToRadians(315))
  })

答案 5 :(得分:0)

这应该可以解决问题:

  1. 如果是y2
  2. 如果&lt; 0,添加360.
  3. 示例:

    (x1,y1)= 0

    (x2,y2) = (-1,1), atan() = -45, [add 360], 270
    (x2,y2) = (1,1), atan() = 45
    (x2,y2) = (1,-1), atan() = -45, [add 180], 135
    (x2 ,y2) = (-1,-1), atan() = 45, [add 180], 225
    

答案 6 :(得分:0)

angle = Math.atan(this.k) * 180 / Math.PI;
angle = 180 - (angle < 0 ? 180 + angle : angle);
angle = p2.Y > p1.Y || (p2.Y == p1.Y && p2.X > p1.X) ? 180 + angle : angle;

答案 7 :(得分:0)

对于0 =向上,90 =向右,180 =向下,270 =向左等(x = x2-x1,y = y2-y1)

您可以使用公式:

f(x,y)=180-90*(1+sign(y))* (1-sign(x^2))-45*(2+sign(y))*sign(x)

-(180/pi())*sign(x*y)*atan((abs(y)-abs(x))/(abs(y)+abs(x)))

答案 8 :(得分:0)

所以只有一个决定(我希望这个丑陋的基本符号能解释它):

如果x = 0,然后

360度= 270-(SIGN(x)+1)* 90

ELSE

360度= MOD(180 +(SIGN(y)+1)* 90 + ATAN(x / y),360)

ENDIF

沿顺时针方向从北0度到360度画一个完整的圆:

x = SIN(0to360)y = COS(0to360)

欢呼,列夫

答案 9 :(得分:-2)

function angle(x1,y1,x2,y2)
{
eangle = Math.atan((x2-x1)/(y1-y2))/(Math.PI/180)
if ( angle > 0 )
{
  if (y1 < y2)
    return angle;
  else
    return 180 + angle;
} else {
  if (x1 < x2)
    return 180 + angle;
  else
    return 360 + angle;
}
}