3维空间旋转3维空间矩阵旋转及旋转变换

2023-05-16

本文将实现三维空间中的旋转和平移变换,即将三维空间中的一个向量(或者一个空间图形)移动到另一个位置。如下图所示:


如上图所示,由矢量一移动到矢量二。

三维空间中的移动可以分为旋转和平移。

设矢量一在坐标位置(X0,Y0,Z0) .目标矢量二在坐标位置(X,Y,Z)。

空间任意一个位置的向量移动到与Z轴位置(法失和起点值相同)可以拆分为两步。第一步是绕Z轴旋转到XZ平面,第二步是绕Y轴旋转到Z轴。可以参考如下链接:

其中,第一步绕Z轴旋转到XZ平面的旋转矩阵如下所示:




第二步,绕Y轴旋转时,Y的值为0,仅仅在XZ平面内作旋转。旋转矩阵如下:



那么由原点位置任意方向移动到与Z轴正向相同需要经过如下步骤:

(X0,Y0,Z0) = Ty (Tz *(X,Y, Z))

即(X0,Y0,Z0) = Ty Tz (X,Y, Z)

因为任意矢量先要绕Z轴旋转,再绕Y轴旋转 所以为TyTz

那么,现在要将在Z轴正向的矢量移动到空间任意位置 只需要将上式求逆即可

具体如下:

(X,Y, Z) =  (Ty Tz)^-1 (X0,Y0,Z0)


设空间任意向量法失归一化后表示为u v w

那么

</pre><pre name="code" class="cpp">    a1 = u/sqrt(u*u + v*v);
    a2 = v/sqrt(u*u + v*v);
    a3 = w/sqrt(u*u + v*v + w*w);
    a4 = sqrt(u*u + v*v) / sqrt(u*u + v*v + w*w);

    Tz = [ a1  a2  0
            -a2 a1  0
            0   0   1];
        
    Ty = [ a3   0   -a4
           0    1   0 
           a4   0   a3];

TyTz = [    a1*a3   a2*a3   -a4
                -a2     a1      0
                a1*a4   a2*a4   a3
        ];

所以Tz^-1*Ty^-1 = (TyTz)^-1 = (TyTz)^T(这里因为是单位正交矩阵,所以求逆等于求转置)

= [a1*a3   -a2   a1*a4
                a2*a3   a1   a2*a4
                -a4    0    a3]; 

最后利用公式即可得到旋转后的矩阵。即

(X,Y, Z) =  (Ty Tz)^-1 (X0,Y0,Z0)


实验验证:

定义空间任意位置圆心参数:

center = [3 4 5]';
normVec0 = [3 -5 -1];

radius = 1;
numPts0 = 100;

目标位置为:

center0 = [0 0 1]‘;

normVec = [0 0 1];

代码如下:

clear;close all;
center = [3 4 5]';
normVec0 = [3 -5 -1];
normVec0 = - normVec0 / sqrt(sum(normVec0.^2));
radius = 1;
numPts0 = 100;
normalVec = normVec0;
d = sqrt( sum(normalVec.^2) );
u = normalVec(1) / d;
v = normalVec(2) / d;
w = normalVec(3) / d;

a1 = u/sqrt(u*u + v*v);
a2 = v/sqrt(u*u + v*v);
a3 = w/sqrt(u*u + v*v + w*w);
a4 = sqrt(u*u + v*v) / sqrt(u*u + v*v + w*w);

Tz = [ a1  a2  0
    -a2 a1  0
    0   0   1];

Ty = [ a3   0   -a4
    0    1   0
    a4   0   a3];
invTransMat = Ty*Tz;
transMat = inv(invTransMat);

pi = 3.141592653;
theta = linspace(0, 2*pi, numPts0);

X = radius * cos(theta);
Y = radius * sin(theta);
Z = zeros(1, length(X));
%circlePts0 = bsxfun(@plus, [X; Y; Z], center);
circlePts0 = [X; Y; Z];
circlePts = bsxfun(@plus, transMat * [X; Y; Z], center);
figure;
plot3(circlePts0(1, :), circlePts0(2, :), circlePts0(3, :));grid on;
hold on;
plot3(circlePts(1, :), circlePts(2, :), circlePts(3, :));grid on;
hold on;
结果如下:

箭头是我自己加上去的:绘制箭头的参考代码如下:

