从某一点出发沿任意一方向旋转矩阵计算思考与实现

这篇具有很好参考价值的文章主要介绍了从某一点出发沿任意一方向旋转矩阵计算思考与实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

欢迎关注更多精彩
关注我,学习常用算法与数据结构,一题多解,降维打击。

上期讲到
绕任一向量旋转矩阵计算思考与实现
点击前往
点击前往

问题提出

之前讲到绕任一向量旋转矩阵实现,原来的向量都是从原点出发,现在把出发点改变成任意一点。

从某一点出发沿任意一方向旋转矩阵计算思考与实现

除了需要计算旋转矩阵,还可以支持2个旋转矩阵的乘法操作。就是2个旋转矩阵依次作用以后的一个综合结果。

问题分析

从某点出发沿某一方向旋转实现

从原点出发的旋转是已经实现的,我的思路是把坐标系统一平移一个(-x0, -y0,-z0),然后作用旋转矩阵,最后再平移回去。

用公式表示, RT1表示旋转矩阵,O1表示出发点。

P ′ = R T 1 ⋅ ( P − O 1 ) + O 1 ( 1 ) P' = RT1\cdot(P-O1)+O1 (1) P=RT1(PO1)+O11

既我们只要用一个旋转矩阵RT加一个出发点O就可以表示这个旋转动作。那么如果是2个旋转动作叠加怎么去用一个旋转动作来表示呢。

旋转相乘

有一种方法是用奇次矩阵来表示一个平移和旋转的组合,然后矩阵可以相乘,但是这种方式需要用到4*4的矩阵效率上没有3*3的矩阵来得高。

我这边通过公式推导得到一种新的表示方法。

首先对式子(1)进行展开再合并同类项得到

P ′ = R T 1 ⋅ P + ( I − R T 1 ) ⋅ O 1 P'=RT1\cdot P+(I-RT1)\cdot O1 P=RT1P+(IRT1)O1

( I − R T 1 ) ⋅ O 1 是一个常量, (I-RT1)\cdot O1 是一个常量, (IRT1)O1是一个常量,

即只要一个表示形如 R T ⋅ P + Q ( Q 是一个常量 ) 的形式, 即只要一个表示形如 RT\cdot P+Q(Q是一个常量)的形式, 即只要一个表示形如RTP+Q(Q是一个常量)的形式,

就可用一个矩阵加一个出发点的形式来表示。 就可用一个矩阵加一个出发点的形式来表示。 就可用一个矩阵加一个出发点的形式来表示。

出发点 O = ( I − R T ) − 1 Q 出发点O=(I-RT)^{-1}Q 出发点O=(IRT)1Q

现在有第二个旋转RT2,O2作用于P’ 得到

P ′ ′ = R T 2 ⋅ P ′ + ( I − R T 2 ) ⋅ O 2 P''=RT2\cdot P' + (I-RT2)\cdot O2 P′′=RT2P+(IRT2)O2

= R T 2 ⋅ R T 1 ⋅ P + R T 2 ⋅ ( I − R T 1 ) ⋅ O 1 + ( I − R T 2 ) ⋅ O 2 =RT2\cdot RT1 \cdot P + RT2\cdot (I-RT1)\cdot O1 + (I-RT2)\cdot O2 =RT2RT1P+RT2(IRT1)O1+(IRT2)O2

上式中 , R T = R T 2 ⋅ R T 1 上式中, RT = RT2\cdot RT1 上式中,RT=RT2RT1

O = ( I − R T ) − 1 ⋅ [ R T 2 ⋅ ( I − R T 1 ) ⋅ O 1 + ( I − R T 2 ) ⋅ O 2 ] O = (I-RT)^{-1}\cdot [RT2\cdot (I-RT1)\cdot O1 + (I-RT2)\cdot O2] O=(IRT)1[RT2(IRT1)O1+(IRT2)O2]

这样,我们就得了两个刚体变换的综合变换。

但是上面的方法有一个问题,当(I-RT)不可逆时,那么该公式失效。
我的理解是,当(I-RT)不可逆时,O并不是没有解,而是有很多个解。

那么我们要另选他法。

再观察(1)式,其实我们并不需要求出O,只要求出Q就可以了。

