绕任一向量旋转矩阵计算思考与实现

news2024/11/29 6:34:27

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

问题提出

请添加图片描述

如图所示,在空间中有一向量A,问点O绕A方向逆时针旋转角度α的矩阵如何表示。

问题分析

问题化规

直接去构造一个矩阵是比较困难的。
我们知道绕X,Y,Z三个方向的旋转矩阵是可以直接给出的。分别如下。
角度根据右手定则绕各轴逆时针旋转θ

绕 X 轴表示为: X ( θ ) = [ 1 0 0 0 c o s θ − s i n θ 0 s i n θ c o s θ ] 绕X轴表示为:X(\theta)=\begin{bmatrix}1&0&0\\0&cos\theta&-sin\theta\\0&sin\theta&cos\theta\end{bmatrix} X轴表示为:X(θ)= 1000cosθsinθ0sinθcosθ

绕 Y 轴表示为: Y ( θ ) = [ c o s θ 0 s i n θ 0 1 0 - s i n θ 0 c o s θ ] 绕Y轴表示为:Y(\theta)=\begin{bmatrix}cos\theta&0&sin\theta\\0&1&0\\-sin\theta&0&cos\theta\end{bmatrix} Y轴表示为:Y(θ)= cosθ0sinθ010sinθ0cosθ

绕 Z 轴表示为: Z ( θ ) = [ c o s θ − s i n θ 0 s i n θ c o s θ 0 0 0 1 ] 绕Z轴表示为:Z(\theta)=\begin{bmatrix}cos\theta&-sin\theta&0\\sin\theta&cos\theta&0\\0&0&1\end{bmatrix} Z轴表示为:Z(θ)= cosθsinθ0sinθcosθ0001

一个直观的想法就是先把向量A转到与X轴相同的方向。
也就是沿着A与X叉乘方向旋转β,如图所示。

请添加图片描述

图中向量M分别与向量A,向量X垂直,可知向量M处于平面YOZ中。

设上述旋转为RM

那么O点最终结果可以表示如下

O ′ = R M − 1 ⋅ X ( α ) ⋅ R M ⋅ O O'=RM^{-1}\cdot X(\alpha) \cdot RM\cdot O O=RM1X(α)RMO

由于向量M并不与X,Y,Z轴中任意一轴平行,所以还是不好直接给出RM表达式。

但是向量M处于平面YOZ,可以行将向量M旋转到与Y轴平行,再按照上述同理操作。设旋转到Y轴矩阵为RY。

R M = R Y − 1 ⋅ Y ( − β ) ⋅ R Y RM=RY^{-1}\cdot Y(-\beta)\cdot RY RM=RY1Y(β)RY

= X ( − γ ) − 1 ⋅ Y ( − β ) ⋅ X ( − γ ) =X(- \gamma)^{-1}\cdot Y(-\beta)\cdot X(- \gamma) =X(γ)1Y(β)X(γ)

致此,所有旋转都转化成和X轴,Y轴相关的旋转。

求解过程

RY计算。

RY的作用是把M转到与Y轴相同位置。

M可以由A与X叉乘得到

设 M = ( 0 , M y , M z ) , 由于 M 处于 Y O Z 平面,可知 M x = 0 设M=(0, My, Mz), 由于M处于YOZ平面,可知Mx=0 M(0,My,Mz),由于M处于YOZ平面,可知Mx=0

请添加图片描述
由上图可以知

R Y = X ( − γ ) = X ( γ ) T RY=X(-\gamma)=X(\gamma)^T RY=X(γ)=X(γ)T

= [ 1 0 0 0 c o s γ − s i n γ 0 s i n γ c o s γ ] T =\begin{bmatrix}1&0&0\\0&cos\gamma&-sin\gamma\\0&sin\gamma&cos\gamma\end{bmatrix}^T = 1000cosγsinγ0sinγcosγ T

= [ 1 0 0 0 c o s γ s i n γ 0 - s i n γ c o s γ ] =\begin{bmatrix}1&0&0\\0&cos\gamma&sin\gamma\\0&-sin\gamma&cos\gamma\end{bmatrix} = 1000cosγsinγ0sinγcosγ

= [ 1 0 0 0 M y M z 0 - M z M y ] =\begin{bmatrix}1&0&0\\0&My&Mz\\0&-Mz&My\end{bmatrix} = 1000MyMz0MzMy

R Y − 1 = R Y T RY^{-1}=RY^T RY1=RYT

有了RY后,可以先将A乘上RY。这样A就会被旋转到平面ZOX上来。

A ′ = R Y ⋅ A = ( A x ′ , 0 , A z ′ ) A' = RY\cdot A = (Ax',0, Az') A=RYA=(Ax,0,Az)

同理,

R X = Y ( − β ) = Y ( β ) T RX=Y(-\beta) = Y(\beta)^T RX=Y(β)=Y(β)T

