3D数学读书笔记——向量运算及在c++上的实现

本系列文章由birdlove1987编写,转载请注明出处。  

 文章链接: http://blog.csdn.net/zhurui_idea/article/details/24782661

 

开始之前:接上上篇说的,张宇老师说过线性代数研究的就是向量。其实严谨的说,数学中专门研究向量的分之称作线性代数,线性代数是一个非常有趣并且应用广泛的研究

领域,但它与3D数学关注的领域并不相同。3D数学主要关心向量和向量运算的几何意义。

 

零向量:任何集合,都存在 the additive identity element,我们把它表示为 x (变量只是作为代表未知量的占位符存在) ,对集合中任意元素 y ,满足 y + x = y。

n维向量集合的 the additive identity element 就是 n维零向量。它的每一维都是零。

                                                                             

零向量非常特殊,因为它是唯一大小为零的向量。对于其他任意数m,存在无数多个大小为m的向量。它们构成了一个圆。

                                

零向量也是唯一一个没有方向的向量。其实零向量表示的就是“没有位移”,就像标量零表示“没有数量”一样。

 

负向量:对于任意集合,元素 x 的加性逆元为 -x,其与x相加等于the additive identity,即 x + (-x) = 0.             

运算法则1:向量变负,要得到任意维向量的负向量,只需要简单的将向量地每一个分量都变负即可。

                                                 

几何解释:向量变负,将得到一个和原来向量大小相等,方向相反的向量。(向量在图中的位置是无关紧要的,只有大小和方向才是最重要的)。

                                           

 

向量大小:其实向量的大小和方向都没有在向量的数学表示中明确的表示出来。所有向量的大小是需要计算的,向量的大小也常被称作向量的长度或

运算法则2:n维向量大小的计算公式如下图

                                       

线性代数中,向量的大小用向量两边双竖线表示,这和标量的绝对值在标量两边加单竖线表示类似。(和我们在神经网络课上学的范数也很像)。

 

标量与向量的乘法:虽然标量与向量不能相加,但它们能相乘。结果得到一个向量,与源向量平行,但长度不同或方向相反。

运算法则3:标量和向量的乘法非常直接,将向量的每一个分量都与标量相乘即可。

                                          

ps:1. 标量与向量的乘法和除法优先级高于加法和减法。

    2. 标量不能除以向量,并且向量不能除以另一个向量。

    3. 负向量能被认为是乘法的特殊情况,乘以标量-1.

几何解释:几何意义上,向量乘以标量K的效果是以因子|k| 缩放向量的长度。

 

 

 

 

标准化向量:对许多向量,我们只关心它的方向而不关心其大小,这样的情况下,使用单位向量将非常方便。

单位向量就是大小为1的向量,单位向量经常也被称作标准化向量。

运算法则4:对于任意非零向量v,都能计算出一个和v方向相同的单位向量 v‘ 这个过程被称作向量的标准化,要标准化向量,将向量除以它的大小即可。

             

ps:零向量不能被标准化。数学上这是不允许的,因为将导致除零。几何上也没有意义,因为零向量没用方向。

 

向量的加法和减法:如果两个向量的维数相同,那么它们能相加,或相减。结果向量的维数与原向量相同。向量加减法的记法和标量加减的记法相同。

运算法则5:两个向量相加或相减,将对应分量相加即可。

                           

ps:(1)向量不能与标量或维数不同的向量相加减。

    (2)和标量加法一样,向量加法满足交换律,但向量减法不满足交换律。

 

向量点乘:向量点乘也常称作向量内积。

运算法则6:向量点乘就是对应分量乘积的和,结果是一个标量。

                               

几何解释:点乘结果描述了两个向量的“相似”程度,点乘结果越大,两个向量越相近。

                                                                  

                                   

ps:(1)如果a,b中任意一个为零,那么a·b的结果也等于零。但是点乘等于零也可能是两个向量相互垂直。

 

向量投影:给定两个向量 v 和 n,能将v分解成两个分量:,它们分别平行和垂直于n ,并满足 v = +。一般称平行分量为 v 在 n 上的投影。

运算法则7:我们使用点乘计算投影。

                        

 

向量叉乘:向量叉乘又叫叉积,仅可应用于3D向量。

运算法则8:                       

                       

几何解释:叉乘得到的向量垂直于原来的两个向量。

        

          

========================华丽的分割线===============================

