【问题标题】:How to determine if a vector is between two other vectors?如何确定一个向量是否在其他两个向量之间?
【发布时间】:2012-11-18 10:05:56
【问题描述】:

我正在寻找一种快速有效的方法来确定向量 B 是否介于向量 A 和向量 C 的小角度之间。通常我会使用垂直点积来确定每条线 B 的哪一边位于但在此case 不是那么简单,原因如下:

  • 没有一个向量可以被认为是标准化的,标准化它们是我希望避免的额外步骤。
  • 我不清楚哪一边是最小的角度,所以很难说哪一边是好的。
  • A 和 B 可能共线或正好相隔 180 度,在这种情况下我想返回 false。
  • 当我在 3D 环境中工作时,我很容易将其简化为 2D,如果这样可以让事情变得更容易,更重要的是更快。此测试将用于需要尽可能快地运行的算法。

如果有一些简单有效的方法来确定我的垂直向量应该指向哪个方向,我可以使用这两个点积进行测试。

到目前为止,我一直在考虑但没有取得多大成功的另一种方法是使用矩阵。理论上,根据我对矩阵变换的理解,我应该能够使用 A 和 C 作为基向量。然后将 B 乘以矩阵 I 应该能够通过 X 和 Y 是否都为正来测试 B 所在的象限。如果我能让这种方法发挥作用,它可能是最好的,因为一个矩阵乘法应该比两个点积更快,而且我不必担心哪一边的角度最小。

问题出在我的测试中,我不能简单地使用 A 和 C 作为基础并将其正常相乘并获得正确的行为。我真的不确定我在这里做错了什么。我已经多次遇到“向量空间”这个术语,据我所知,它似乎是一个与矩阵变换非常相似的概念,不需要正交基或正交基。它和矩阵一样吗?如果没有,是否有更好的方法,我将如何使用它?

只是为了更直观地解释我在说什么:

@Aki Suihkonen 我似乎无法让它工作。编写了一个我可以运行的模拟案例,看看我是否无法弄清楚

对于这种情况使用

斧头 2.9579773 斧头 3.315979

Cx 2.5879822 Cy 5.1630249

对于 B,我围绕四个象限旋转,向量将空间划分为。

我得到的迹象: - 第一季度-- - 第二季度+- - 第三季度+- - 第四季度--

假设我在环境中以与图像相同的方向旋转,我很确定我做了。

【问题讨论】:

  • 您为此使用什么语言/环境?优化始终取决于上下文。
  • 你为什么不尝试用高斯方法求解向量方程xA+yC=B?如果解决方案存在,正 x 和 y 都表示 B 位于 A 和 C 之间。
  • 我正在使用 C++,但我目前对数学上的优化很感兴趣。
  • 如果要旋转 A,[B],C 使 B 面向“上”即 y>0, x=0,则条件为 sign(Ax)!=sign(Cx) .无论如何,“中间”的含义有一些主观性(例如,如果三个向量只是任意的,并且 a 和 c 都面向 b 的“后向”。(认为粗体黑线是 A 和 C 以及向量 B指向“q3”。)它在中间吗?公式说是。另一个额外的标准是,当 A 和 C 旋转 B 时,A 和 C 的 x 符号也必须为正。(和 y 符号必须不同)

标签: math vector matrix


【解决方案1】:

考虑这一点的一种方法是将所有这些向量 A、B、C 视为复数。

将A、C全部与B*相乘,B*是B的复共轭,两个结果向量都将在复平面上旋转,使得参考轴(B*Conj(B))现在是实轴(或 y = 0)——不需要计算该轴。在这种情况下,只需检查“y”或虚数的符号是​​否不同。同样在这种情况下,两个结果向量都被缩放了相同的长度 |B|。

`return sign(Imag(A * Conj(B))) != sign(Imag(C * Conj(B)));`

A = ax + i * ay; B = bx + i * by; C = cx + i * cy;
Conj(B) = bx - i * by; 
A * B = (ax * bx - ay * by) + i * (ax * by + ay * bx);

我认为这个等式会带来更好的性能,因为只需要乘法的虚部。

作为一个完整的解决方案,这转换为:

return (ay * bx - ax * by) * (ay * cx - ax * cy) < 0;

中间的乘法是以下的捷径:

return Sign(ay * bx - ax * by) != Sign(ay * cx - ax * cy);

没有复数,这个问题也可以看成向量 B 是 { Rcos beta, Rsin beta },可以表示为一个旋转矩阵。

R*[  cb -sb ]    [ bx -by ],   cb = cos(beta), sb = sin(beta)
  [  sb  cb ] =  [ by  bx ]    cos(-beta) = cos(beta), sin(-beta) = -sin(beta)

将 [ax,ay], [cx,cy] 与缩放矩阵 [bx by, -by bx] 的 转置 相乘会影响 [ax, ay] * rotMatrix(- beta), [cx, cy] * rotMatrix(-beta) 完全相同。

【讨论】:

  • 投影不需要计算向量的大小吗?
  • 他们通常会。但正如我所看到的,等式的左侧乘以 |A|*|B|*|A|*|C|右边是|A|*|C|*|A|*|B|。
  • 乘法是正确的,因为如果 B 与 A 或 C 重合,则乘积为零。
  • 虚数和共轭从来都不是我的强项,所以我很难理解这一点。尽管如果将向量 B 设置为我们的坐标空间 Axis 之一,您确实给了我一个很好的主意,但问题变得非常简单。所以只需 2 次矩阵旋转,然后比较符号。我会玩一会儿。
【解决方案2】:

在极坐标中,您只会问是否 θAB C。所以先转换为极地:

a_theta = ax ? atan(ay / ax) : sign(ay) * pi

【讨论】:

  • 这与我的答案几乎相同的几何解释,顺便说一下自动处理零。
  • A 和 C 是可互换的,而不是按照从左到右定义和已知的顺序。这可以很容易地解决,尽管更大的问题是如果 B 反转,它看起来会返回 true。
  • 抱歉,我有一个更长的答案,但最初的近似值存在缺陷,所以我暂时删除了其余部分。总体思路是对单调递增的索引使用更便宜的等价物并进行比较。
【解决方案3】:

我认为 Aki 的解决方案很接近,但有些情况下它不起作用:

来自他的解决方案:

return (ay * bx - ax * by) * (ay * cx - ax * cy) < 0;

这相当于检查B和A之间的叉积是否与C和A之间的叉积具有相同的符号。

叉积 (U x V) 的符号告诉您 V 是位于 U 的一侧还是另一侧(板外,板内)。在大多数坐标系中,如果 U 需要逆时针旋转(在棋盘外),则符号为正。

因此,Aki 的解决方案检查 B 是否需要向一个方向旋转才能到达 A,而 C 是否需要向另一个方向旋转。如果是这种情况,则 B 不在 A 和 C 之内。当您不知道 A 和 C 的“顺序”时,此解决方案不起作用,如下所示:

要确定 B 是否在 A 和 C 内,您需要同时检查两种方式。即从A到B的旋转方向应与从A到C的旋转方向相同,从C到B的旋转方向应与从C到A的旋转方向相同。

这简化为:

if (AxB * AxC >= 0 && CxB * CxA >= 0)

// then B is definitely inside A and C

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-03
    • 1970-01-01
    • 1970-01-01
    • 2011-03-04
    • 1970-01-01
    • 2019-01-23
    • 2017-03-28
    相关资源
    最近更新 更多