= [ c o s β 0 − s i n β 0 1 0 s i n β 0 c o s β ] = \begin{bmatrix}cos\beta&0&-sin\beta\\0&1&0\\sin\beta&0&cos\beta\end{bmatrix} = cosβ0sinβ010sinβ0cosβ

= [ A x ′ 0 A z ′ 0 1 0 - A z ′ 0 A x ′ ] = \begin{bmatrix}Ax'&0&Az'\\0&1&0\\-Az'&0&Ax'\end{bmatrix} = Ax0Az010Az0Ax

旋转后的P’

P ′ = R Y − 1 ⋅ R X − 1 ⋅ X ( α ) ⋅ R X ⋅ R Y ⋅ P P'=RY^{-1}\cdot RX^{-1}\cdot X(\alpha)\cdot RX\cdot RY\cdot P P=RY1RX1X(α)RXRYP

代码实现

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

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;
        }
        
        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;
        }

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

数据测试

测试代码链接点击前往

测试代码链接点击前往

测试代码链接点击前往

效果展示


往外的三条线分别是X,Y,Z中间那么是向量(1,1,1),红点是(0.5,0,0.5)
绿点是红点沿(1,1,1)逆时针转90度结果。


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

欢迎添加我的公众号,进群交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/166246.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自从我学会了Jenkins的自动构建,我再也没有每次都打包上传到服务器然后发布Java服务了

上次我们讲了使用Jenkins部署maven项目 工作两年半&#xff0c;终于学会了Jenkins部署Maven项目 这次我们来讲一下每次提交代码的时候Jenkins自动构建 我们使用的代码仓库是gitee 文章目录&#x1f3c3;第一步&#xff0c;我们在Jenkins中安装gitee插件&#x1f3c3;第二步&am…

Go语言并发编程及依赖管理

目录&#x1f9e1;并发编程GoroutineCSP(Communicating Sequential Processes)&#x1f9e1;依赖管理依赖演变依赖管理三要素&#x1f49f;这里是CS大白话专场&#xff0c;让枯燥的学习变得有趣&#xff01; &#x1f49f;没有对象不要怕&#xff0c;我们new一个出来&#xff0…

Linux (open、write、read、close、lseek、chmod、sync)操作文件的函数详解

目录 一、文件操作方式 二、Linux底层文件操作 1. open 2. write 3. read 4. close 5. lseek 6. chmod 7. sync、syncfs、fsync、fdatasync 三、 Linux 系统调用 四、总结 linux中&#xff0c;一切皆文件&#xff08;网络设备除外&#xff09; 硬件设备也“是”文件&a…

力扣刷题记录——507.完美数、509. 斐波那契数、520. 检测大写字母

本专栏主要记录力扣的刷题记录&#xff0c;备战蓝桥杯&#xff0c;供复盘和优化算法使用&#xff0c;也希望给大家带来帮助&#xff0c;博主是算法小白&#xff0c;希望各位大佬不要见笑&#xff0c;今天要分享的是——《507.完美数、509. 斐波那契数、520. 检测大写字母》。 目…

InfluxDB + Grafana计算成功率

文章目录方式一 借助Grafana的Transfrom方式二 Influx子查询Transfrom介绍建议针对每类Metric&#xff0c;使用一个Metric&#xff0c;增加success的tag区分成功还是失败。 方式一 借助Grafana的Transfrom 第一步&#xff1a;新建2个Query Query Total: SELECT sum("coun…

安科瑞电气火灾监控系统在春晓161#地块人防工程的设计与应用

安科瑞 华楠摘要&#xff1a;本文简述了电气火灾监控系统的组成原理&#xff0c;分析了电气火灾监控系统在应用中的设计依据和相关规范。通过安科瑞剩余电流式电气火灾监控系统在春晓161#地块人防工程电气火灾监控系统项目的实例介绍&#xff0c;阐述了电气火灾监控系统功能的实…

c语言实现扫雷(详细讲解)

本篇介绍,讲解如何使用c语言实现扫雷小游戏. 金句分享: ✨✨✨爱你所爱,行你所行✨✨✨ 目录前言:一、游戏设计思路介绍:效果展示二、游戏的分步讲解2.1、主函数测试区&#xff08;test.c&#xff09;基本构成2.2、游戏中函数实现区(game.c) (重点)2.21、雷盘的创建与初始化函…

centos8 Ambari-2.7.6.3+HDP-3.3.1离线安装详细教程(附安装包)

自2021年1月31日开始,所有Cloudera软件都需要有效的订阅,且订阅费昂贵。此外,CDH6和HDP3将是CDH和HDP的最后企业版本,原有企业版用户无法继续获取新的功能和性能提升。至2022年3月份,CDH/HDP全部停止服务(EoS),用户没办法获取售后支持。由于生产环境系统升级到centos8,…

linux 中 PCIE 中断映射机制

