根据两个向量计算它们之间的旋转矩阵

一、简介

本文主要介绍通过给定的两个空间向量,计算出从一个向量旋转到另一个向量的旋转矩阵。

二、步骤

① 假设两个向量分别为vectorBefore(x1,y1,z1), vectorAfter(x2,y2,z2),将这两个向量转为单位向量。

得到 va = normalize(vectorBefore), vb = normalize(vectorAfter)

② vs = vb × va, 叉乘得到旋转轴vs

③ v = normalize(vs), vs转为单位向量得到v

④ ca = vb · va, 点乘得到旋转角的余弦值 ca, 即cos(angle)

⑤ vt = v * scale, 对v进行缩放,方便后面计算, scale = 1 – ca

⑥ 旋转矩阵rm为 [3,3]矩阵, 计算原理为 罗德里格旋转公式(Rodrigues’ rotation formula)

rm[0,0] = vt.x * v.x + ca

rm[1,1] = vt.y * v.y + ca

rm[2,2] = vt.z * v.z + ca

vt.x *= v.y

vt.z *= v.x

vt.y *= v.z

rm[0,1] = vt.x – vs.z

rm[0,2] = vt.z – vs.y

rm[1,0] = vt.x – vs.z

rm[1,2] = vt.y – vs.x

rm[2,0] = vt.z – vs.y

rm[2,1] = vt.y – vs.x

根据两个向量计算它们之间的旋转矩阵

三、效果

红色为旋转前的平面,蓝色为旋转后的实际平面, 绿色是对红色平面应用计算的旋转矩阵后得到的平面,所以绿色与蓝色应在同一平面内。

根据两个向量计算它们之间的旋转矩阵

四、代码

public struct Vec3
        {
            public float x;
            public float y;
            public float z;
            public Vec3(float X, float Y, float Z)
            {
                x = X;
                y = Y;
                z = Z;
            }
        }

float[,] getRotationMatrix(Vec3 vectorBefore, Vec3 vectorAfter)
        {
            Vec3 vb = Normalize(vectorBefore);
            Vec3 va = Normalize(vectorAfter);

            Vec3 vs = CrossProduct(vb, va);
            Vec3 v = Normalize(vs);
            float ca = DotProduct(vb, va);

            float scale = 1 - ca;
            Vec3 vt = new Vec3(v.x * scale, v.y * scale, v.z * scale);

            float[,] rotationMatrix = new float[3,3];

            rotationMatrix[0, 0] = vt.x * v.x + ca;
            rotationMatrix[1, 1] = vt.y * v.y + ca;
            rotationMatrix[2, 2] = vt.z * v.z + ca;
            vt.x *= v.y;
            vt.z *= v.x;
            vt.y *= v.z;

            rotationMatrix[0, 1] = vt.x - vs.z;
            rotationMatrix[0, 2] = vt.z + vs.y;
            rotationMatrix[1, 0] = vt.x + vs.z;
            rotationMatrix[1, 2] = vt.y - vs.x;
            rotationMatrix[2, 0] = vt.z - vs.y;
            rotationMatrix[2, 1] = vt.y + vs.x;

            return rotationMatrix;
        }

        Vec3 CrossProduct(Vec3 a, Vec3 b)
        {
            Vec3 c = new Vec3()
            {
                x = a.y * b.z - a.z * b.y,
                y = a.z * b.x - a.x * b.z,
                z = a.x * b.y - a.y * b.x
            };

            return c;
        }

        float DotProduct(Vec3 a, Vec3 b)
        {
            return a.x * b.x + a.y * b.y + a.z * b.z;
        }

        Vec3 Normalize(Vec3 v)
        {
            float frt = (float)Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
            if (frt == 0.0f)
            {
                return new Vec3(0, 0, 0);
            }
            else
            {
                return new Vec3(v.x / frt, v.y / frt, v.z / frt);
            }
        }

五、调用库

以上是通过自己计算得出结果,其实eigen库中有输入两个向量得出旋转矩阵的接口,非常简单。

Eigen::Matrix3d rotMatrix;
    Eigen::Vector3d vectorBef(vectorBefore[0], vectorBefore[1], vectorBefore[2]);
    Eigen::Vector3d vectorAft(vectorAfter[0], vectorAfter[1], vectorAfter[2]);

    rotMatrix = Eigen::Quaterniond::FromTwoVectors(vectorBef, vectorAft).toRotationMatrix();