function h = mArrow3(p1,p2,varargin)
%mArrow3 - plot a 3D arrow as patch object (cylinder+cone)
%
% syntax:   h = mArrow3(p1,p2)
%           h = mArrow3(p1,p2,'propertyName',propertyValue,...)
%
% with:     p1:         starting point
%           p2:         end point
%           properties: 'color':      color according to MATLAB specification
%                                     (see MATLAB help item 'ColorSpec')
%                       'stemWidth':  width of the line
%                       'tipWidth':   width of the cone                       
%
%           Additionally, you can specify any patch object properties. (For
%           example, you can make the arrow semitransparent by using
%           'facealpha'.)
%                       
% example1: h = mArrow3([0 0 0],[1 1 1])
%           (Draws an arrow from [0 0 0] to [1 1 1] with default properties.)
%
% example2: h = mArrow3([0 0 0],[1 1 1],'color','red','stemWidth',0.02,'facealpha',0.5)
%           (Draws a red semitransparent arrow with a stem width of 0.02 units.)
%
% hint:     use light to achieve 3D impression
%

propertyNames = {'edgeColor'};
propertyValues = {'none'};    

%% evaluate property specifications
for argno = 1:2:nargin-2
    switch varargin{argno}
        case 'color'
            propertyNames = {propertyNames{:},'facecolor'};
            propertyValues = {propertyValues{:},varargin{argno+1}};
        case 'stemWidth'
            if isreal(varargin{argno+1})
                stemWidth = varargin{argno+1};
            else
                warning('mArrow3:stemWidth','stemWidth must be a real number');
            end
        case 'tipWidth'
            if isreal(varargin{argno+1})
                tipWidth = varargin{argno+1};
            else
                warning('mArrow3:tipWidth','tipWidth must be a real number');
            end
        otherwise
            propertyNames = {propertyNames{:},varargin{argno}};
            propertyValues = {propertyValues{:},varargin{argno+1}};
    end
end            

%% default parameters
if ~exist('stemWidth','var')
    ax = axis;
    if numel(ax)==4
        stemWidth = norm(ax([2 4])-ax([1 3]))/300;
    elseif numel(ax)==6
        stemWidth = norm(ax([2 4 6])-ax([1 3 5]))/300;
    end
end
if ~exist('tipWidth','var')
    tipWidth = 3*stemWidth;
end
tipAngle = 22.5/180*pi;
tipLength = tipWidth/tan(tipAngle/2);
ppsc = 50;  % (points per small circle)
ppbc = 250; % (points per big circle)

%% ensure column vectors
p1 = p1(:);
p2 = p2(:);

%% basic lengths and vectors
x = (p2-p1)/norm(p2-p1); % (unit vector in arrow direction)
y = cross(x,[0;0;1]);    % (y and z are unit vectors orthogonal to arrow)
if norm(y)<0.1
    y = cross(x,[0;1;0]);
end
y = y/norm(y);
z = cross(x,y);
z = z/norm(z);

%% basic angles
theta = 0:2*pi/ppsc:2*pi; % (list of angles from 0 to 2*pi for small circle)
sintheta = sin(theta);
costheta = cos(theta);
upsilon = 0:2*pi/ppbc:2*pi; % (list of angles from 0 to 2*pi for big circle)
sinupsilon = sin(upsilon);
cosupsilon = cos(upsilon);

%% initialize face matrix
f = NaN([ppsc+ppbc+2 ppbc+1]);

%% normal arrow
if norm(p2-p1)>tipLength
    % vertices of the first stem circle
    for idx = 1:ppsc+1
        v(idx,:) = p1 + stemWidth*(sintheta(idx)*y + costheta(idx)*z);
    end
    % vertices of the second stem circle
    p3 = p2-tipLength*x;
    for idx = 1:ppsc+1
        v(ppsc+1+idx,:) = p3 + stemWidth*(sintheta(idx)*y + costheta(idx)*z);
    end
    % vertices of the tip circle
    for idx = 1:ppbc+1
        v(2*ppsc+2+idx,:) = p3 + tipWidth*(sinupsilon(idx)*y + cosupsilon(idx)*z);
    end
    % vertex of the tiptip
    v(2*ppsc+ppbc+4,:) = p2;

    % face of the stem circle
    f(1,1:ppsc+1) = 1:ppsc+1;
    % faces of the stem cylinder
    for idx = 1:ppsc
        f(1+idx,1:4) = [idx idx+1 ppsc+1+idx+1 ppsc+1+idx];
    end
    % face of the tip circle
    f(ppsc+2,:) = 2*ppsc+3:(2*ppsc+3)+ppbc;
    % faces of the tip cone
    for idx = 1:ppbc
        f(ppsc+2+idx,1:3) = [2*ppsc+2+idx 2*ppsc+2+idx+1 2*ppsc+ppbc+4];
    end

