Эту проблему можно решить либо с помощью матрицы вращения, либо с помощью кватернионов, однако я бы предложил маршрут с матрицей вращения, потому что вы можете одновременно решить все точки с помощью одного матричного умножения.
Матрица вращения: если вы знаете, на какой угол Эйлера вы хотите повернуться, то Матрица вращения — это то, что нужно. Чтобы сформировать матрицу вращения, см. раздел «Основные вращения» по ссылке. Вместо того, чтобы знать, что такое «вверх», вам нужно знать, насколько сильно вы хотите повернуть свой объект. В этом случае (судя по предоставленным фотографиям) вы хотите повернуть на 90 градусов вокруг глобальной оси x (если вы хотите сделать это вокруг локальной оси, вы должны знать текущую ориентацию объекта. Я могу уточнить в редактировании, если вам нужны локальные повороты). Ваша глобальная матрица ротации будет выглядеть так:
[1 0 0]
[0 0 1]
[0 -1 0]
Я рассчитал это, используя матрицу Rx(90) в разделе «Основные вращения». Теперь сформируйте свои 3D-точки в векторах-столбцах. Допустим, одна точка находится в (0,0,1). Эта точка находится прямо там, где должен быть нос, поэтому мы ожидаем, что преобразованная точка будет (0,1,0). Просто умножьте матрицу вращения, чтобы получить результат:
[1 0 0] [0] [0]
[0 0 1]*[0]=[1]
[0 -1 0] [1] [0]
Обратите внимание, что в этом случае преобразование довольно тривиально; мы просто сдвигаем координаты (x остается прежним, y инвертируется, z и y меняются местами). Вы можете одновременно преобразовать большой набор точек, соединив по горизонтали все начальные координаты, чтобы сформировать матрицу 3xN, а затем умножив матрицу поворота влево. Например, преобразуем точки { (0,0,1), (0,1,0), (1,0,1), (0,0,-1)}:
[1 0 0] [0 0 1 0] [0 0 1 0]
[0 0 1]*[0 1 0 0]=[1 0 1 0]
[0 -1 0] [1 0 1 -1] [0 -1 0 1]
Напоминаем, что это преобразование вращается вокруг глобального начала координат (как показано точкой (1,0,1)). Вам нужно будет вычесть центроид ваших координат, повернуть, а затем добавить окончательные координаты перевода.
Кватернион: здесь я могу дать руководство, но это часто называют нотацией «ось-угол»; вы можете использовать его для создания матрицы вращения, которая будет поворачивать ваши точки вокруг произвольной единичной оси на заданный угол. Вот отличное руководство по этому вопросу. Дайте мне знать, если я должен уточнить в редактировании.
РЕДАКТИРОВАТЬ: в ответ на добавленный псевдокод
Если векторное произведение равно 0, то прямые параллельны. Ось вращения может быть ЛЮБЫМ вектором, перпендикулярным ЛЮБОМ входу (что делает его перпендикулярным обоим по определению). Вектор p определяется как перпендикулярный, если dot(v,p)==0 или vx*p.x+vy*p.y+vz*pz==0 и length(p)>0, поэтому мы можем произвольно выбрать любое решение, удовлетворяющее этим уравнениям.
v1 = vector(0,10,0)
v2 = vector(0,-10,0)
//Not necessary, since you will normalize the cross product result
//v1 = normalize(v1)
//v2 = normalize(v2)
cross = v2.cross(v1) // (0,0,0) and possible divide by 0 if normalized here
if(length(cross)==0){ //either "==0" or "<thresh" where thresh is some very small number
if(v.z!=0)
cross = vector(1,1,-(v1.x+v1.y)/v1.z);
else if(v.y!=0) //is z==0? well here's an identical solution as long as y isn't 0
cross = vector(1,-(v1.x+v1.z)/v.y,1);
else //by this point, v1.x must be the only nonzero remaining point, otherwise it's a null vector
cross = vector(-(v1.y+v1.z)/v.x,1,1);
}
cross=normalize(cross);
angle = acos( normalize(v2.dot(v1)) ) // 180
quat = quaternion(cross,angle)
Я не знаком с кодом Python, поэтому добавил эквивалент C++. Если бы кто-то мог отредактировать этот пост, чтобы исправить его, это было бы превосходно.
Редактировать: я не видел вашего комментария об acos, извините за это. Соответственно изменил код.
person
Suedocode
schedule
27.04.2013