web-dev-qa-db-ja.com

ベクトルを別のベクトルに垂直にするための式は何ですか?

ベクトルAに垂直な平面上にある3次元ベクトルBを取得する式は何ですか?

つまり、ベクトルAが与えられた場合、Aに垂直なベクトルを与える式f(angle、modulus)とは何ですか?

8
MaiaVictor

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

z10。その後、あなたは飛行機にいます。

12
Petar Minchev
_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_の場合も同様です。

9
golopot

クロス積AxCを、Cと同一線上にない別のベクトルAを使用して計算します。

Aに垂直な平面には多くの可能な方向があります。どれを選択しても構わない場合は、Cと同一直線上にない任意のベクトルAを作成するだけです。

if (A2 != 0 || A3 != 0)
    C = (1, 0, 0);
else
    C = (0, 1, 0);
B = A x C; 
7
Henrik

これにより、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であるのに対し、vecquite直交のままですすべて等しい。したがって、2つのほぼ整列したベクトルの外積を取るという不安定なケースを回避します。

2
sircolinton

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
lessthanoptimal

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:軸と角度からの回転行列

別の方法は、 四元数回転 を使用することです。頭を包むのはもう少しですが、追跡する数は少なくなります。

1
Markus Jarderot