计算角度是否在两个角度之间

时间:2012-09-02 08:47:23

标签: math trigonometry

所以我正在制作一个小游戏,我正在检查角色是否可以“看到”另一个角色A可以看到角色B,如果A在B的某个距离内,并且A的角度方向是+/-角度B的45度朝向。

目前,我正在进行一些计算,我正在检查是否

(facingAngle - 45) =< angleOfTarget =< (facingAngle + 45)

除了当我们穿过360度线时,这种方法很好。

我们说facingAngle = 359, angleOfTarget = 5。在这种情况下,目标只偏离中心6度,所以我希望我的函数返回true。不幸的是,5不在314和404之间。

6 个答案:

答案 0 :(得分:21)

试试

anglediff = (facingAngle - angleOfTarget + 180 + 360) % 360 - 180

if (anglediff <= 45 && anglediff>=-45) ....

原因是角度的差异为facingAngle - angleOfTarget,但由于包裹效应,可能会偏离360度。

添加180 + 360然后模数360然后减去180,实际上只是将所有内容转换为-180到180度的范围(通过加或减360度)。

然后您可以轻松检查角度差异,是否在-45到45度之间。

答案 1 :(得分:8)

有一个三角解决方案可以避免包装问题。

我假设你有两个字符P1P2的(x,y)坐标。你已经指定你知道两者之间的距离,你可能用毕达哥拉斯定理计算了它。

您可以使用两个向量的点积来计算它们之间的角度:

A . B = |A| . |B| . cos(theta).

如果您将A作为facingAngle向量,它将为[cos(fA), sin(fA)],且幅度|A|为1。

如果您将B作为两个字符之间的向量,并且您的距离高于:

cos(theta) = (cos(fA) * (P2x - P1x) + sin(fA) * (P2y - P1y)) / |B|

其中|B|是您已计算的距离。

您无需实际使用反余弦来查找theta,因为对于-45到+45的范围,您只需要检查cos(theta) >= 0.70710678(即1 / sqrt(2)

这似乎略微复杂,但是你可能已经在你的程序中找到了所有必需的变量。

答案 2 :(得分:8)

这是我在网上找到的一个简单的功能,并进行了修改。 它适用于任何角度(可以在0-360之外)。 (此功能适用于c,适用于Xcode。)

请记住,它会从角度A到角度B检查COUNTER-CLOCKWISE。如果角度在以下之间,则返回 YES (true)。)

首先,简单的转换功能使所有角度为1-360

//function to convert angle to 1-360 degrees
 static inline double angle_1to360(double angle){
 angle=((int)angle % 360) + (angle-trunc(angle)); //converts angle to range -360 + 360
 if(angle>0.0)
 return angle;
 else
 return angle + 360.0;
 }

检查角度是否介于:)

//check if angle is between angles
 static inline BOOL angle_is_between_angles(float N,float a,float b) {
 N = angle_1to360(N); //normalize angles to be 1-360 degrees
 a = angle_1to360(a);
 b = angle_1to360(b);

 if (a < b)
 return a <= N && N <= b;
 return a <= N || N <= b;
 }

enter image description here

EG。检查角度300是否在180到10度之间:

BOOL isBetween=angle_is_between_angles( 300, 180,10);

//返回是

答案 3 :(得分:0)

处理低端包装(转换为负值)的简单解决方案就是为所有值添加360:

(facingAngle + 315) =< (angleOfTarget + 360) =< (facingAngle + 405)

这样,45的减法永远不会消极,因为它不再发生。

要处理顶端的换行,您需要再次检查,将另一个 360添加到angleOfTarget值:

canSee  = (facingAngle + 315 <= angleOfTarget + 360) &&
          (angleOfTarget + 360 <= facingAngle + 405);
canSee |= (facingAngle + 315 <= angleOfTarget + 720) &&
          (angleOfTarget + 720 <= facingAngle + 405);

答案 4 :(得分:0)

使用始终最小正差并与阈值比较的另一种方法:

anglediff = Math.min(Math.abs(facingAngle - angleOfTarget), 360 - Math.abs(angleOfTarget - allowDirection));
if (anglediff <= 45)

答案 5 :(得分:0)

以不同的方式重述Alnitak的答案,避免角度环绕360度的解决方案是在不同的坐标系中重新解决问题,其中角度总是很小。这是代码:

def inside_angle(facing, target):
    dot = cos(facing)*cos(target) + sin(facing)*sin(target)
    angle = acos(dot)

    return angle <= pi/4

这是使用矢量投影完成的。假设向量&gt; = [cos(面对)罪(面对)]和|目标&gt; = [cos(目标)sin(目标)],当将目标投影到面对矢量时,当目标正好在面向量时或者将增加到任一侧时,角度将从零开始。这样我们就可以将它与pi / 4(45度)进行比较。角度的公式如下:

cos(angle) = <facing|target> / <target|target> <facing|facing>

即,角度的余弦是矢量&gt;之间的点积。和|目标&gt;将它们的模块分开,在这种情况下为1,变为:

angle = acos(<facing|target>)

参考: https://en.wikipedia.org/wiki/Vector_projection