需要解决一个数学问题: 我需要使用 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=向左
- 等等
需要解决一个数学问题: 我需要使用 x 和 y 坐标来获取相对于 0 度的真实角度。 目前我正在使用以下代码:
Math.atan((x2-x1)/(y1-y2))/(Math.PI/180)
但是/(Math.PI/180)
会将结果限制在-90到90之间,我需要0-360。
注意:我使用角度来表示方向:
atan函数只能在-x轴到+x轴之间的半个单位圆内(0在x轴上)提供结果,而在-pi和+pi之间的整个单位圆需要使用另一个库函数来获取,即atan2。
我认为最好使用atan2来获取正确的象限,而不是自己分支,然后按照您一直在做的方式进行缩放,例如:
Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI + 180
将180除以pi得出的数值只是将弧度转换为角度的比例尺,这与问题中的内容相同(但进行了简化)。加上+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轴指向哪里?
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
。 - John S同时需要注意:
if (y1==y2) {
if (x1>x2)
angle = 90;
else if (x1<x2)
angle = 270;
else
angle = 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;
这应该可以解决问题:
示例:
(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
因此,通过单个决策(我希望这种丑陋的类Basic符号可以解释清楚):
如果x = 0,则
360度 = 270 -(SIGN(x)+1)* 90
否则
360度= MOD(180 +(SIGN(y)+1)* 90 + ATAN(x / y),360)
ENDIF
要从北部0度顺时针绘制一个完整的圆:
x = SIN(0to360)y = COS(0to360)
干杯,Lev
对于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)))
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 ;
}
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))
})
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;
}
}