旋转示意:

3x3矩阵可以用于表示一个物体的旋转信息,例如下面的图形,下面三维图形没有做任何的平移旋转操作。途中红绿蓝三个箭头的方向分别代表X轴,Y轴,Z轴,并且,三轴的交点是原点(0,0,0)。

每个三维模型都是由大量的点面组成,有点就一定有一个坐标系,这个坐标系就是数据坐标系。当显示一个模型在空间不做任何移动,旋转,那么他的数据坐标系就刚好和显示空间的世界坐标系重合,如上图一样。上图的显示可以看出飞机模型原始数据的原点和方向(x',y',z'),就是和目前显示的完全一样,图中X,Y,Z和x',y',z'重合。当移动模型的时候,如下图:

上图的移动过程,将模型移动到了【18.0,36.0,54.0】的位置了,移动可以看作是眼三维向量的移动。与移动相对应的旋转也一样,旋转可以用3x3的矩阵表示。旋转示意如下,绕X轴旋转30度效果:

旋转前后,位置不变,模型的姿态(数据坐标姿态)和原始相比,绕X轴旋转了30度。在旋转前,数据坐标与世界坐标完全重合,此时,旋转矩阵为单位矩阵,当旋转30度后,旋转矩阵的X轴不发生变化,Y、Z轴均旋转了30度,矩阵分别如下:

  

注意,这里的矩阵是4x4的矩阵,代表了物体的旋转平移放大等信息,其旋转部分为左上角的3x3矩阵。如果我们先绕X轴旋转30度,再移动到【18.0,36.0,54.0】和我们先移动到【18.0,36.0,54.0】再绕X轴旋转30度,这两种情况如下图:

  

可以看出,两种操作得到的结构并不一样。

Matrix3x3:

旋转矩阵就是用于表示物体的旋转姿态信息,也包含放大信息,因此,在qySpace的3x3矩阵库的接口也是根据这样的需求来的,并不一定可以很好地适用于线性代数的计算。

用Matrix3x3来表示物体的旋转非常直观,一眼便可看出旋转后的X、Y、Z轴的方向。不仅如此,3x3矩阵还可以很好地表示出放大缩小信息,避免了使用欧拉角带来的万向节锁死问题。

3x3矩阵的构造函数和析构函数如下:

        /// constructor, unit matrix default.matrix3x3();/// construct from another matrix3x3.matrix3x3(const matrix3x3& mat);/// move constructor.matrix3x3(matrix3x3&& mat) noexcept;/// construct from quaternion.matrix3x3(const quaternion& q);/// construct from pointer, there must be nine values.matrix3x3(const real* data);/// destructor.virtual ~matrix3x3();

它可以直接构造、从另一个矩阵构造,从四元数构造,从数据指针构造。注意,上面的real数据实际上就是double。在vtk等三维引擎中,直接使用指针的地方很多,里面的矩阵一般也能够通过指针构造,因此,最后一个构造函数是为了兼容和使用方便设计的。

除此之外,矩阵计算还包括:

    public:/// return true if not equal.bool operator!=(const matrix3x3& mat) const;/// return true if equal, all values equal.bool operator==(const matrix3x3& mat) const;/// operator=, from another matrix3x3.matrix3x3& operator=(const matrix3x3& mat);/// move operator=.matrix3x3& operator=(matrix3x3&& mat) noexcept;/// operator= from quaternion.matrix3x3& operator=(const quaternion& q);/// operator=, from pointer, there must be nine values.matrix3x3& operator=(const real* data);/// operator*=, return *this, *this *= mat.matrix3x3& operator*=(const matrix3x3& mat);/// operator*, return *this * mat, non change in *this.[[nodiscard]] matrix3x3 operator*(const matrix3x3& mat) const;/// operator*, return *this * pt, non change in *this.[[nodiscard]] point operator*(const point& pt) const;/// operator*, return *this * vec, non change in *this.[[nodiscard]] vector operator*(const vector& vec) const;public:/// print on console.void print() const;/// is real, is available.bool isReal();/// set matrix form x and y axis, calculate z axis automatically.void rotateFromXYAxis(const vector& vecX, const vector& vecY);/// set matrix from z axis, x and y are random, normalized vector.void rotateFromZAxis(const vector& vecZ);/// zero all data.void zero();/// convert to unit matrix.void identity();/// convert to invert matrix.void invert();/// convert to transpose matrix.void transpose();/// *this *= mat, save in this.void multiplied(const matrix3x3& mat);/// mat *= *this, save in this.void preMultiplied(const matrix3x3& mat);/// return *this * mat, non change in *this.[[nodiscard]] matrix3x3 multiply(const matrix3x3& mat) const;/// return mat * *this, non change in *this.[[nodiscard]] matrix3x3 preMultiply(const matrix3x3& mat) const;/// return *this * pt, non change in *this.[[nodiscard]] point multiply(const point& pt) const;/// return *this * vec, non change in *this.[[nodiscard]] vector multiply(const vector& vec) const;/// retuan determinate.real determinate() const;/// rotate around axisvoid rotateAxis(const real radians, const vector& vec);/// rotate around axisvoid rotateAxis(const real radians, Axis axis);/// rotate around self axisvoid rotateSelfAxis(const real radians, Axis axis);

注释和函数名都能够非常好地表示函数实际功能。如果不明白也没关系,下面对Matrix3x3的每个函数进行测试和介绍。

测试:

一、构造函数和析构函数部分:

    qytk::matrix3x3 mat0;mat0.print();qytk::matrix3x3 mat1(mat0);mat1.print();double d[9]{ 0,1,0,0,0,1,1,0,0 };qytk::matrix3x3 mat2(d);mat2.print();

其中前两个是构造的单位矩阵,第三个实际上是单位矩阵绕【1.0,1.0,1.0】轴旋转-120度的结果,可以脑补下这个旋转得到的应该是什么样的状态,其打印结果如下:

    

绕【1.0,1.0,1.0】旋转-120度,实际上是X轴旋转到Z轴,Y轴旋转到X轴,Z轴旋转到Y轴。如上第三个打印,第一列数据就代表X轴,为【0,0,1】,即变换后的X轴位于世界坐标的Z轴,以此类推。

二、对于operator!=和operator==,以及operator=不着重介绍,对于operator*如下:

    mat0 *= mat3;mat0.print();mat3 = mat3 * mat3;mat3.print();qytk::point pt0(1.0, 2.0, 3.0);qytk::point pt1 = mat3 * pt0;pt1.print();qytk::vector vec0(1.0, 2.0, 3.0);qytk::vector vec1 = mat3 * vec0;vec1.print();

初始状态为:mat0为单位矩阵,mat3为绕【1.0,1.0,1.0】旋转-120度的旋转矩阵。上面计算结果打印如下:

上面即为普通的矩阵计算方法,但其对空间变换的含义为:

1、将mat3的姿态应用一次单位矩阵的变换(实际就是什么都没变)

2、将mat3的姿态在应用一次mat3的变换(即绕【1.0,1.0,1.0】旋转-120度,再次绕这个轴旋转-120度,此时XYZ

轴的位置分别为:X->Y,Y->Z,Z->X)

3、点【1.0,2.0,3.0】经过mat3的变换后,得到新的点【3.0,1.0,2.0】,注意,新的点是在世界坐标系(单位矩阵)下面的坐标,这个计算过程可以看作点经过mat3变换到新的位置。

4、向量【1.0,2.0,3.0】经过mat3的变换后,得到的新的向量【3.0,1.0,2.0】,与上面点完全一样,此计算过程是将向量尖端变换到新的位置(变换后为世界坐标系下原点指向新的位置的向量)。

三、设置旋转矩阵

    vec0.set(3, 4, 5);vec1.set(-4, 3, 5);mat4.identity();mat4.rotateFromXYAxis(vec0, vec1);mat4.print();qytk::matrix3x3 mat5;mat5.rotateFromZAxis(vec1);mat5.print();

上面计算是根据设置XY两轴生成旋转矩阵、根据设置的Z轴生成旋转矩阵。其中根据Z轴生成的旋转矩阵的XY两轴是随机的,此接口是为了方便使用。而根据XY轴可以生成坐标系是建立在使用右手直角坐标系的基础上的。这两种建立旋转矩阵的方法都不存在缩放信息,只包含姿态信息。打印结果如下:

四、下面对普通的计算函数进行简要介绍,不做测试解析:

1、zero()、将矩阵置零,所有元素均赋值为0,再空间变换中,几乎不会使用这个函数。

2、identity()、将矩阵赋值为单位矩阵,一般用于初始化/复位矩阵。

3、invert()、求当前矩阵的逆矩阵,并赋值给当前矩阵。逆矩阵用于表示反向变换,及逆变换。

4、transpose()、求转置矩阵,一般不会使用。

5、determinate()、计算矩阵的行列式值并返回,一般外部不使用,在内部求取逆矩阵时会使用。

五、矩阵乘法:

        void multiplied(const matrix3x3& mat);/// mat *= *this, save in this.void preMultiplied(const matrix3x3& mat);/// return *this * mat, non change in *this.matrix3x3 multiply(const matrix3x3& mat) const;/// return mat * *this, non change in *this.matrix3x3 preMultiply(const matrix3x3& mat) const;/// return *this * pt, non change in *this.point multiply(const point& pt) const;/// return *this * vec, non change in *this.vector multiply(const vector& vec) const;

矩阵乘法部分与上面的operator*和operator*=完全一样,示例与上面也基本一样,不介绍。

六、旋转部分:

        /// rotate around axisvoid rotateAxis(const real radians, const vector& vec);/// rotate around axisvoid rotateAxis(const real radians, Axis axis);/// rotate around self axisvoid rotateSelfAxis(const real radians, Axis axis);

这部分是矩阵旋转,前两个函数是矩阵绕指定轴旋转,最后一个是矩阵绕当前自身轴旋转(XYZ轴或-X-Y-Z轴之一),,示例如下:

    qytk::matrix3x3 mat8;mat8.rotateAxis(qytk::radiansFromDegrees(120), qytk::vector(1.0, 1.0, 1.0));mat8.print();mat8.identity();mat8.rotateAxis(qytk::radiansFromDegrees(30.0), qytk::Axis::AXIS_X);mat8.print();mat8.rotateSelfAxis(qytk::radiansFromDegrees(30.0), qytk::Axis::AXIS_Y);mat8.print();

打印如下:

效果分别如下:

总结:

3x3的矩阵可用于表示三维空间的缩放、旋转姿态等信息,同时,四元数也可以表示三维空间的旋转信息,可以将四元数转换成3x3矩阵。

qySpace下载地址(github):qySpace

qySpace下载地址(csdn):qySpace

空间变换与计算_02_3x3矩阵相关推荐

  1. 形象理解线性代数(三)——列空间、零空间(核)、值域、特征值(特征向量)、矩阵与空间变换、矩阵的秩

    这里,我们还是要以 形象理解线性代数(一)--什么是线性变换?为基础.矩阵对向量的作用,可以理解为线性变换,同时也可以理解为空间的变换,即(m*n)的矩阵会把一个向量从m维空间变换到n维空间. 一.矩 ...

  2. DirectX 11---从空间变换来看3D场景如何转化到2D屏幕

    DirectX 11---从空间变换来看3D场景如何转化到2D屏幕 在看<Introduction to 3D Game Programming with DirectX 11>的时候,发 ...

  3. ker矩阵是什么意思_矩阵分析(一):空间变换与基变换

    "在这个小测验里,我让你们求一个2*3矩阵的行列式.让我感到非常可笑的是,你们当中竟然有人尝试去做."(摘自http://mathprofessorquotes.com,作者佚名) ...

  4. Unity Shader入门精要笔记(四):矩阵与空间变换

    本系列文章由Aimar_Johnny编写,欢迎转载,转载请标明出处,谢谢. http://blog.csdn.net/lzhq1982/article/details/73612170 上一篇我们学习 ...

  5. Opencv——几何空间变换(仿射变换和投影变换)

    几何空间变换 [1]几何变换(空间变换)简述 [2]变换矩阵知识简述 齐次坐标的概念 几何运算矩阵 [3]图像的仿射变换 1.平移变换 2.比例缩放 3.旋转 4.对称变换(不做展示) 1.关于X轴变 ...

  6. OpenCV之灰度空间变换

    OpenCV入门之灰度空间变换 本系列博客主要以数字图像处理第三版为算法基础,以OpenCV为工具进行图像处理基础知识的分享.该教材的前两张基础知识这里不详述,有需要的读者自行查阅.本篇博客介绍第三章 ...

  7. 土圭垚㙓数学课(四)空间变换

    我曾经在Shader山下(十六)坐标空间与转换矩阵中介绍过,一个物体要显示在平面上,需要经过四步空间变换(实际上是五步): 物体空间->世界空间->观察空间->裁剪空间(->归 ...

  8. 点的空间变换与坐标系的空间变换

    博主小白,分享一下自己对于点变换和坐标系变换的理解,不对的地方请大家指出~ 目录 坐标系变换 点变换 KITTI数据集中的坐标系关系 参考 坐标系变换 以最简单的坐标系变换为例,如下图 图中有两个坐标 ...

  9. 使用eigen库进行空间变换

    使用eigen库进行空间变换 在三维空间中,常常需要变换当前机器人的位姿计算定义的绝对坐标系和当前机器人所处相对坐标系之间的关系.而主要的变换则是平移和旋转,有时候可能需要尺度变换,那么就可以描述为: ...

  10. 图像坐标空间变换:透视变换(Perspective Transformation),或称为单应性(Homography)变换

    文章目录 透视变换简介 预备知识 透视变换公式推导 投影 二维坐标向齐次坐标的变换 公式求解 例子:A4纸视角校正 原始图片和坐标变换模板 计算程序 结果 透视变换的限制 前向映射与后向映射矩阵不互逆 ...

最新文章

  1. 存clob为空的值_将网页文本(HTML)保存到ORACLE数据库CLOB字详解
  2. 题目1132:与7无关的数
  3. 将一个键值对添加入一个对象_细品Redis高性能数据结构之hash对象
  4. 体二极管的原理及应用
  5. qq饥荒联机版服务器没有响应,饥荒联机版专用服务器卡顿原因及解决方法汇总...
  6. [Selenium] 操作新弹出窗口之验证标题和内容
  7. 蓝牙天线的一点小资料
  8. PL\SQL设置中文
  9. 自然语言处理-停用词
  10. matlab网格划分提取坐标,ANSYS-划分网格后导出单元和结点坐标等信息
  11. 写给 python 程序员的 OpenGL 教程
  12. 前端JS xxxx年xx月xx日转换成页面时间组件xxxx-xx-xx格式
  13. 千年db服务器注册,千年服务器架设说明.doc
  14. 语音信号的短时平均过零率
  15. mysql slave是什么_是mysql表里
  16. SGU 111 Very simple problem 翻译 题解
  17. 树莓派实战:微信机器人(itchat实现)
  18. LWN:两组跟memory-tier有关的patch!
  19. 《神秘的程序员们》年度抽奖活动 开奖了
  20. python绘制太阳系模型_用python做一个漂亮的太阳系运动模拟

热门文章

  1. android分辨率修改器,安卓分辨率一键修改器
  2. flask 导出excel
  3. vueAdmin-template-master十次方后台项目前端(已经完成初始化)下载地址
  4. 中国数控机床行业市场竞争态势及投资战略规划报告2022-2028年版
  5. 【Chinapub读书会第9期】5月28日赵鑫磊带你深入解析Linux
  6. python天气可视化分析报告_Python爬取天气数据及可视化分析
  7. 微信打飞机项目小结-屏幕适配
  8. 谷歌金山词霸更新历史
  9. 1_Hadoop安装部署及常用配置(HDFS+YARN)
  10. Node——request使用代理