ベクトルAに垂直な平面上にある3次元ベクトルBを取得する式は何ですか?
つまり、ベクトルAが与えられた場合、Aに垂直なベクトルを与える式f(angle、modulus)とは何ですか?
2つのベクトルが垂直である場合、それらの内積はゼロです。
したがって:v1(x1, y1, z1), v2(x2, y2, z2)
。
=> x1 * x2 + y1 * y2 + z1 * z2 = 0
ええと (x1, y1, z1)
。任意のx2
およびy2
と対応する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
_の場合はmax(a,b) = max(a,b,c)
、次にvector(b,-a,0).length() > max(a,b) = max(a,b,c)
であり、max(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が任意の数値型の3次元ベクトルであると仮定します。
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つだけ設定されます。 bN
は、次元N
の大きさが、後続のすべての次元より厳密に小さく、前のすべての次元より大きくない場合に設定されます。次に、vec
の最小の大きさの次元に対応する単一のゼロ以外の次元を持つ単位ベクトルがあります。これとvec
の外積は、外積の定義によってvec
に直交します。ここで、2つのベクトルが非常に密接に整列している場合にのみ、外積が数値的に不安定であると考えます。単位ベクトルが1次元でのみ大きく、その次元がvec
が小さい次元に対応していることを考慮してください。したがって、クロス積を取る前にvec
に緩やかに直交することが保証され、vec
のすべての次元が等しい場合、直交性は最小になります。この最小直交のケースでは、単位ベクトルが1次元を除いてすべて0であるのに対し、vec
はquite直交のままですすべて等しい。したがって、2つのほぼ整列したベクトルの外積を取るという不安定なケースを回避します。
q4w56は、堅牢なソリューションのためにほとんどあります。問題:1)アカウントのスケーリングを考慮しない。 2)必要なときに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の間の値で浮動小数点演算を行う方がよいでしょう。
1つの方法は、正の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:軸と角度からの回転行列
別の方法は、 四元数回転 を使用することです。頭を包むのはもう少しですが、追跡する数は少なくなります。