获取 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 pi1/2 pi之间的夹角,即右半圆。要修复它,只需对 pi 求和,以防 dX 为负数。
  • 然后我们得到-1/2 pi3/2 pi之间的角度。因此,如果它是负数,我们对 2 pi 求和以获得 02 pi 之间的角度。
  • 请注意,我们必须考虑 -0 否定才能使其正常工作。因此,我们不检查 dX < 0radians < 0,而是检查它们的倒数。
  • 请注意,如果 dXdY 均为 0(或 -0),则最终结果将为 NaN

您可以直接从坐标执行此操作,而无需计算斜边等额外信息,方法是使用 atan2 函数,该函数是 FORTRAN 早期为与您的情况完全相同的情况而设计的。

注意两件重要的事情:

  1. 已创建 atan2 函数来自动处理 除了一种情况之外的所有情况,并且
  2. 它将输出范围(-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 + '&deg;' + ' (' + 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>