Что такое формула для получения вектора, перпендикулярного другому вектору?

Какова формула для получения трехмерного вектора B, лежащего на плоскости, перпендикулярной вектору A?

То есть, для вектора A, какова формула f(угол, модуль), которая дает вектор, перпендикулярный к A, с указанным модулем и повернутый на угол?

6 ответов

Решение

Если два вектора перпендикулярны, то их скалярное произведение равно нулю.

Так: 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 - трехмерный вектор произвольного числового типа.

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)));
}

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.

Один из способов - найти преобразование вращения от положительной оси 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: Матрица вращения от оси и угла

Другим методом будет использование кватернионного вращения. Это немного больше, чтобы обернуть голову, но меньше цифр, чтобы отслеживать.

Другие вопросы по тегам