R T = R T 2 ⋅ R T 1 , Q = R T 2 ⋅ Q 1 + Q 2 RT = RT2\cdot RT1, Q=RT2\cdot Q_1 + Q_2 RT=RT2RT1,Q=RT2Q1+Q2

这个方法与奇次矩阵相比,计算量小很多。

代码实现

  • 代码链接点击前往
  • 代码链接点击前往
  • 代码链接点击前往

namespace acamcad {
    const double pi = acos(-1);
    using Point = Eigen::Vector3d;
    class RigidRTMatrix {
    private:
        Eigen::Matrix3d mat;
        Eigen::Vector3d trans;
        
    public:
        RigidRTMatrix(Point start, Point end, double theta) {
            cout << "generate RigidRTMatrix 2" << endl;
            Eigen::Vector3d v = end - start;
            cout << "v:" << v << endl;
            cout << "angle:" << theta << endl;
            assert(!v.isZero());
            // Point::Zero();
            v.normalize();
            Eigen::Vector3d X(1,0,0);
            Eigen::Vector3d m = v.cross(X);
            // todo m=0时特殊处理
            if (m.isZero()) {
                if (v.dot(X) > 0) m = { 0,1,0 }; // 直接等于Y轴
                else m = { 0,-1,0 }; // 等于Y轴的反轴
            }

            auto RY = GetRY(m);
            // 将v 旋转至ZOX 平面。
            auto vZOX = RY * v;
            auto RX = GetRX(vZOX);

            auto Xrotate = GetXRotate(theta);

            mat = RY.transpose() * RX.transpose() * Xrotate * RX * RY;
            cout << "mat create :" << mat << endl;

            trans = (Eigen::Matrix3d::Identity() - mat) * start; // 存储总体位移
        }
        
        RigidRTMatrix() {

        }
        
        // 给定YOX平面上的单位M向量,将其旋转到Y轴上。
        Eigen::Matrix3d GetRY(Eigen::Vector3d m) {
            assert(!m.isZero());
            m.normalize();
            Eigen::Matrix3d RY;
            RY.setIdentity();
            RY(1, 1) = m.y();
            RY(1, 2) = m.z();
            RY(2, 1) = -m.z();
            RY(2, 2) = m.y();
            return RY;
        }

        // 给定ZOX平面上的单位M向量,将其旋转到X轴上。
        Eigen::Matrix3d GetRX(Eigen::Vector3d m) {
            assert(!m.isZero());
            m.normalize();
            Eigen::Matrix3d RX;
            RX.setIdentity();
            RX(0, 0) = m.x();
            RX(0, 2) = m.z();
            RX(2, 0) = -m.z();
            RX(2, 2) = m.x();
            return RX;
        }

        // 给定ZOX平面上的单位M向量,将其旋转到X轴上。
        Eigen::Matrix3d GetXRotate(double theta) {
            double rad = theta / 180 * pi;
            Eigen::Matrix3d X;
            X.setIdentity();
            X(1, 1) = cos(rad);
            X(1, 2) = -sin(rad);
            X(2, 1) = sin(rad);
            X(2, 2) = cos(rad);
            return X;
        }

        double angleMod(double theta) {
            while (theta < -180)theta += 360;
            while (theta > 180)theta -= 360;
            return theta;
        }

        Point Trans(Point &a) {
            return mat * a + trans;
        }

        friend static RigidRTMatrix operator*(RigidRTMatrix& a, RigidRTMatrix& b) {
            RigidRTMatrix multi;
            multi.mat = a.mat * b.mat;
            multi.trans = a.mat * b.trans + a.trans;
            return multi;
        }
    };
}

代码测试

从某一点出发沿任意一方向旋转矩阵计算思考与实现

从某一点出发沿任意一方向旋转矩阵计算思考与实现
可以看出一个点依次作用与用一次综合矩阵的效果是一样的。


本人码农,希望通过自己的分享,让大家更容易学懂计算机知识。

欢迎添加我的公众号,进群交流。文章来源地址https://www.toymoban.com/news/detail-428869.html

