Вопрос по math – Вычисление двух векторов, перпендикулярных третьему в 3D

5

Чтоbest (fastest) способ вычислить два вектора, которые перпендикулярны третьему вектору (X) и также перпендикулярны друг другу?

Вот как я сейчас вычисляю эти векторы:

// HELPER - unit vector that is NOT parallel to X
x_axis = normalize(X);
y_axis = crossProduct(x_axis, HELPER);
z_axis = crossProduct(x_axis, y_axis);

Я знаю, что существует бесконечное количество решений, и мне все равно, какое из них будет моим решением.

Что стоит за этим вопросом: мне нужно построить матрицу преобразования, где я знаю, в каком направлении должна указывать ось X (первый столбец в матрице). Мне нужно рассчитать оси Y и Z (второй и третий столбец). Как известно, все оси должны быть перпендикулярны друг другу.

Сделать любой из алгоритмовhere есть что нужно? Они касаются генерации y_axis надежным и эффективным способом. John McFarlane
Это почти такой же вопрос, как: [stackoverflow.com/questions/19649452/… с одним орто-вектором, просто скрестите произведение для получения второго. ideasman42

Ваш Ответ

5   ответов
3

X<>0 или жеY<>0 является

A = [-Y, X, 0] B = [-X*Z, -Y*Z, X*X+Y*Y]

а затем нормализовать векторы.

[ X,Y,Z]·[-Y,X,0] = -X*Y+Y*X = 0
[ X,Y,Z]·[-X*Z,-Y*Z,X*X+Y*Y] = -X*X*Z-Y*Y*Z+Z*(X*X+Y*Y) = 0
[-Y,X,0]·[-X*Z,-Y*Z,X*X+Y*Y] = Y*X*Z+X*Y*Z = 0

Это называетсяnullspace вашего вектора.

ЕслиX=0 а такжеY=0 затемA=[1,0,0], B=[0,1,0].

Пожалуйста, объясните "нестабильный". Можете ли вы привести (ненулевой) пример, если он потерпит неудачу?
И еще одно математически точное, но численно нестабильное вычисление.
Например, если X и Y различаются по своим величинам, возведение в квадрат их будет иметь тенденцию давать результаты, которые хотя и алгебраически верны, но не являются численно корректными. ИксX + YY уменьшается до Y * Y, когда Y достаточно велик по сравнению с X.
Вы можете подумать, что[ε,ε,1] случай терпит неудачу, но когда результаты нормализованы в последнем шаге, это работает правильно. Не используйте современные компьютеры с внутренними 80-разрядными числами с плавающей запятой, но в конце выведите только 32 или 64-разрядные.
Входной вектор нормализуется в соответствии с ОП, и поэтому наихудший случай будет[1, ε, 0] где & # x3B5; это точность машины. Результаты будут[-ε,1,0] а также[0,0,1] который до сих порnullspace, Я действительно не вижу твоей точки зрения здесь (в данном случае).
0

smallest absolute valueи использовать эту координатную ось:

absX = abs(X.x); absY = abs(X.y); absZ = abs(X.z);
if(absX < absY) {
  if(absZ < absX)
    HELPER = vector(0,0,1);
  else // absX <= absZ
    HELPER = vector(1,0,0);
} else { // absY <= absX
  if(absZ < absY)
    HELPER = vector(0,0,1);
  else // absY <= absZ
    HELPER = vector(0,1,0);
}

Примечание: это фактически очень похоже на ответ @ MBo: взятие перекрестного произведения с наименьшей осью координат эквивалентно установке наименьшей координаты равной нулю, замене больших двух и отрицанию одной.

0

что минимальный максимальный Magnatude из всех элементов в единичном векторе всегда больше, чем 0,577, поэтому вы можете обойтись без этого:

- & GT; Сократите проблему нахождения перпендикулярного вектора для трехмерного вектора до двумерного вектора, найдя любой элемент, магнитуда которого больше, чем, скажем, 0,5, затем игнорируйте другой элемент (используйте 0 на его месте) и примените перпендикуляр к формуле двухмерного вектора в остальные элементы (для 2D-оси x = (ax, ay) - & gt; y-axis = (- ay, ax))

let x-axis be represented by (ax,ay,az)

if (abs(ay) > 0.5) {
  y-axis = normalize((-ay,ax,0))
} else if (abs(az) > 0.5) {
  y-axis = normalize((0,-az,ay))
} else if (abs(ax) > 0.5) {
  y-axis = normalize((az,0,-ax))
} else {
  error("Imposs,ible unit vector")
}
3


Это также, вероятно,only способ сделать это. Любой другой способ будет математически эквивалентен.
Может быть возможно сэкономить несколько циклов, открыв вычисление кросс-продукта и убедившись, что вы не выполняете одни и те же умножения более одного раза, но это действительно далеко в область микрооптимизации.

Одна вещь, которую вы должны быть осторожны, это, конечно, вектор Хелпера. Он должен быть не только не параллельным X, но также хорошей идеей, что он будет ОЧЕНЬ не параллелен X. Если X и HELPER будут хотя бы несколько параллельными, ваши вычисления с плавающей запятой будут нестабильными и неточный. Вы можете проверить и посмотреть, что произойдет, если скалярное произведение X и HELPER будет примерно равно 0,9999.

Спасибо за ваш ответ. Да, HELPER далеко не параллелен X. Я разрабатываю для платформы Android, и я надеялся, что будет какой-то трюк для вычисления хотя бы первого параллельного вектора, несколько более дешевого. Я дам на этот вопрос некоторое время, и если лучшего ответа не будет, я приму его в качестве ответа. sidon
Нет. Это НЕ ЕДИНСТВЕННЫЙ способ сделать это, и при этом это не обязательно лучший способ, в зависимости от значения ПОМОЩИ.
2

ашим y_axis).

Пусть 's X = (ax, ay, az). Выберите 2 элемента с большей величиной, обменяйте их и отрицайте один из них. Установите в ноль третий элемент (с наименьшей величиной). Этот вектор перпендикулярен X.

Пример:

if (ax & lt; = ay) и (ax & lt; = az) тогда HELPER = (0, -az, ay) (или (0, az, -ay))

X * HELPER = 0 * 0 - ay * az + az * ay = 0

if (ay & lt; = ax) и (ay & lt; = az) тогда HELPER = (az, 0, -ay)

Похожие вопросы