【发布时间】:2009-11-10 11:03:39
【问题描述】:
在数学问题上需要帮助: 我需要使用 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=左
- 等
【问题讨论】:
标签: javascript
在数学问题上需要帮助: 我需要使用 x 和 y 坐标从 0 度获得真实角度 我现在正在使用这个:
Math.atan((x2-x1)/(y1-y2))/(Math.PI/180)
但 /(Math.PI/180) 将结果限制在 -90 到 90
我需要 0-360
注意:我用角度来表示方向:
【问题讨论】:
标签: javascript
atan 函数只给出 -pi/2 和 +pi/2 之间的一半单位圆(x 轴上的 0),还有另一个库函数可以给出 -pi 和 + pi 之间的整个单位圆,atan2
我认为您最好使用 atan2 来获得正确的象限,而不是自己分支,然后像以前一样扩展,例如
Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI + 180
在 pi 上乘以 180 只是问题中从弧度到度数的比例(但除以简化的除法),+180 确保其始终为正,即 0-360 度而不是 -180 到180度
【讨论】:
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, 90 度向上 (x=0,y>0) 135 度向上和向左 (y>0, x=-y) 等等。你的 x 轴和 y 轴指向吗?
【讨论】:
@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
使用模运算可能有更简洁的解决方案,但我找不到。
【讨论】:
(Math.atan2(y, x) * 180 / Math.PI + 450) % 360。
另请注意:
if (y1==y2) {
if (x1>x2)
angle = 90;
else if (x1<x2)
angle = 270;
else
angle = 0;
}
【讨论】:
这应该可以解决问题:
例子:
(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
【讨论】:
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;
【讨论】:
这里有两个解决方案,一个是 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))
})
【讨论】:
对于 0=up,90=right,180=down,270=left 等 (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)))
【讨论】:
所以只有一个决定(我希望这个丑陋的基本符号可以解释它):
如果 x = 0 那么
360 度 = 270 - (SIGN(x) + 1) * 90
否则
360 度 = MOD(180 + (SIGN(y) + 1) * 90 + ATAN(x/y) , 360)
ENDIF
从北 0 度到 360 度顺时针画一个完整的圆:
x=SIN(0to360) y=COS(0to360)
干杯,列夫
【讨论】:
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;
}
}
【讨论】: