获取 360 度的角度
Get angle in terms of 360 degrees
我想获得 360 度的角度...对于我的游戏,我需要知道玩家的前进方向...
此处的代码获得了正确的角度,但仅以 90 度为增量:(意思是,当我单击左上象限时,我获得的角度为 0 到 90 度...左下角为 0 到 - 90 度等...)
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;
360度如何获取?
再举一个例子:前两个代表问题...当我在upper/lower左象限中单击时,它一直从x轴绘制一个直角三角形...
我需要它像下面两张图片一样,它一直在画周围的角度:
你需要使用比 arcsin 多一点的信息来解决这个问题。这样做的原因是如您所知,arcsin 只会 return 介于 -π/2 和 π/2(-90 度和 90 度)之间的值。
所以,要弄清楚另一部分,你需要知道你在哪个象限。
在2象限,arcsin在90和0之间,实角在90和180之间。所以如果你在2象限,180-calculated angle
=real angle
。 (180-90=90, 180-0=180)
.
在第 3 象限中,arcsin 在 0 到 -90 之间。实际角度在 180 和 270 之间。因此,180-calculated angle
= real angle
。 (180-0=180, 180-(-90)=270)
.
在第4象限,arcsin在-90到0之间,真实角度在270到360之间,所以360+calculated angle
=real angle
。 (360+(-90)=270, 360+0)=360)
.
象限1也是一样,只是不需要做变换。 (0+360=360 (equivalent to 0), 90+360=450 (equivalent to 90) )
.
所以,先确定象限,然后根据象限应用规则。
对于 (x,y) 坐标,如果 x 为正且 y 为正,则您在象限 1。如果 x 为负且 y 为正,则您在象限 2。如果 x 为负且 y 为负,则您在象限 3 .如果x是正数,y是负数,你是第4象限
所以在你的情况下,到原点的距离是你的 (dX,dY)
坐标对,所以应该这样做:
//your original code...
var degrees = radians*(180/Math.PI); //convert from radians to degrees
//then
if (dX>=0 and dY>=0)
{//quadrant 1
//no transformation, do nothing
}
if (dX>=0 and dy<0)
{ //quadrant 4
degrees=360+degrees;
}
if (dX<0 and dy<0)
{ //quadrant 3
degrees=180-degrees;
}
if (dX<0 and dy>0)
{ //quadrant 2
degrees=180-degrees;
}
this.calculatedAngle = degrees;
试试这个:
var dY = this.pos.y - e.gameY, // opposite
dX = this.pos.x - e.gameX, // adjacent
radians = Math.atan(dY/dX); // wrong, in [-1/2 pi, 1/2 pi]
if(1/dX < 0) radians += Math.PI; // fixed, in [-1/2 pi, 3/2 pi]
if(1/radians < 0) radians += 2*Math.PI; // fixed, in [+0, 2 pi]
var degrees = radians*180/Math.PI; // from radians to degrees
解释:
- 最好用
Math.atan
和切线计算弧度。使用 Math.sqrt
计算斜边很昂贵。
Math.atan
给出了-1/2 pi
和1/2 pi
之间的夹角,即右半圆。要修复它,只需对 pi
求和,以防 dX
为负数。
- 然后我们得到
-1/2 pi
和3/2 pi
之间的角度。因此,如果它是负数,我们对 2 pi
求和以获得 0
和 2 pi
之间的角度。
- 请注意,我们必须考虑
-0
否定才能使其正常工作。因此,我们不检查 dX < 0
和 radians < 0
,而是检查它们的倒数。
- 请注意,如果
dX
和 dY
均为 0
(或 -0
),则最终结果将为 NaN
。
您可以直接从坐标执行此操作,而无需计算斜边等额外信息,方法是使用 atan2
函数,该函数是 FORTRAN 早期为与您的情况完全相同的情况而设计的。
注意两件重要的事情:
- 已创建
atan2
函数来自动处理 除了一种情况之外的所有情况,并且
- 它将输出范围
(-PI, PI]
。
两个坐标均为 (0, 0) 的情况未定义(当向量的大小为零时所有角度都相等),因此在这种情况下我任意将角度设置为零度。而为了得到想要的范围,还需要一些简单的逻辑和加法。
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;
结果将是为所有情况定义的角度,并根据需要在 [0, 360°) 范围内。
例子
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 + '°' + ' (' + 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>
我想获得 360 度的角度...对于我的游戏,我需要知道玩家的前进方向...
此处的代码获得了正确的角度,但仅以 90 度为增量:(意思是,当我单击左上象限时,我获得的角度为 0 到 90 度...左下角为 0 到 - 90 度等...)
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;
360度如何获取?
再举一个例子:前两个代表问题...当我在upper/lower左象限中单击时,它一直从x轴绘制一个直角三角形...
我需要它像下面两张图片一样,它一直在画周围的角度:
你需要使用比 arcsin 多一点的信息来解决这个问题。这样做的原因是如您所知,arcsin 只会 return 介于 -π/2 和 π/2(-90 度和 90 度)之间的值。
所以,要弄清楚另一部分,你需要知道你在哪个象限。
在2象限,arcsin在90和0之间,实角在90和180之间。所以如果你在2象限,180-calculated angle
=real angle
。 (180-90=90, 180-0=180)
.
在第 3 象限中,arcsin 在 0 到 -90 之间。实际角度在 180 和 270 之间。因此,180-calculated angle
= real angle
。 (180-0=180, 180-(-90)=270)
.
在第4象限,arcsin在-90到0之间,真实角度在270到360之间,所以360+calculated angle
=real angle
。 (360+(-90)=270, 360+0)=360)
.
象限1也是一样,只是不需要做变换。 (0+360=360 (equivalent to 0), 90+360=450 (equivalent to 90) )
.
所以,先确定象限,然后根据象限应用规则。 对于 (x,y) 坐标,如果 x 为正且 y 为正,则您在象限 1。如果 x 为负且 y 为正,则您在象限 2。如果 x 为负且 y 为负,则您在象限 3 .如果x是正数,y是负数,你是第4象限
所以在你的情况下,到原点的距离是你的 (dX,dY)
坐标对,所以应该这样做:
//your original code...
var degrees = radians*(180/Math.PI); //convert from radians to degrees
//then
if (dX>=0 and dY>=0)
{//quadrant 1
//no transformation, do nothing
}
if (dX>=0 and dy<0)
{ //quadrant 4
degrees=360+degrees;
}
if (dX<0 and dy<0)
{ //quadrant 3
degrees=180-degrees;
}
if (dX<0 and dy>0)
{ //quadrant 2
degrees=180-degrees;
}
this.calculatedAngle = degrees;
试试这个:
var dY = this.pos.y - e.gameY, // opposite
dX = this.pos.x - e.gameX, // adjacent
radians = Math.atan(dY/dX); // wrong, in [-1/2 pi, 1/2 pi]
if(1/dX < 0) radians += Math.PI; // fixed, in [-1/2 pi, 3/2 pi]
if(1/radians < 0) radians += 2*Math.PI; // fixed, in [+0, 2 pi]
var degrees = radians*180/Math.PI; // from radians to degrees
解释:
- 最好用
Math.atan
和切线计算弧度。使用Math.sqrt
计算斜边很昂贵。 Math.atan
给出了-1/2 pi
和1/2 pi
之间的夹角,即右半圆。要修复它,只需对pi
求和,以防dX
为负数。- 然后我们得到
-1/2 pi
和3/2 pi
之间的角度。因此,如果它是负数,我们对2 pi
求和以获得0
和2 pi
之间的角度。 - 请注意,我们必须考虑
-0
否定才能使其正常工作。因此,我们不检查dX < 0
和radians < 0
,而是检查它们的倒数。 - 请注意,如果
dX
和dY
均为0
(或-0
),则最终结果将为NaN
。
您可以直接从坐标执行此操作,而无需计算斜边等额外信息,方法是使用 atan2
函数,该函数是 FORTRAN 早期为与您的情况完全相同的情况而设计的。
注意两件重要的事情:
- 已创建
atan2
函数来自动处理 除了一种情况之外的所有情况,并且 - 它将输出范围
(-PI, PI]
。
两个坐标均为 (0, 0) 的情况未定义(当向量的大小为零时所有角度都相等),因此在这种情况下我任意将角度设置为零度。而为了得到想要的范围,还需要一些简单的逻辑和加法。
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;
结果将是为所有情况定义的角度,并根据需要在 [0, 360°) 范围内。
例子
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 + '°' + ' (' + 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>