确定平均角度

时间:2013-08-06 00:47:21

标签: math angle

我正在开发一个涉及在游戏中获取相机角度的应用程序。角度可以是0-359。 0是North,90是East,180是South等。我正在使用API​​,它在Camera类中有一个getAngle()方法。

如何找到不同摄像机角度之间的平均值。实际平均值0和359是179.5。作为摄像机角度,这将是南方,但显然0和359都非常接近北方。

4 个答案:

答案 0 :(得分:5)

你可以用矢量来思考它。让θ1θ2成为您在radians中表达的两个角度。然后我们可以确定处于这些角度的单位向量的x和y分量:

x1 = sin(θ1)
y1 = cos(θ1)

x2 = sin(θ2)
y2 = cos(θ2)

然后,您可以添加这两个向量,并确定结果的x和y分量:

x* = x1 + x2
y* = y1 + y2

最后,您可以确定此结果矢量的角度:

θavg = tan-1(y*/x*)

或者更好的是,使用atan2(许多语言支持的功能):

θavg = atan2(y*, x*)

您可能需要单独处理y* = 0 x* = 0的情况,因为这意味着两个向量指向完全相反的方向(那么应该是什么'平均'是?)。

答案 1 :(得分:0)

这取决于“平均”的含义。但正常的定义是包含锐角的平分线。你必须将两者放在180度之内。有很多方法可以做到这一点,但一个简单的方法是增加或减少其中一个角度。如果角度为ab,则可以执行此操作:

if (a < b)
  while (abs(a - b) > 180) a = a + 360
else
  while (abs(a - b) > 180) a = a - 360

现在您可以计算简单平均值:

avg = (a + b) / 2

当然,您可能希望再次标准化:

while (avg < 0) avg  = avg + 360
while (avg >= 360) avg = avg - 360

在你的例子中,你有一个= 0,b = 359。第一个循环将a增加到360.平均值将是359.5。当然,如果你愿意,你可以将它舍入为整数。如果你向上舍入到360,那么最后一组循环将减少到0。

请注意,如果您的角度始终标准化为[0..360],则这些循环中的任何一个都不会执行多次。但它们可能是一种很好的做法,因此狂野的争论不会导致代码失败。

答案 2 :(得分:0)

您想要平分角度而不是平均角度。首先得到它们之间的距离,以最短的方式,然后将其分成两半并添加到其中一个角度。例如:

A = 355
B = 5

if (abs(A - B) < 180) {
    Distance = abs(A - B)
    if (A < B) {
        Bisect = A + Distance / 2
    }
    else {
        Bisect = B + Distance / 2
    }
}
else {
    Distance = 360 - abs(A - B)
    if (A < B) {
        Bisect = A - Distance / 2
    }
    else {
        Bisect = B - Distance / 2
    }
}

或类似的东西 - 对于给定的输入,“Bisect”应该为零。有很多聪明的方法可以使用更少的if和abs操作来实现算法。

答案 3 :(得分:0)

在评论中,你提到要平均的所有“角度”都在90度之内。我猜测实际上只有一台摄像机,但它会移动很多,而且你正在为摄像机POV创建一些图像稳定机制。

在任何情况下,只有特殊情况下相机可能位于270-​​359象限和0-89象限。对于所有其他情况,您可以采取简单的平均值。因此,您只需要检测特殊情况,当它发生时,将270-359象限中的角度视为-90到-1。然后,在计算简单平均值后,如有必要,将其调整回270-359象限。

在C代码中:

int quadrant (int a) {
    assert(0 <= a && a < 360);
    return a/90;
}

double avg_rays (int rays[], int num) {
    int i;
    int quads[4] = { 0, 0, 0, 0 };
    double sum = 0;
    /* trivial case */
    if (num == 1) return rays[0];
    for (i = 0; i < num; ++i) ++quads[quadrant(rays[i])];
    if (quads[0] == 0 || quads[3] == 0) {
        /* simple case */
        for (i = 0; i < num; ++i) sum += rays[i];
        return sum/num;
    }
    /* special case */
    for (i = 0; i < num; ++i) {
        if (quadrant(rays[i]) == 3) rays[i] -= 360;
        sum += rays[i];
    }
    return sum/num + (sum < 0) * 360;
}

此代码可以在明确目的的情况下进行优化。当您检测到特殊情况时,您可以在事后确定sum。因此,您可以计算sum并找出特殊情况,并在一次通过中进行修复。

double avg_rays_opt (int rays[], int num) {
    int i;
    int quads[4] = { 0, 0, 0, 0 };
    double sum = 0;
    /* trivial case */
    if (num == 1) return rays[0];
    for (i = 0; i < num; ++i) {
        ++quads[quadrant(rays[i])];
        sum += rays[i];
    }
    if (quads[0] == 0 || quads[3] == 0) {
        /* simple case */
        return sum/num;
    }
    /* special case */
    sum -= quads[3]*360;
    return sum/num + (sum < 0) * 360;
}

我确信它可以进一步优化,但它应该给你一个开始。