我正在开发一个涉及在游戏中获取相机角度的应用程序。角度可以是0-359。 0是North,90是East,180是South等。我正在使用API,它在Camera类中有一个getAngle()方法。
如何找到不同摄像机角度之间的平均值。实际平均值0和359是179.5。作为摄像机角度,这将是南方,但显然0和359都非常接近北方。
答案 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度之内。有很多方法可以做到这一点,但一个简单的方法是增加或减少其中一个角度。如果角度为a
和b
,则可以执行此操作:
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;
}
我确信它可以进一步优化,但它应该给你一个开始。