%% only cone v
else
    tipWidth = 2*sin(tipAngle/2)*norm(p2-p1);
    % vertices of the tip circle
    for idx = 1:ppbc+1
        v(idx,:) = p1 + tipWidth*(sinupsilon(idx)*y + cosupsilon(idx)*z);
    end
    % vertex of the tiptip
    v(ppbc+2,:) = p2;
    % face of the tip circle
    f(1,:) = 1:ppbc+1;
    % faces of the tip cone
    for idx = 1:ppbc
        f(1+idx,1:3) = [idx idx+1 ppbc+2];
    end
end

%% draw
fv.faces = f;
fv.vertices = v;
h = patch(fv);
for propno = 1:numel(propertyNames)
    try
        set(h,propertyNames{propno},propertyValues{propno});
    catch
        disp(lasterr)
    end
end




本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

3维空间旋转3维空间矩阵旋转及旋转变换 的相关文章

  • 我的2016--"狗血"

    偶然看到了CSDN的 我的2016 主题征文活动 xff0c 突然感慨一番 xff0c 今年又快结束了 xff0c 而我这一年的经历 xff0c 可以浓缩为两个字 xff1a 狗血 然而 xff0c 我能用上如此不羁的词汇 xff0c 并未
  • 华为OD机试 - 买卖股票的最佳时机(Java)

    一 题目描述 给定一个数组 prices xff0c 它的第 i 个元素 prices i 表示一支给定股票第 i 天的价格 你只能选择 某一天 买入这只股票 xff0c 并选择在 未来的某一个不同的日子 卖出该股票 设计一个算法来计算你所
  • Linux下安装、配置、启动Apache

    环境 Centos 6 5 64位操作系统 安装Apache前准备 xff1a 1 检查该环境中是否已经存在httpd服务的配置文件 xff0c 默认存储路径 xff1a etc httpd httpd conf xff08 这是cento
  • 我从来没有得到过你,却好像已经失去了你千万次。

    为什么从来没有得到的东西 xff0c 也会让人有一种失去的感觉 xff1f 如题 xff01 xff01
  • power yourself

    1 不要做繁琐的计划 2 远离魔鬼 躲避诱惑 3 保持早睡早起的习惯 4 记录自己的成长轨迹 5 选择性离开网络世界
  • 希望余生尽早开始

    我爱你在暖和的天气感冒 我爱你用一小时来点菜 我爱你皱着眉头看我 好像我是疯子一样 我爱跟你分别后 仍然萦绕不散的余香 我想在睡前和你聊天 我来这 并不是因为我寂寞 也不是因为今天是除夕 是因为发现 如果你想要与某人共度余生 那你就会希望余
  • 又一年--在深圳

    一晃再晃 xff1b 一拖再拖 xff1b 我还是独自一个人奋战 xff0c 在这座繁华都市 严重的错觉就是 xff0c 总以为自己不想加班 xff0c 却发现只有加班的日子才过的充实 xff0c 也许事不知道业余时间该干嘛 这一年 xff
  • Debian下安装配置fcitx

    本人新装Debian7 LXDE桌面 xff0c 下面介绍一下安装配置fcitx的步骤 在此之前 xff0c 需要先保证locale的中文支持 xff1a 1 locale a xff0c 得到若干语言编码组合 xff0c 其中需要有zh
  • ROS: catkin_make/catkin_make_isolated/catkin build/colcon的区别

    1 catkin make catkin make 是第一个构建catkin工作区的脚本 xff0c 因此在许多教程中使用 它有几个缺点 xff08 需要包中的非标准逻辑来声明跨包目标依赖关系 xff09 和限制 xff08 不能处理普通的
  • 关于Segmentation fault (core dumped)几个简单问题

    有的程序可以通过编译 xff0c 但在运行时会出现Segment fault 段错误 这通常都是指针错误引起的 但这不像编译错误一样会提示到文件一行 xff0c 而是没有任何信息 一种办法是用gdb的step 一步一步寻找 但要step一个
  • CUDA C 编程指南

    CUDA C Programming Guide CUDA C 编程指南 导读 田子宸 浙大水硕在读 184 人 赞同了该文章
  • 2014华为校招机试高级题——if语法中的括号判断

    http blog csdn net wy4649 article details 11725073 package com huawei job import java util ArrayList import java util Sc
  • MySQL插入数据时报错Cause: java.sql.SQLException: #HY000

    造成这个错误的原因是数据库中有字段要求不能为空 xff0c 但insert语句中没有提供该字段的数据
  • 操作系统经典书籍推荐

    推荐原则 xff1a 宁缺勿滥 xff0c 决不混进糟粕 好书不一定对所有人都合适 xff0c 但对于它的目标读者群来说 xff0c 一定是好书 选书原则 xff1a 有国外的 xff0c 不看国产的 有原版的 xff0c 不看翻译的 看大
  • 英特尔T265 通过Python API获得位置(姿态)数据

    如果你想在树莓派或者jetson nano等嵌入式设备上使用Python API获得T265的数据 xff0c 需要编译pyrealsense2 jetson nano的安装可以参考这篇文章 xff1a jetson nano 编译pyre
  • 英特尔 t265 保存地图 (Python API)

    保存地图 span class token keyword import span pyrealsense2 span class token keyword as span rs span class token keyword impo
  • 车辆控制知识总结(一):LQR算法

    目录 1 LQR简介 2 现代控制理论基础 2 1 状态空间描述 2 2 线性定常系统的状态空间描述框图 2 3 线性系统连续系统的反馈控制 2 31 全状态反馈控制器 3 LQR设计控制器的方法 3 1 什么是二次型 3 3 连续时间下的
  • VMware安装centos 8无法连接外网处理过程

    使用VMware安装centos 8之后发现火狐无法打开百度 xff0c 另外一台ubuntu的虚拟机却可以上百度 对比之后发现问题如下 unbuntu的网卡信息 xff1a centos 8的网卡信息 xff1a 这里很容易发现unbun
  • input输入框、select下拉框在安卓与ios上的兼容性问题

    一 input输入框 在平常做移动端项目时 xff0c 如果不注意的话 xff0c 在ios系统上经常会出现这种问题 xff0c 点击输入框 xff0c 输入框获取焦点 xff0c 此时 苹果手机页面会自动放大 xff0c 而安卓手机不会出
  • WSL2初体验之使用 docker版 Ubuntu 18.04,VNC远程控制

    一 前言 以前用 Oracle VM VirtualBox xff0c 玩 CentOS 7 xff0c 时不时就卡一些 xff0c 而且还不流畅 我喜欢平滑顺畅完美 xff1b 无意中发现了 windows WSL2发布了 xff0c 感

