如何检查向量是否面向相同的方向
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何检查向量是否面向相同的方向相关的知识,希望对你有一定的参考价值。
我正在研究一个问题,我在一个右手坐标系中工作,其中y轴是直线上升的。我提供了一个表示三维向量的结构,如下所示:
struct vec{float x; float y; float z; };
我需要编写一个函数,它接受一个代表北方的单位向量,一个单位向量代表一个玩家的前向向量,如果它们面向的是北方而不是南方,则返回。不幸的是我不知道从哪里开始,我相信我必须这样做:
PlayerDirection = sqrt((PlayerVector.x *= PlayerVector.x)
+ (PlayerVector.y *= PlayerVector.y)
+ (PlayerVector.z *= PlayerVector.z));
但我不知道从哪里开始。任何帮助/解释都会有所帮助,谢谢。
将点积应用于两个向量。如果两个矢量之间的角度小于90度,则点积为正,否则为负。
您包含的公式(包含错误 - 产品为“*”,而不是“* =”)为您提供移动的实体 - 向量的长度。您已经知道,因为它是一个单位向量,因此长度为1。
您需要在两个向量之间执行dot product。如果两个单位向量完全对齐(平行),则得1;如果它们是反平行的,则得-1,如果它们彼此正常,则得0。
“北越南”意味着标量积为正,因此:
如果他们面向北方而不是南方则返回
Alignment = ((PlayerVector.x * NorthVector.x)
+ (PlayerVector.y * NorthVector.y)
+ (PlayerVector.z * NorthVector.z));
return (Alignment > 0);
Questions
如果我想知道它是否面向东/西?
点积告诉您两个向量对齐了多少。它与Kevin Glasson所示的公式相同,没有单位向量范数,因为它们是1,除以1不会改变任何东西。
所以,除了另一个向量之外,你不能用它来判断向量面向的位置。这就是你被赋予北向量的原因;单独使用播放器矢量,您无法运行点积。要判断玩家是否面向东方,您需要东向量(或西向量,然后采用相反的符号)。
所以,如果数字以35表示回来,则意味着它面向北方而不是南方,但为什么呢?
为什么会这样:你可以在维基百科页面上找到它解释,点积等于两个长度乘以它们角度的余弦的乘积。由于长度均为1,因此它只是余弦。余弦在1和-1之间变化(所以你不能得到35)。当余弦为1时,意味着角度为零,矢量对齐;当它是-1时,它们是相反的。零的余弦意味着矢量彼此正常,即形成90°的角度,在这种情况下,它意味着玩家面向东方,西方,或向上或向下 - 但它不会告诉你哪一个。
我认为可行的是采用向量的'dot product'。使用以下表格:
你将在哪里重新安排theta。这将为您提供两个向量之间的角度。
在我看来,至少如果角度是0那么你指向的是北方,如果角度大于90,那么你面向更南方。
我不知道你打算如何使用它,但这应该能够在3D空间中从南方告诉北方。
那么你可以使用点积来获得2个向量之间的角度。公式如下:
cos(phi) = (a * b) / (|a|*|b|)
哪个转换为:
phi = acos((ax*bx + ay*by + az * bz) / (sqrt(ax^2 + ay^2 + az^2)+sqrt(bx^2 + by^2 + bz^2)))
现在点积是对称的,意思是:(1,1,1)(2,2,2)给出与(2,2,2)(1,1,1)相同的结果。因此,您必须再添加一步。通过添加第三个向量,其角度与您知道的第一个给定向量,您可以验证两个向量之间的真实角度。选择该参考矢量可以通过将第一个矢量绕一个轴来完成,现在为了确保它是一个有效的参考,它必须与矢量a和b在同一平面上。这意味着转动第一个矢量arround的轴必须与矢量1和2正交,2个矢量的矢量产生一个与两者正交的矢量,因此我们将使用如此获得的矢量作为轴。
axis = a x b
这相当于:
axis = (aybz-azby, azbx-axbz, axby-aybx)
要围绕轴将矢量旋转给定量,必须执行以下操作:
double R[3][3] = {};
Vector axis = Axis.getUnitVector();
double deg = degrees / 180 * M_PI;
R[0][0] = axis.X * axis.X * (1 - cos(deg)) + cos(deg); R[0][1] = axis.X * axis.Y * (1 - cos(deg)) - axis.Z * sin(deg); R[0][2] = axis.X * axis.Z * (1 - cos(deg)) + axis.Y * sin(deg);
R[1][0] = axis.Y * axis.X * (1 - cos(deg)) + axis.Z * sin(deg); R[1][1] = axis.Y * axis.Y * (1 - cos(deg)) + cos(deg); R[1][2] = axis.Y * axis.Z * (1 - cos(deg)) - axis.X * sin(deg);
R[2][0] = axis.Z * axis.X * (1 - cos(deg)) - axis.Y * sin(deg); R[2][1] = axis.Z * axis.Y * (1 - cos(deg)) + axis.X * sin(deg); R[2][2] = axis.Z * axis.Z * (1 - cos(deg)) + cos(deg);
double x = this->X * R[0][0] + this->Y * R[0][1] + this->Z * R[0][2];
double y = this->X * R[1][0] + this->Y * R[1][1] + this->Z * R[1][2];
double z = this->X * R[2][0] + this->Y * R[2][1] + this->Z * R[2][2];
unitvector定义如下:
e_a = (ax / sqrt(ax^2+ay^2+az^2),ay / sqrt(ax^2+ay^2+az^2),az / sqrt(ax^2+ay^2+az^2))
使用这个新轴,我们可以将第一个矢量旋转90°。通过计算我们的参考和第二个矢量之间的角度,我们现在可以评估第一个和第二个矢量之间的实际角度。如果与参考的角度大于90°,则第二个矢量位于第3或第4个扇区或笛卡尔坐标系中,意味着要获得真实角度,我们必须从第一个和第二个矢量之间减去我们获取的角度360°。如果与参考的角度小于90°,则计算的角度是实际角度。
现在还有另一个问题,北方是什么/哪里?如果我们知道北方,我们可以计算出北方和两个向量之间的角度,而角度较小的那个将更加北方。这意味着没有理由评估参考向量或构建并应用旋转矩阵。
如果是固定的北方,您还可以将矢量投影到包含北方的平面上,并简化所需的计算。提供更多信息,我将对此进行编辑。
编辑:/因为你提供了北方和一个玩家矢量,只需计算它们之间的角度。
以上是关于如何检查向量是否面向相同的方向的主要内容,如果未能解决你的问题,请参考以下文章