到了这里,关于从某一点出发沿任意一方向旋转矩阵计算思考与实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 采用VMD按照某一坐标轴旋转坐标结构

    关注 M r . m a t e r i a l   , color{Violet} rm Mr.material , Mr.material   , 更 color{red}{更} 更 多 color{blue}{多} 多 精 color{orange}{精} 精 彩 color{green}{彩} 彩 ! 主要专栏内容包括:   †《LAMMPS小技巧》: ‾ textbf{ underline{dag《LAMMPS小技巧》:}}   † 《 LAMMPS 小技巧》: ​ 主要介绍采

    2024年02月13日
    浏览(36)
  • 判断任意一点是否在矩形内(矩形可能与坐标轴有一定夹角)

    问题 如何判断点 P P P 是否在被 P 1 P 2 P 3 P 4 P_1P_2P_3P_4 P 1 ​ P 2 ​ P 3 ​ P 4 ​ 四个点围成的矩形框内? 方法 如果在矩形内:点 P P P 与矩形4个角的连线与任意轴形成的夹角都为锐角。可以用向量的点乘判断角度是否为锐角。具体方法如下图所示。 所以可以通过下列公式判断

    2024年02月09日
    浏览(38)
  • 图形学、02 推导证明 | 任意一点经过透视投影后 z 坐标相对于之前有什么变化

    齐次坐标知识点: (begin{bmatrix} x \\\\ y \\\\ z \\\\ 1 \\\\end{bmatrix} Rightarrowbegin{bmatrix} nx \\\\ ny \\\\ nz \\\\ n \\\\end{bmatrix}) 两个都表示同一个点 透视投影:先将远截面按一定规则缩放到跟近截面一样大,然后再正交投影 缩放规则: 远截面 缩放后 (z) 不变,缩放过后大小同近截面相同。 截

    2024年02月08日
    浏览(38)
  • ROS下控制无人机任任意方向下往机头方向飞行

    控制方案如下: 1、无人机任意方向放置后,通过程序获取初始放置的偏航监督yaw 2、结合距离L,计算出相对ROS的ENU坐标系下的XY位置 3、保持角度和目标位置飞行 4、识别到目标后,控制无人机以机体坐标系进行运动 5、运动到目标正上方后,投放物体即可

    2024年02月22日
    浏览(40)
  • Android 获取屏幕方向,根据屏幕旋转角度判断屏幕实际方向

    在使用 getResources().getConfiguration().orientation 获取屏幕方向时,可能会遇到不准确的问题。 这是因为该方法返回的是设备的自然方向,而不是屏幕的实际方向。 在某些情况下,设备的自然方向可能与屏幕的实际方向不同。例如,如果设备是横向放置的,但屏幕是纵向显示的,那

    2024年02月03日
    浏览(51)
  • 欧拉角计算旋转矩阵的MATLAB函数——eul2rotm和angle2dcm区别

    学惯导的人都知道怎么根据欧拉角或者姿态角计算旋转矩阵,直接照着公式两分钟就写好了代码。但是或许你没有注意到MATLAB中 eul2rotm 和 angle2dcm 两个函数的定义完全不一样, 两个函数算出来的旋转矩阵互为转置 。MATLAB本身并未将两个函数的定义写得很清楚,经过一番搜索

    2024年02月15日
    浏览(44)
  • CSS 沿着同一个方向旋转

    主要解决旋转360°后倒转的问题,沿着一个方向旋转,而不是倒回去重新开始。 效果  源码 在线示例 同方向旋转

    2024年02月15日
    浏览(49)
  • 知三维空间中任意旋转抛物面的顶点和焦点坐标,建立该旋转抛物面方程

            建立三维空间旋转抛物线方程的前提,首先需要确定三维空间直角坐标系的 位置,然后确定焦点和抛物面顶点的坐标,再利用焦点和抛物面顶点的坐标求出准面方程(我们这里把准面定义为是准线绕着焦点与抛物面顶点形成的直线旋转180°所形成的平面,且该平面垂

    2024年02月09日
    浏览(47)
  • 【FPGA图像处理】——DDR仲裁、多输入源拼接、旋转任意角度、突发长度修改、任意地址读取。

    前言:做FPGA大赛期间遇到的问题,自己coding过程。 包含:hdmi、摄像头等多输入源的拼接;了解DDR以及多种DMA传输方式,修改底层突发长度以及存储位宽;单输入源任意角度旋转(无需降低帧率)。 写这篇文章的原因呢,是因为之前参加FPGA大赛的时候遇到很多问题找不到系

    2024年02月05日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包