随机推荐

  • 友善串口调试助手

    友善串口调试助手是一款功能十分强大的串口调试工具 xff0c 该软件能够让用户自定义发送文本 保存数据 识别端口等 xff0c 而且还兼容多种Windows系统win10 win7 xp xff0c 能够支持常用的50 256000bps波
  • Struts Action的execute方法不执行问题

    学习了SpringMVC xff0c 又想去探究一下Struts的奥秘 xff0c 是否和SpringMVC有什么异同之处 xff1f 于是 xff0c 动手编写了一个非常简单的demo程序 xff0c 但是在写的过程中 xff0c 发现页
  • JPress开源框架的安装过程 Maven工程导入MyEclipse并运行

    1 点击Jpress下载链接 https github com JpressProjects jpress 下载源码压缩包 xff0c 解压 2 复制解压后的工程到MyEclipse的工作空间中 3 点击MyEclipse gt File
  • Neutron OVS Bridge 连接方式 (veth pair / ovs peer) 的选型和性能测试

    概述 Neutron 的桥的连接从Juno开始使用了ovs peer代替veth pair作为默认的网桥连接方式 xff0c 并宣称有性能方面的提升 xff08 commit xff09 同时在配置文件 xff08 etc neutron
  • JPress安装

    安装完成后数据库中就会生成数据表
  • jQuery LigerUI 使用教程

    首页引入样式文件和js文件 xff1a lt link href 61 34 css ligerui all css 34 rel 61 34 stylesheet 34 type 61 34 text css 34 gt lt jquer
  • 依然迷茫的2016

    2016 xff0c 虽然毕业半年了 xff0c 但自己依然显得稚嫩 xff0c 没有褪去学生时代的幼稚 刚跨完年的我居然马上被骗子盯上了 xff0c 真是非常地不幸 xff0c 俗话说 xff0c 开门红 xff0c 我却倒霉来个开门霉
  • myeclipse部署tomcat问题

    MyEclipse部署tomcat时出现 xff1a Deployment is out of date due to changes in the underlying project contents You 39 ll need to
  • 关于逻辑分区和主分区的困惑

    原文链接 xff1a http www chiphell com thread 556678 1 1 html 问题 xff1a 我新配的机器 xff0c ssd 128g完全用于装系统 xff0c hdd用于存储 xff0c 我是在装完系
  • opencv实现几幅图像拼接成一整幅大图

    开始尝试merge函数 xff0c 具体如下 xff1a 定义四个矩阵A B C D 得到矩阵combine span style font size 18px include lt iostream gt include lt core
  • Python安装时import matplotlib.pyplot as plt报错

    安装matplotlib的时候可能会出现输入import matplotlib pyplot as plt出现报错的现象 xff0c 如下图所示 xff1a gt gt gt import matplotlib gt gt gt impor
  • 回文数和回文素数

    34 回文数 34 是一种数字 如 xff1a 98789 这个数字正读是98789 倒读也是98789 正读倒读一样 xff0c 所以这个数字就是回文数 1千以内 在自然数中 xff0c 最小的回文数是0 xff0c 其次是1 2 3 4
  • pragma pack对齐方式详细介绍

    为了加快读写数据的速度 xff0c 编译器采用数据对齐的方式来为每一个结构体分配空间 写在开头 本文有自己的原创也有转载的博文 xff0c 转载的部分一一列出来 xff0c 可能不全请见谅这里这里这里这里等等 更详细的解说 xff1a 在用
  • Qt学习笔记——打开并显示图片

    使用控件QLabel mainwindow h ifndef MAINWINDOW H define MAINWINDOW H include lt QMainWindow gt include lt QFileDialog gt incl
  • 可调恒流驱动LED电路分析

    https www icxbk com article detail aid 61 884 常规使用的pwm调亮度不仅会导致频闪 xff0c 而且在长时间使用的时候 xff0c 有损坏led的风险 xff0c 所以这次设计了一个恒流调亮度电
  • 如何在雷电模拟器里使用YiLu代理的动态ip?

    1在易路 程序 页面里随意添加一个应用 xff0c 请不要添加 雷电 到YiLu程序里 xff1b 2 YiLu设置 xff1a 点击YiLu 设置 页面 xff1b 选择 YiLu便携代理引擎 xff1b 选择 仅代理YiLu程序选项卡中
  • Freeman链码,差分码,归一化链码,归一化差分码

    Freeman链码是指用曲线起始点的坐标和边界点方向代码来描述曲线或边界的方法 xff0c 常被用来在图像处理 计算机图形学 模式识别等领域中表示曲线和区域边界 它是一种边界的编码表示法 xff0c 用边界方向作为编码依据 xff0c 为简
  • Matlab关联m文件与m文件关联设置

    MATLAB安装后经常出现m文件不能关联到matlab打开 xff0c 很烦恼 网上有一些设置教程 xff0c 比如 xff1a 链接一 按照链接方式一方式二设置后出现报错 修改注册表亦没用 下面链接 链接二 链接三 链接四 都没有效果 代
  • 图像处理形态学椭圆形模板结构元素的设计与实现

    在图像处理中 xff0c 经常要用到形态学操作 xff0c 形态学操作中的结构元素有很多 xff0c 如点结构 十字架结构 圆结构 矩形结构 椭圆形结构等等 本文将介绍椭圆形结构的实现 主要结合OpenCV实现 具体如下 xff1a inc
  • 3维空间旋转3维空间矩阵旋转及旋转变换

    本文将实现三维空间中的旋转和平移变换 xff0c 即将三维空间中的一个向量 或者一个空间图形 移动到另一个位置 如下图所示 xff1a 如上图所示 xff0c 由矢量一移动到矢量二 三维空间中的移动可以分为旋转和平移 设矢量一在坐标位置 X