3d數學基礎-映象矩陣和切變矩陣-用C++程式碼實現
阿新 • • 發佈:2019-01-01
#include <iostream.h>
#include <math.h>
#include <assert.h>
const float kPi = 3.1415926f;
const float k2Pi = kPi*2.0f;
const float kPiover2 = kPi/2.0f;
//數學工具,計算Sin, Cos. theta是角度
void sinCos(float* returnSin, float* returnCos, float theta)
{
*returnSin = sin(theta);
*returnCos = cos(theta);
}
//如果一個數很小,我們就把它置為0
float to_zero(float n)
{
return((abs(n)<0.00001)?0:n);
}
class Vector3
{
public:
double x, y, z; //在數學上的表示 [x,y,z] , 這裡的我們定義為成員變數
public:
Vector3(){}
Vector3(const Vector3& a) : x(a.x), y(a.y), z(a.z){}
Vector3(double a, double b, double c) : x(a), y(b), z(c){}
void zero() //設定為零向量
{
x = y = z = 0;
}
Vector3 operator-() const //負向量
{
return Vector3(-x, -y, -z);
}
Vector3 operator*(float a) const //標量必須在右邊
{
return Vector3(x*a, y*a, z*a);
}
Vector3 operator*=(float a) //標量必須在右邊
{
x*=a; y*=a; z*=a;
return *this;
}
Vector3 operator/(float a) const //標量必須在右邊
{
float oneOverA = 1.0f/a; //計算機中的除法速度比較慢
return Vector3(x*oneOverA, y*oneOverA, z*oneOverA); //目的是速度快一點
}
Vector3 operator/=(float a) //標量必須在右邊
{
float oneOverA = 1.0f/a;
x*=oneOverA; y*=oneOverA; z*=oneOverA;
return *this;
}
//向量的加法,兩個向量相加
Vector3 operator+(const Vector3& a) const
{
return Vector3(x+a.x, y+a.y, z+a.z);
}
//向量的減法,兩個向量相減
Vector3 operator-(const Vector3& a) const
{
return Vector3(x-a.x, y-a.y, z-a.z);
}
//向量的加法,另一種方式
Vector3 operator+=(const Vector3& a)
{
x+=a.x; y+=a.y; z+=a.z;
return *this;
}
//向量的減法,另一種方式
Vector3 operator-=(const Vector3& a)
{
x-=a.x; y-=a.y; z-=a.z;
return *this;
}
//向量的標準化操作,單位向量
void normalize()
{
float magSq = x*x + y*y + z*z;
if(magSq>0.0f)
{
float oneOverMag = 1.0f/sqrt(magSq);
x *= oneOverMag;
y *= oneOverMag;
z *= oneOverMag;
}
}
//點乘
float operator*(const Vector3& a) const
{
return x*a.x + y*a.y + z*a.z;
}
};
/*
如果將資料定義為私有,需要使用友元
public:
friend Matrix3x3& operator*(const Matrix3x3& a, const Matrix3x3& b);
friend Vector3& operator*(const Vector3&p, const Matrix3x3& m);
friend void print_m(Matrix3x3 m);
//叉乘
friend Vector3 crossProduct(const Vector3& a, const Vector3& b);
friend void print_v(Vector3 v);
friend double vectorMag(const Vector3& a);
friend Vector3 operator*(float k, const Vector3& v); //定義標量的左乘
friend float distance(const Vector3& a, const Vector3& b); //兩點之間的距離
*/
double vectorMag(const Vector3& a) //計算模
{
return sqrt(a.x*a.x + a.y*a.y + a.z*a.z);
}
void print_v(Vector3 v)
{
//由於這是float型,有時候會出現很小的數,如果數太小,我們就用0來代替
cout<<"["<<to_zero(v.x)<<", "<<to_zero(v.y)<<", "<<to_zero(v.z)<<"]"<<endl;
}
Vector3 operator*(float k, const Vector3& v)
{
return Vector3(k*v.x, k*v.y, k*v.z);
}
float distance(const Vector3& a, const Vector3& b)
{
//float dx = a.x - b.x;
//float dy = a.y - b.y;
//float dz = a.z - b.z;
//return sqrt(dx*dx + dy*dy + dz*dz);
//以上程式碼可以用一句代替
return vectorMag(a-b);
}
Vector3 crossProduct(const Vector3& a, const Vector3& b)
{
return Vector3
(
a.y*b.z - a.z*b.y,
a.z*b.x - a.x*b.z,
a.x*b.y - a.y*b.x
);
}
//一個3*3的旋轉矩陣,繞X軸旋轉,繞Y軸旋轉,繞Z軸旋轉
class Matrix3x3
{
public:
float m11, m12, m13;
float m21, m22, m23;
float m31, m32, m33;
//axis是1時,繞X軸旋轉。為2時,繞Y軸旋轉。為3時,繞Z軸旋轉
void setRotate(int axis, float theta)
{
float s, c;
sinCos(&s, &c, theta);
switch(axis)
{
case 1:
m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
m21 = 0.0f; m22 = c; m23 = s;
m31 = 0.0f; m32 = -s; m33 = c;
break;
case 2:
m11 = c; m12 = 0.0f; m13 = -s;
m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
m31 = s; m32 = 0.0f; m33 = c;
break;
case 3:
m11 = c; m12 = s; m13 = 0.0f;
m21 = -s; m22 = c; m23 = 0.0f;
m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
break;
default:
assert(false);
}
}
//縮放
void setupScale(const Vector3& s) //這裡的引數是一個向量,但我們沒有把它當作向量來用
{
m11 = s.x; m12 = 0.0f; m13 = 0.0f;
m21 = 0.0f; m22 = s.y; m23 = 0.0f;
m31 = 0.0f; m32 = 0.0f; m33 = s.z;
}
//投影
void setupProject(const Vector3& n) //這裡的這個向量和投影平面相垂直
{
assert(fabs(n*n - 1.0f)<0.01f); //確保這個向量是一個單位向量
m11 = 1.0f - n.x*n.x;
m22 = 1.0f - n.y*n.y;
m33 = 1.0f - n.z*n.z;
m12 = m21 = -n.x*n.y;
m13 = m31 = -n.x*n.z;
m23 = m32 = -n.y*n.z;
}
//映象 2d
void setupReflect(int axits) //指定座標軸
{
switch(axits)
{
case 1: //x座標發生映象,由正的變成負的
m11 = -1.0f; m12 = 0.0f; m13 = 0.0f;
m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
break;
case 2: //y座標發生映象,由正的變成負的
m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
m21 = 0.0f; m22 = -1.0f; m23 = 0.0f;
m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
break;
case 3: //z座標發生映象,由正的變成負的
m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
m31 = 0.0f; m32 = 0.0f; m33 = -1.0f;
break;
default:
assert(false);
}
}
//對3d空間的任意方向的一個映象平面來進行映象
void setupReflect(const Vector3& n)
{
assert(fabs(n*n - 1.0f)<0.01f); //確保這個向量是一個單位向量
float ax = -2.0f * n.x;
float ay = -2.0f * n.y;
float az = -2.0f * n.z;
m11 = 1.0f + ax*n.x;
m22 = 1.0f + ay*n.y;
m33 = 1.0f + az*n.z;
m12 = m21 = ax*n.y;
m13 = m31 = ax*n.z;
m23 = m32 = ay*n.z;
}
//切變
void setupShear(int axis, float s, float t)
{
switch(axis)
{
case 1: //用x去切變y,z,x不變
m11 = 1.0f; m12 = s; m13 = t;
m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
break;
case 2: //用y去切變z,z,y不變
m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
m21 = s; m22 = 1.0f; m23 = t;
m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
break;
case 3: //用z去切變x,y,z不變
m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
m31 = s; m32 = t; m33 = 1.0f;
break;
default:
assert(false);
}
}
};
//矩陣*矩陣
Matrix3x3& operator*(const Matrix3x3& a, const Matrix3x3& b)
{
Matrix3x3 r;
r.m11 = a.m11*b.m11 + a.m12*b.m21 + a.m13*b.m31;
r.m12 = a.m11*b.m12 + a.m12*b.m22 + a.m13*b.m32;
r.m13 = a.m11*b.m13 + a.m12*b.m23 + a.m13*b.m33;
r.m21 = a.m21*b.m11 + a.m22*b.m21 + a.m23*b.m31;
r.m22 = a.m21*b.m12 + a.m22*b.m22 + a.m23*b.m32;
r.m23 = a.m21*b.m13 + a.m22*b.m23 + a.m23*b.m33;
r.m31 = a.m31*b.m11 + a.m32*b.m21 + a.m33*b.m31;
r.m32 = a.m31*b.m12 + a.m32*b.m22 + a.m33*b.m32;
r.m33 = a.m31*b.m13 + a.m32*b.m23 + a.m33*b.m33;
return r;
}
//向量*矩陣
Vector3 operator*(const Vector3& p, const Matrix3x3& m)
{
return Vector3(
p.x*m.m11 + p.y*m.m21 + p.z*m.m31,
p.x*m.m12 + p.y*m.m22 + p.z*m.m32,
p.x*m.m13 + p.y*m.m23 + p.z*m.m33
);
}
//矩陣*矩陣的另一種方式
Matrix3x3& operator*=(Matrix3x3& a, const Matrix3x3& b)
{
a = a*b;
return a;
}
//向量*矩陣的另一種方式
Vector3 operator*=(Vector3& p, const Matrix3x3& m)
{
p = p*m;
return p;
}
//輸出一個矩陣
void print_m(Matrix3x3 m)
{
cout<<to_zero(m.m11)<<"\t"<<to_zero(m.m12)<<"\t"<<to_zero(m.m13)<<endl;
cout<<to_zero(m.m21)<<"\t"<<to_zero(m.m22)<<"\t"<<to_zero(m.m23)<<endl;
cout<<to_zero(m.m31)<<"\t"<<to_zero(m.m32)<<"\t"<<to_zero(m.m33)<<endl;
}
int main()
{
cout<<"hello, 線性變換 - 映象!--2d"<<endl;
Vector3 a(10, 20, 30), b;
Matrix3x3 M;
print_v(a);
M.setupReflect(1); //x軸座標發生變換
b = a*M;
print_v(b);
M.setupReflect(2); //y軸座標發生變換
b = a*M;
print_v(b);
M.setupReflect(3); //z軸座標發生變換
b = a*M;
print_v(b);
cout<<endl<<"hello, 線性變換 - 映象!--3d"<<endl;
Vector3 n(0,0,1); //這個向量是垂直與映象平面,垂直與xy平面,計算之後,z座標發生變換
M.setupReflect(n);
b = a*M;
print_v(b);
cout<<endl<<"hello, 線性變換 - 切變!"<<endl;
M.setupShear(1,1,2); //x不變,y和z會相應的增大
b = a*M;
print_v(b);
return 0;
}
#include <math.h>
#include <assert.h>
const float kPi = 3.1415926f;
const float k2Pi = kPi*2.0f;
const float kPiover2 = kPi/2.0f;
//數學工具,計算Sin, Cos. theta是角度
void sinCos(float* returnSin, float* returnCos, float theta)
{
*returnSin = sin(theta);
*returnCos = cos(theta);
}
//如果一個數很小,我們就把它置為0
float to_zero(float n)
{
return((abs(n)<0.00001)?0:n);
}
class Vector3
{
public:
double x, y, z; //在數學上的表示 [x,y,z] , 這裡的我們定義為成員變數
public:
Vector3(){}
Vector3(const Vector3& a) : x(a.x), y(a.y), z(a.z){}
Vector3(double a, double b, double c) : x(a), y(b), z(c){}
void zero() //設定為零向量
{
x = y = z = 0;
}
Vector3 operator-() const //負向量
{
return Vector3(-x, -y, -z);
}
Vector3 operator*(float a) const //標量必須在右邊
{
return Vector3(x*a, y*a, z*a);
}
Vector3 operator*=(float a) //標量必須在右邊
{
x*=a; y*=a; z*=a;
return *this;
}
Vector3 operator/(float a) const //標量必須在右邊
{
float oneOverA = 1.0f/a; //計算機中的除法速度比較慢
return Vector3(x*oneOverA, y*oneOverA, z*oneOverA); //目的是速度快一點
}
Vector3 operator/=(float a) //標量必須在右邊
{
float oneOverA = 1.0f/a;
x*=oneOverA; y*=oneOverA; z*=oneOverA;
return *this;
}
//向量的加法,兩個向量相加
Vector3 operator+(const Vector3& a) const
{
return Vector3(x+a.x, y+a.y, z+a.z);
}
//向量的減法,兩個向量相減
Vector3 operator-(const Vector3& a) const
{
return Vector3(x-a.x, y-a.y, z-a.z);
}
//向量的加法,另一種方式
Vector3 operator+=(const Vector3& a)
{
x+=a.x; y+=a.y; z+=a.z;
return *this;
}
//向量的減法,另一種方式
Vector3 operator-=(const Vector3& a)
{
x-=a.x; y-=a.y; z-=a.z;
return *this;
}
//向量的標準化操作,單位向量
void normalize()
{
float magSq = x*x + y*y + z*z;
if(magSq>0.0f)
{
float oneOverMag = 1.0f/sqrt(magSq);
x *= oneOverMag;
y *= oneOverMag;
z *= oneOverMag;
}
}
//點乘
float operator*(const Vector3& a) const
{
return x*a.x + y*a.y + z*a.z;
}
};
/*
如果將資料定義為私有,需要使用友元
public:
friend Matrix3x3& operator*(const Matrix3x3& a, const Matrix3x3& b);
friend Vector3& operator*(const Vector3&p, const Matrix3x3& m);
friend void print_m(Matrix3x3 m);
//叉乘
friend Vector3 crossProduct(const Vector3& a, const Vector3& b);
friend void print_v(Vector3 v);
friend double vectorMag(const Vector3& a);
friend Vector3 operator*(float k, const Vector3& v); //定義標量的左乘
friend float distance(const Vector3& a, const Vector3& b); //兩點之間的距離
*/
double vectorMag(const Vector3& a) //計算模
{
return sqrt(a.x*a.x + a.y*a.y + a.z*a.z);
}
void print_v(Vector3 v)
{
//由於這是float型,有時候會出現很小的數,如果數太小,我們就用0來代替
cout<<"["<<to_zero(v.x)<<", "<<to_zero(v.y)<<", "<<to_zero(v.z)<<"]"<<endl;
}
Vector3 operator*(float k, const Vector3& v)
{
return Vector3(k*v.x, k*v.y, k*v.z);
}
float distance(const Vector3& a, const Vector3& b)
{
//float dx = a.x - b.x;
//float dy = a.y - b.y;
//float dz = a.z - b.z;
//return sqrt(dx*dx + dy*dy + dz*dz);
//以上程式碼可以用一句代替
return vectorMag(a-b);
}
Vector3 crossProduct(const Vector3& a, const Vector3& b)
{
return Vector3
(
a.y*b.z - a.z*b.y,
a.z*b.x - a.x*b.z,
a.x*b.y - a.y*b.x
);
}
//一個3*3的旋轉矩陣,繞X軸旋轉,繞Y軸旋轉,繞Z軸旋轉
class Matrix3x3
{
public:
float m11, m12, m13;
float m21, m22, m23;
float m31, m32, m33;
//axis是1時,繞X軸旋轉。為2時,繞Y軸旋轉。為3時,繞Z軸旋轉
void setRotate(int axis, float theta)
{
float s, c;
sinCos(&s, &c, theta);
switch(axis)
{
case 1:
m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
m21 = 0.0f; m22 = c; m23 = s;
m31 = 0.0f; m32 = -s; m33 = c;
break;
case 2:
m11 = c; m12 = 0.0f; m13 = -s;
m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
m31 = s; m32 = 0.0f; m33 = c;
break;
case 3:
m11 = c; m12 = s; m13 = 0.0f;
m21 = -s; m22 = c; m23 = 0.0f;
m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
break;
default:
assert(false);
}
}
//縮放
void setupScale(const Vector3& s) //這裡的引數是一個向量,但我們沒有把它當作向量來用
{
m11 = s.x; m12 = 0.0f; m13 = 0.0f;
m21 = 0.0f; m22 = s.y; m23 = 0.0f;
m31 = 0.0f; m32 = 0.0f; m33 = s.z;
}
//投影
void setupProject(const Vector3& n) //這裡的這個向量和投影平面相垂直
{
assert(fabs(n*n - 1.0f)<0.01f); //確保這個向量是一個單位向量
m11 = 1.0f - n.x*n.x;
m22 = 1.0f - n.y*n.y;
m33 = 1.0f - n.z*n.z;
m12 = m21 = -n.x*n.y;
m13 = m31 = -n.x*n.z;
m23 = m32 = -n.y*n.z;
}
//映象 2d
void setupReflect(int axits) //指定座標軸
{
switch(axits)
{
case 1: //x座標發生映象,由正的變成負的
m11 = -1.0f; m12 = 0.0f; m13 = 0.0f;
m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
break;
case 2: //y座標發生映象,由正的變成負的
m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
m21 = 0.0f; m22 = -1.0f; m23 = 0.0f;
m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
break;
case 3: //z座標發生映象,由正的變成負的
m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
m31 = 0.0f; m32 = 0.0f; m33 = -1.0f;
break;
default:
assert(false);
}
}
//對3d空間的任意方向的一個映象平面來進行映象
void setupReflect(const Vector3& n)
{
assert(fabs(n*n - 1.0f)<0.01f); //確保這個向量是一個單位向量
float ax = -2.0f * n.x;
float ay = -2.0f * n.y;
float az = -2.0f * n.z;
m11 = 1.0f + ax*n.x;
m22 = 1.0f + ay*n.y;
m33 = 1.0f + az*n.z;
m12 = m21 = ax*n.y;
m13 = m31 = ax*n.z;
m23 = m32 = ay*n.z;
}
//切變
void setupShear(int axis, float s, float t)
{
switch(axis)
{
case 1: //用x去切變y,z,x不變
m11 = 1.0f; m12 = s; m13 = t;
m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
break;
case 2: //用y去切變z,z,y不變
m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
m21 = s; m22 = 1.0f; m23 = t;
m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
break;
case 3: //用z去切變x,y,z不變
m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
m31 = s; m32 = t; m33 = 1.0f;
break;
default:
assert(false);
}
}
};
//矩陣*矩陣
Matrix3x3& operator*(const Matrix3x3& a, const Matrix3x3& b)
{
Matrix3x3 r;
r.m11 = a.m11*b.m11 + a.m12*b.m21 + a.m13*b.m31;
r.m12 = a.m11*b.m12 + a.m12*b.m22 + a.m13*b.m32;
r.m13 = a.m11*b.m13 + a.m12*b.m23 + a.m13*b.m33;
r.m21 = a.m21*b.m11 + a.m22*b.m21 + a.m23*b.m31;
r.m22 = a.m21*b.m12 + a.m22*b.m22 + a.m23*b.m32;
r.m23 = a.m21*b.m13 + a.m22*b.m23 + a.m23*b.m33;
r.m31 = a.m31*b.m11 + a.m32*b.m21 + a.m33*b.m31;
r.m32 = a.m31*b.m12 + a.m32*b.m22 + a.m33*b.m32;
r.m33 = a.m31*b.m13 + a.m32*b.m23 + a.m33*b.m33;
return r;
}
//向量*矩陣
Vector3 operator*(const Vector3& p, const Matrix3x3& m)
{
return Vector3(
p.x*m.m11 + p.y*m.m21 + p.z*m.m31,
p.x*m.m12 + p.y*m.m22 + p.z*m.m32,
p.x*m.m13 + p.y*m.m23 + p.z*m.m33
);
}
//矩陣*矩陣的另一種方式
Matrix3x3& operator*=(Matrix3x3& a, const Matrix3x3& b)
{
a = a*b;
return a;
}
//向量*矩陣的另一種方式
Vector3 operator*=(Vector3& p, const Matrix3x3& m)
{
p = p*m;
return p;
}
//輸出一個矩陣
void print_m(Matrix3x3 m)
{
cout<<to_zero(m.m11)<<"\t"<<to_zero(m.m12)<<"\t"<<to_zero(m.m13)<<endl;
cout<<to_zero(m.m21)<<"\t"<<to_zero(m.m22)<<"\t"<<to_zero(m.m23)<<endl;
cout<<to_zero(m.m31)<<"\t"<<to_zero(m.m32)<<"\t"<<to_zero(m.m33)<<endl;
}
int main()
{
cout<<"hello, 線性變換 - 映象!--2d"<<endl;
Vector3 a(10, 20, 30), b;
Matrix3x3 M;
print_v(a);
M.setupReflect(1); //x軸座標發生變換
b = a*M;
print_v(b);
M.setupReflect(2); //y軸座標發生變換
b = a*M;
print_v(b);
M.setupReflect(3); //z軸座標發生變換
b = a*M;
print_v(b);
cout<<endl<<"hello, 線性變換 - 映象!--3d"<<endl;
Vector3 n(0,0,1); //這個向量是垂直與映象平面,垂直與xy平面,計算之後,z座標發生變換
M.setupReflect(n);
b = a*M;
print_v(b);
cout<<endl<<"hello, 線性變換 - 切變!"<<endl;
M.setupShear(1,1,2); //x不變,y和z會相應的增大
b = a*M;
print_v(b);
return 0;
}