PCIE 中断映射机制 1、 PCIE 中有三种中断方式&#xff0c; MSI&#xff0c;MSI-X 和INTx PCIe总线继承了PCI总线的所有中断特性&#xff08;包括INTx和MSI/MSI-X&#xff09;&#xff0c;以兼容早期的一些PCI应用层软件。 PCI总线最早采用的中断机制是INTx&#xff0c;这是…

基于Flink+kafka实时告警

引出问题 项目使用告警系统的逻辑是将实时数据保存到本地数据库再使用定时任务做判断&#xff0c;然后产生告警数据。这种方式存在告警的延时实在是太高了。数据从产生到保存&#xff0c;从保存到判断都会存在时间差&#xff0c;按照保存数据定时5分钟一次&#xff0c;定时任务…

智慧水务能效管理平台在污水处理厂电气节能中的应用

摘要&#xff1a;污水处理属于高能耗行业&#xff0c;会消耗大量的电能、燃料和药剂等&#xff0c;高能耗不仅会提升污水处理成本&#xff0c;还会加剧能源危机。所以&#xff0c;本文首先探究了污水处理厂耗能的原因&#xff0c;分析了污水处理与节能降耗的关系&#xff0c;然…

MyBatis-Plus数据安全保护(加密解密)

项目创建POM依赖 <dependency><!--MyBatis-Plus 企业级模块--><groupId>com.baomidou</groupId><artifactId>mybatis-mate-starter</artifactId><version>1.2.8</version> </dependency> <!-- https://mvnrepository…

git commit 命令详解

文章目录前言1. git commit 介绍2. git commit 使用3. git commit -m4. git commit -am5. git commit --amend6. commit 多行提交信息7. commit 背后到底发生了什么前言 CSDN 只用来做博客主站文章的转载 博客主站&#xff1a;https://www.itqaq.com 下面地址路径可能会发生变…

Java---中间件---Redis的常见命令和客户端使用

Redis的常见命令和客户端使用1.初识Redis1.1.认识NoSQL1.1.1.结构化与非结构化1.1.2.关联和非关联1.1.3.查询方式1.1.4.事务1.1.5.总结1.2.认识Redis1.3.安装Redis1.3.1.依赖库1.3.2.上传安装包并解压1.3.3.启动1.3.4.默认启动1.3.5.指定配置启动1.3.6.开机自启1.4.Redis桌面客…

VulnHub2018_DeRPnStiNK靶机总结

VulnHub2018_DeRPnStiNK靶机渗透总结 靶机下载地址: https://download.vulnhub.com/derpnstink/VulnHub2018_DeRPnStiNK.ova https://www.dropbox.com/s/8jqor3tuc3jhe1w/VulnHub2018_DeRPnStiNK.ova?dl0 打开靶机,使用nmap扫描出靶机的ip和开放的所有端口 可以看到,靶机开放…

从零开始学习Linux

Linux Linux内核版本&#xff1a;Linux内核运维开发小组&#xff0c;源码在不开源 Linux发行版本&#xff1a;由各大互联网/软件公司定制&#xff0c;开源 一个内核版本是有多种多样的发行版本 Ubuntu&#xff1a;以强大的桌面应用为主&#xff0c;吸收不少Windows用户&…

Docker部署jeecgboot微服务使用记录

docker安装和基础命令 docker安装 docker安装详细步骤 Docker命令 #进入容器 sudo docker exec -it 775c7c9ee1e1 /bin/bash # docker中 启动所有的容器命令 docker start $(docker ps -a | awk { print $1} | tail -n 2) # docker中 关闭所有的容器命令 docker stop $(doc…

(黑马C++)L09 C++类型转换 异常 输入输出流

一、C类型转换 类型转换&#xff08;cast&#xff09;是将一种数据类型转换成另一种数据类型&#xff0c;一般情况下要尽量少的去使用类型转换&#xff0c;除非解决非常特殊的问题。 &#xff08;1&#xff09;静态转换&#xff08;static_cast&#xff09; static_cast使用…

联合证券|内外利好共振 今年A股可更乐观一点

在经历了开年首周的快速拉升后&#xff0c;上星期A股商场全体高位盘整。职业板块从普涨转为快速轮动&#xff0c;前期领涨的新能源及大消费主线均出现了必定程度的回撤&#xff0c;由金融、信创板块接力“领跑”。 展望后市&#xff0c;指数在盘整后能否持续上攻&#xff1f;外…

解决前后端分离Vue项目部署到服务器后出现的302重定向问题

解决前后端分离Vue项目部署到服务器后出现的302重定向问题问题描述问题原因定位问题解决方案校验修改效果相关阅读写在最后问题描述 最近发现自己开发的vue前后端分离项目因为使用了spring security 安全框架&#xff0c;即使在登录认证成功之后再调用一些正常的接口总是会莫名…