사원수의 기본적인 형태
q = [ w, xi, yj, zk ]
- w : scalar
- xi, yj, zk : 허수로 표현된 벡터
스칼라를 제외한 허수들은 벡터를 난타낸다. 그러므로 아래처럼 간략하게 나타내기도 한다
q = [ w, v ]
단위 사원수
q = [ 1, 0, 0, 0 ]
단위 사원수의 경우, 절대값(크기)이 1이다.
|| q || = sqrt(w^2 + x^2 + y^2 + z^2) = 1, w^2 + x^2 + y^2 + z^2 = 1
사원수 크기 ( Length, Norm)
|| q || = Norm(q) = sqrt(w^2 + x^2 + y^2 + z^2)
정규화(단위사원수 생성) : 사원수의 크기로 사원수를 나눈다
q = q / || q || = q / sqrt(w^2 + x^2 + y^2 + z^2)
켤레 사원수
[ w, xi, yj, zk ]의 켤레 사원수는 [ w, -xi, -yj, -zk ]
사원수의 역수
사원수 q의 역수 = (켤레 사원수) / || q ||^2, 그러므로 크기가 1인 경우, 역수=켤레사원수
단위 사원수의 역수 = 켤레 사원수 (단위사원수는 크기가 1이므로 )
회전을 위한 사원수(회전축, 회전량을 표현함)
q = [ cos(θ/2), xsin(θ/2), ysin(θ/2), zsin(θ/2) ] = [ cos(θ/2), v*(θ/2) ]
- x, y, z : 회원축을 나타내는 단위벡터(v)
- θ : 회전량(Radian)
- 이렇게 설정했을 때 단위 사원수가 됨
점(벡터) 회전을 위한 곱셈
q´ = q v q-1, (v = [0, v])
q' : 벡터 v가 회전변환된 결과 벡터를 포함한 사원수
q : 회전을 위한 사원수(회전축과 회전량 포함)
v : 회전 대상 점(벡터)을 사원수 형식으로 표현 ( v = [0, v] ), 일반벡터 앞에 0을 추가한 것
q-1 : 사원수 q의 역수(단위 사원수의 역수는 켤레 사원수와 같다)
사원수의 곱셈규칙
q1=(w1, x1, y1, z1); q2=(w2, x2, y2, z2);
위의 각 사원수에서 벡터부를 아래처럼 표현할 수 있다
v1 = (x1, y1, z1), v2 = ( x2, y2, z2 )
q1 * q2 = ( w1*w2 - v1.Dot(v2), v2*w1 + v1*w2 + v1.Cross(v2 ) )
위의 식을 가감승제로만 표현하면 다음과 같다
w = w1w2 - x1x2 - y1y2 - z1z2
x = w1x2 + x1w2 + y1z2 - z1y2
y = w1y2 + y1w2 + z1x2 - x1z2
z = w1z2 + z1w2 + x1y2 - y1x2
참고 : 벡터의 외적(Cross Products)
사원수 나눗셈 규칙
https://kr.mathworks.com/help/aeroblks/quaterniondivision.html
The Quaternion Division block divides a given quaternion by another.
The quaternions have the form of
q=q0+iq1+jq2+kq3
and
r=r0+ir1+jr2+kr3.
The resulting quaternion from the division has the form of
t=qr=t0+it1+jt2+kt3,
사원수를 이용하여 공간상의 특정 점(벡터)을 회전하는 예
#include <iostream>
#include <cmath>
using namespace std;
struct Vector
{
float x, y, z;
Vector() {}
Vector(float x, float y, float z) :x(x), y(y), z(z) {}
/* Dot Product
v = [x, y, z]
v'= [x',y',z']
Dot(v) = xx' + yy' + zz'
*/
float Dot(const Vector& v2) const {
return x * v2.x + y * v2.y + z * v2.z;
}
/* Cross Product
v = [x, y, z]
v'= [x',y',z']
v x v' = [yz'-zy', zx'-xz', xy'-yx']
*/
Vector Cross(const Vector& v2) const {
return Vector(
y*v2.z - z * v2.y,
z*v2.x - x * v2.z,
x*v2.y - y * v2.x);
}
Vector operator*(float scalar) const {
return Vector(x*scalar, y*scalar, z*scalar);
}
Vector operator+(const Vector& v2) const {
return Vector(x + v2.x, y + v2.y, z + v2.z);
}
float length() {
return sqrt(x*x + y * y + z * z);
}
};
struct Quaternion
{
float w;
Vector v;
Quaternion() {}
Quaternion(float w, float x, float y, float z)
:w(w), v(Vector(x, y, z)) {}
Quaternion(const Vector& n, float a)
{
a = 3.14159F / 180.0F * a;
w = cos(a / 2);
v.x = n.x*sin(a / 2);
v.y = n.y*sin(a / 2);
v.z = n.z*sin(a / 2);
}
Quaternion(float w, Vector v) : w(w), v(v) {}
/*
q1 * q2 = (w1,v1) * (w2,v2) =
( w1w2-v1.Dot(v2), w1v2 + w2v1 + v1.Cross(v2) )
*/
Quaternion operator*(const Quaternion& q) const {
Quaternion r;
r.w = w * q.w - v.Dot(q.v);
r.v = q.v*w + v * q.w + v.Cross(q.v);
return r;
}
const Vector rotate(const Vector& V) const {
Quaternion p;
p.w = 0;
p.v = V;
const Quaternion& q = (*this);
return (q * p * q.Invert()).v;
}
Quaternion Invert() const {
//단위 쿼터니언의 역수는 켤레 사원수와 같으므로
return Quaternion(w, Vector(-v.x, -v.y, -v.z));
}
float magnitude() {
return sqrt(w*w + v.x*v.x + v.y*v.y + v.z*v.z);
}
};
int main()
{
//Quaternion(사원수)
Quaternion q1(Vector(1, 0, 0), 90);
Quaternion q2(Vector(0, 1, 0), 90);
Quaternion q3 = q1 * q2;
cout << "w:" << q2.w << ", x:" << q2.v.x << ", y" << q2.v.y << ", z:" << q2.v.z << endl;
cout << "크기:" << q2.magnitude() << endl;
Vector v1(0, 0, 1);
Vector v2 = q1.rotate(v1); //x축 중심 90도 회전
cout << "v2, x:" << v2.x << ", y:" << v2.y << ", z:" << v2.z << endl; // y:-1
cout << "v2 결과벡터 크기:" << v2.length() << endl; // 1
Vector v3 = q2.rotate(v1); //y축 중심 90도 회전
cout << "v3, x:" << v3.x << ", y:" << v3.y << ", z:" << v3.z << endl; // x:1
cout << "v3 결과벡터 크기:" << v3.length() << endl; // 1
/*
Quaternion q(Vector(1, 0, 0), 90);
cout << "크기:" << q.magnitude() << endl; //1
*/
return 0;
}
위의 코드를 실행하면 다음과 같은 결과를 볼 수 있다
w:0.707107, x:0, y0.707106, z:0 크기:1 v2, x:0, y:-1, z:1.19209e-06 v2 결과벡터 크기:1 v3, x:1, y:0, z:1.19209e-06 v3 결과벡터 크기:1 |