获得位于垂直于向量 A 的平面上的三维向量 B 的公式是什么?
也就是说,给定一个向量 A,公式 f(angle,modulus) 是什么,它给出了一个垂直于 A 的向量,具有所述模数并旋转了一个角度?
如果两个向量垂直,则它们的点积为零。
所以:v1(x1, y1, z1), v2(x2, y2, z2)
。
=> x1 * x2 + y1 * y2 + z1 * z2 = 0
你知道(x1, y1, z1)
。放任意x2
andy2
你会收到相应的z2
:
z1 * z2 = -x1 * x2 - y1 * y2
=> z2 = (-x1 * x2 - y1 * y2) / z1
请注意,如果z1
是0
。然后你在飞机上。
function (a,b,c)
{
return (-b,a,0)
}
但是当 a,b 接近 0 时,这个答案在数值上不稳定。
为避免这种情况,请使用:
function (a,b,c)
{
return c<a ? (b,-a,0) : (0,-c,b)
}
上面的答案是数值稳定的,因为如果c < a
then max(a,b) = max(a,b,c)
、 thenvector(b,-a,0).length() > max(a,b) = max(a,b,c)
和 sincemax(a,b,c)
不应该接近于零,那么向量也是如此。c > a
情况类似。
计算与另一个不共线的向量的叉积 。AxC
C
A
在垂直于 的平面上有许多可能的方向A
。如果您真的不在乎,选择哪一个,只需创建一个C
与 不共线的任意向量A
:
if (A2 != 0 || A3 != 0)
C = (1, 0, 0);
else
C = (0, 1, 0);
B = A x C;
我相信这应该产生一个垂直于给定向量的任意向量,vec
同时无论角度如何vec
(假设 的大小vec
不接近零)都保持数值稳定。假设 Vec3D 是一个任意数值类型的三维向量。
Vec3D arbitrary_orthogonal(Vec3D vec)
{
bool b0 = (vec[0] < vec[1]) && (vec[0] < vec[2]);
bool b1 = (vec[1] <= vec[0]) && (vec[1] < vec[2]);
bool b2 = (vec[2] <= vec[0]) && (vec[2] <= vec[1]);
return cross(vec, Vec3D(int(b0), int(b1), int(b2)));
}
非正式解释
恰好 1 个并且只有 1 个布尔值被设置;bN
如果维度N
的大小严格小于所有后续维度且不大于所有先前维度,则设置。然后,我们有一个具有单个非零维度的单位向量,该维度对应于 中的最小量值维度vec
。this 的叉积与叉积的定义vec
正交vec
。现在考虑只有当两个向量非常接近时,叉积在数值上是不稳定的。考虑我们的单位向量仅在一个维度上很大,并且该维度对应vec
于较小的维度。因此,它保证松散正交于vec
vec
在取叉积之前,在所有维度相等的情况下正交性最小。在这种最小正交的情况下,我们仍然是完全正交的,因为我们的单位向量除了一维 0外,其他所有维度vec
都相等。因此,我们避免了取两个几乎对齐的向量的叉积的不稳定情况。
一种方法是找到从正 z 轴(或任何其他轴)到给定向量的旋转变换。然后<modulus * cos(angle), modulus * sin(angle), 0>
使用此变换进行变换。
def getPerpendicular(v1,modulus,angle):
v2 = vector(0,0,1)
v1_len = v2.length()
axis = v1.cross_product(v2)
sinAngle = axis.length() / v1_len # |u x v| = |u| * |v| * sin(angle)
cosAngle = v1.dot_product(v2) / v1_len # u . v = |u| * |v| * cos(angle)
axis = axis.normalize()
# atan2(sin(a), cos(a)) = a, -pi < a < pi
angle = math.atan2(sinAngle, cosAngle)
rotationMatrix = fromAxisAngle(axis, angle)
# perpendicular to v2
v3 = vector(modulus*cos(angle),modulus*sin(angle),0)
return rotationMatrix.multiply(v3);
要计算旋转矩阵,请参阅这篇文章:WP: Rotation matrix from axis and angle
另一种方法是使用四元数旋转。绕着你的脑袋要多一点,但要跟踪的数字要少一些。
q4w56 几乎可以提供强大的解决方案。问题: 1) 不考虑帐户缩放。2)不应该比较两个变量之间的大小。
scale = |x| + |y| + |z|
if scale == 0:
return (0,0,0)
x = x/scale
y = y/scale
z = z/scale
if |x| > |y|:
return (z, 0,-x)
else:
return (0, z,-y)
在处理非常大或非常小的数字时,缩放很重要。另外,一般来说,你最好对 0 到 1 之间的值进行浮点运算。