2

我正在尝试优化实验中的模拟功能,这样我就可以一次运行更多的人工大脑控制代理。我分析了我的代码,发现我的代码现在的最大瓶颈是计算每个代理到每个代理的相对角度,即 O(n 2 ),减去我所做的一些小的优化。这是我用于计算角度的当前代码片段:

[C++]
double calcAngle(double fromX, double fromY, double fromAngle, double toX, double toY)
{
    double d = 0.0;
    double Ux = 0.0, Uy = 0.0, Vx = 0.0, Vy = 0.0;

    d = sqrt( calcDistanceSquared(fromX, fromY, toX, toY) );

    Ux = (toX - fromX) / d;

    Uy = (toY - fromY) / d;

    Vx = cos(fromAngle * (cPI / 180.0));
    Vy = sin(fromAngle * (cPI / 180.0));

    return atan2(((Ux * Vy) - (Uy * Vx)), ((Ux * Vx) + (Uy * Vy))) * 180.0 / cPI;
}

我有两个 2D 点 (x 1 , y 1 ) 和 (x 2 , y 2 ) 以及“从”点 (x a )的朝向。我想计算代理 x 需要转向(相对于其当前面向)面对代理 y 的角度。

根据分析器,最昂贵的部分是atan2。我已经用谷歌搜索了几个小时,上面的解决方案是我能找到的最好的解决方案。有谁知道计算两点之间角度的更有效方法?如果这会影响任何事情,我愿意为速度牺牲一点精度(+/- 1-2 度)。

4

5 回答 5

6

正如评论中提到的,可能有一些高级方法可以减少您的计算负载。

但是对于手头的问题,您可以只使用点积关系

theta = acos ( a . b / ||a|| ||b|| )

其中ab是您的向量,.表示“点积”并|| ||表示“向量幅度”。

本质上,这会将您的 { sqrt, cos, sin, atan2} 替换为 { sqrt, acos}。

我还建议在所有内部计算中坚持使用弧度,仅在人类可读 I/O 的角度之间进行转换。

于 2012-06-10T18:17:53.930 回答
1

您的评论说明了很多:“我正在为每个代理模拟 180 度的正面视网膜,所以我需要角度”。不,你没有。您只需要知道位置向量和视觉向量之间的角度是大于还是小于 90 度。

A·B简单:如果 A 和 B 之间的角度小于 90 度,则点积> 0;如果角度正好是 90 度,则为 0,如果角度大于 90 度,则 <0。计算这个需要 3 次乘法和 2 次加法。

于 2012-06-11T09:10:15.007 回答
0

我认为这更像是一个数学问题:

尝试

abs(arctan((y1-yfrom)/(x1-xfrom)) - arctan(1/((y2-yfrom2)/(x2-xfrom2))))

于 2012-06-10T18:17:52.073 回答
0

使用这两个向量的点积,最坏的情况是你需要做一个反余弦:

A = 面对方向。B = 代理 Y 从代理 X 的方向

计算点是简单的乘法和加法。从那里你有角度的余弦。

于 2012-06-10T18:22:37.447 回答
0

对于初学者,您应该意识到有一些简化可以稍微减少计算:

  1. 您无需计算从代理到自身的角度,
  2. 如果您有从代理 i 到代理 j 的角度,那么您已经知道从代理 j 回到代理 i 的角度。

我不得不问:“agent i 转向面对 agent j”是什么意思?如果两个表面彼此正对,您是否需要进行计算?你对“直视对方”有什么容忍度?

如果您不再专注于数学并更全面地描述问题,那么建议做什么会更容易。

于 2012-06-10T18:59:37.080 回答