Original: https://www.cnblogs.com/Clark-Zhang/p/16495263.html
Author: 朔月の流光
Title: 根据两个向量计算它们之间的旋转矩阵

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/582746/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 【socket】基于Linux使用select上报温度–服务端

    select使用 * – select函数 – select流程图 – 服务端代码实现 select函数 select监视并等待多个文件描述符的…

    Linux 2023年6月13日
    078
  • linux安装Oracle11G

    1、Linux下以Oracle帐户进入Linux系统。 2、执行以下命令查看数据库监听器的状况: lsnrctl status 3、执行以下命令停止数据库监听器运行: lsnrct…

    Linux 2023年6月13日
    069
  • 添加SSH服务

    1、基于commit命令创建 1.1 启动容器 [root@master ~]# docker run -it ubuntu:18.04 bash #更&am…

    Linux 2023年6月13日
    078
  • Linux 系统安全加固经验总结

    本文为博主原创,转载请注明出处: 1. 禁止root密码登录 修改 /etc/ssh/sshd_config 中 允许root 用户登录 PermitRootLogin 的值改为 …

    Linux 2023年6月14日
    092
  • 性能测试—实施流程记录

    posted @2022-06-08 17:31 尼古丁·瘾 阅读(26 ) 评论() 编辑 Original: https://www.cnblogs.com/ngd-mzl/p…

    Linux 2023年6月8日
    0107
  • 面试复盘(1)

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Linux 2023年6月7日
    091
  • js笔记之switch-case

    switch 语句来选择要执行的多个代码块之一。switch 不能处理大于小于的 工作原理:首先设置表达式 n(通常是一个变量)。随后表达式的值会与结构中的每个 case 的值做比…

    Linux 2023年6月13日
    074
  • VMware vSphere 7 Update 3 下载

    请访问原文链接:https://sysin.org/blog/vmware-vsphere-7-u3/,查看最新版。原创作品,转载请保留出处。 vSphere 7 Update 3…

    Linux 2023年5月27日
    0101
  • docker安装redis

    Redis configuration file example. # Note that in order to read the configuration file, Red…

    Linux 2023年5月28日
    088
  • 【MQTT】使用MQTT.fx上报温度到腾讯云

    打开 腾讯云官网, 注册并登录. 2.登录之后点击右上角的控制台点进去 3.在搜索框[物联网通信],点击进入 4.点击创建新产品 5.选择普通产品,名称随便,选择密钥认证,选择js…

    Linux 2023年6月13日
    083
  • Linux与Windows文件同步

    本次采用的同步方式是rsync,Rsync是一款免费且强大的同步软件,可以镜像保存整个目录树和文件系统,同时保持原来文件的权限、时间、软硬链接。第一次同步时会复制全部内容,下次只传…

    Linux 2023年6月8日
    0116
  • Redis分布式锁实战

    背景 目前开发过程中,按照公司规范,需要依赖框架中的缓存组件。不得不说,做组件的大牛对CRUD操作的封装,连接池、缓存路由、缓存安全性的管控都处理的无可挑剔。但是有一个小问题,该组…

    Linux 2023年5月28日
    086
  • Redis 用的很溜,了解过它用的什么协议吗?

    我是风筝,公众号「古时的风筝」,一个兼具深度与广度的程序员鼓励师,一个本打算写诗却写起了代码的田园码农!文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白…

    Linux 2023年5月28日
    095
  • Question08-查询没学过”张三”老师授课的同学的信息

    * SELECT * FROM Student WHERE SID NOT IN ( SELECT DISTINCT Student.SID FROM Student , SC ,…

    Linux 2023年6月7日
    090
  • GDT表实现

    GDT是保护模式下的内存段登记表。 段界限计算 段界限用 20 个二进制位来表示。只不过此段界限只是个单位量,它的单位要么是字节,要么是 4K,这是由描述符中的G位来指 定的。由于…

    Linux 2023年6月7日
    075
  • 如何在CentOS 6.3上安装nslookup

    nslookup是bind-utils软件包的一部分。请注意,host、dig和nslookup也是bind工具的一部分。如果没有安装bind-utils包,当你尝试nslooku…

    Linux 2023年6月7日
    0105
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球