下面用c++代码实现以下上面出现过的计算过程:

 

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. class Vector3D {  
  2. public:  
  3. float x,y,z;  
  4. // 构造函数  
  5. // 默认构造函数,不执行任何操作  
  6. Vector3D() {}  
  7. // 复制构造函数  
  8. Vector3D(const Vector3D &a) : x(a.x), y(a.y), z(a.z) {}  
  9. // 带三个参数的构造函数,三个值完成初始化  
  10. Vector3D(float nx, float ny, float nz) : x(nx), y(ny), z(nz) {}  
  11. // 重载赋值运算符  
  12. Vector3D &operator =(const Vector3D &a) {  
  13.   x = a.x; y = a.y; z = a.z;  
  14.   return *this;  
  15. }  
  16. // 重载比较运算符  
  17. bool operator ==(const Vector3D &a) const {  
  18.   return x==a.x && y==a.y && z==a.z;  
  19. }  
  20. bool operator !=(const Vector3D &a) const {  
  21.   return x!=a.x || y!=a.y || z!=a.z;  
  22. }  
  23. // 向量运算  
  24. // 设置零向量  
  25. void zero() { x = y = z = 0.0f; }  
  26. // 重载负运算符  
  27. Vector3D operator –() const { return Vector3D(–x,–y,–z); }  
  28. // 重载加减运算符  
  29. Vector3D operator +(const Vector3D &a) const {  
  30.   return Vector3D(x + a.x, y + a.y, z + a.z);  
  31. }  
  32. Vector3D operator –(const Vector3D &a) const {  
  33.   return Vector3D(x – a.x, y – a.y, z – a.z);  
  34. }  
  35. // 重载标量乘、除法运算符  
  36. Vector3D operator *(float a) const {  
  37.   return Vector3D(x*a, y*a, z*a);  
  38. }  
  39. Vector3D operator /(float a) const {  
  40.   float oneOverA = 1.0f / a; // 没有对除零检查  
  41.   return Vector3D(x*oneOverA, y*oneOverA, z*oneOverA);  
  42. }  
  43. // 重载?=运算符  
  44. Vector3D &operator +=(const Vector3D &a) {  
  45.   x += a.x; y += a.y; z += a.z;  
  46.   return *this;  
  47. }  
  48. Vector3D &operator –=(const Vector3D &a) {  
  49.   x –= a.x; y –= a.y; z –= a.z;  
  50.   return *this;  
  51. }  
  52. Vector3D &operator *=(float a) {  
  53.   x *= a; y *= a; z *= a;  
  54.   return *this;  
  55. }  
  56. Vector3D &operator /=(float a) {  
  57.   float oneOverA = 1.0f / a;  
  58.   x *= oneOverA; y *= oneOverA; z *= oneOverA;  
  59.   return *this;  
  60. }  
  61. // 向量标准化  
  62. void normalize() {  
  63.   float magSq = x*x + y*y + z*z;  
  64.   if (magSq > 0.0f) { // 检查除零  
  65.      float oneOverMag = 1.0f / sqrt(magSq);  
  66.     x *= oneOverMag;  
  67.     y *= oneOverMag;  
  68.     z *= oneOverMag;  
  69. }  
  70. }  
  71. // 向量点乘,重载乘法运算符  
  72. float operator *(const Vector3D &a) const {  
  73.   return x*a.x + y*a.y + z*a.z;  
  74. }  
  75. };  
  76.   
  77. // 求向量模  
  78. inline float vectorMag(const Vector3D &a) {  
  79.   return sqrt(a.x*a.x + a.y*a.y + a.z*a.z);  
  80. }  
  81. // 计算两向量的叉乘  
  82. inline Vector3D crossProduct(const Vector3D &a, const Vector3D &b) {  
  83.   return Vector3D(a.y*b.z – a.z*b.y,a.z*b.x – a.x*b.z,a.x*b.y – a.y*b.x);  
  84. }  
  85. // 标量乘法  
  86. inline Vector3D operator *(float k, const Vector3D &v) {  
  87.   return Vector3D(k*v.x, k*v.y, k*v.z);  
  88. }  
  89. // 计算两点间距离  
  90. inline float distance(const Vector3D &a, const Vector3D &b) {  
  91.   float dx = a.x – b.x;  
  92.   float dy = a.y – b.y;  
  93.   float dz = a.z – b.z;  
  94.   return sqrt(dx*dx + dy*dy + dz*dz);  
  95. }  
  96.   
  97. // 全局零向量  
  98. extern const Vector3D kZeroVector;  


                                                             -End-

 参考文献:(1)《3D Math Primer for Graphics and Game Development》

                 (2)百度百科  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值