方位

方位

表示方位的方法有三种,分别为矩阵,欧拉角,四元数表示法。

描述方位必须要有一个参照方位,如果没有参照方位,矩阵,欧拉角和四元数表示法只可以代表一种角位移

方位其实就是在原方位上的旋转,那怎么样确定旋转的正负方向呢?

在左手坐标系中,从旋转轴的正方向望向原点,顺时针为正方向,逆时针为负方向;在右手坐标系中则相反,即逆时针为正方向,顺时针为负方向。

本文使用左手坐标系。

一。矩阵

表示角位移的矩阵其实就是旋转矩阵,此矩阵为绕某个旋转轴旋转。

图形API(如OPENGLDX都是用矩阵来表示方位)。

用矩阵表示角位移需要存放9个数(如果用4X4矩阵则是16个数),占用内存大。

矩阵表示法的优缺点详细说明见(p142)

二.欧拉角

欧拉角用三个数表示角位移,分别为heading,pitch,bank,这三个数都是角度值,heading表示绕物体坐标系的Y轴旋转的角度,picthX轴,bankZ轴。旋转顺序其实是无关紧要的,我们一般就按heading->pitch->bank顺序操作,本文所提到的欧拉角都是使用这种表示方法和旋转顺序。

由于角度描述和旋转顺序的多样性导致了表示同一方位的欧拉角表述的不唯一性,为了排除这种不唯一性,我们将headingbank限制在+180-180度之间,pitch限制在+90-90度之间。

欧拉角有一个有趣的问题,当pitch+90-90度时,将导致heading,bank的旋转轴相同(注意,heading,bank表示绕物体坐标系的轴,而不是原坐标系),称做万向锁,也叫做万向节。这将导致另外一种别名问题,由于heading,bank的旋转轴相同,它们可以相互抵消或相加,而最终结果是可以只用headingbank一个旋转就可以了。为此,我们规定,当picth+90-90度时,我们用heading完成竖直轴的旋转,bank定为0。万向节还导致欧拉角描述方法丢失一个自由度,这就是著名的万向节死锁问题。

我们设A(φ,θ,ψ) heading=φ,pitch=θ,bank=ψ的方位,Pφ)为绕Y轴旋转φ个角度, Nφ,θ)为绕X轴旋转θ个角度,Rφ,ψ)为绕Z轴旋转ψ个角度。有如图的计算方式:

A(φ,ψ) = R(φ,ψ)N(φ,θ)P(φ)

解释为A的转换等于先绕Y轴旋转φ个角度,再绕X轴旋转θ个角度,最后绕Z轴旋转ψ个角度(从右到左的运算顺序)

有公式为:

(δφ + φ,ψ) = P(δφ)A(φ,ψ)

解释为物体在现有角位移(设为角位移A)上进行*转换等于在A的相应转换上加上*转换,如:物体在现有角位移A上再绕物体坐标系的Y轴旋转*个角度等于在AY轴转换中加上*个角度。在这里有个例外,当N(绕X轴的转换)为正或负90度时,我们丢失了一个旋转自由度,故上面三个等式均不成立,这就是万向节死锁的原因:当N为正或负90度时,我们不能再用原有方位+PNR转换来得出现有方位(即不能用连续的欧拉角来表示空间中连续的角位移)。

三.四元数

一个四元数包含一个标量和一个3D向量:

[w,v]

[w,( x,y,z)]

现在我们来复习一下复数,复数包含一个实部和虚部。复数(a,b)定义为复数a+bia称为实数,b为虚数,满足i的平方等于-1。共轭复数使虚部变负。

四元数扩展了复数系统,它使用三个虚部i,j,k,它们的关系如下:

i^2 = j^2 = k^2 = -1;

ij = k; ji = -k;

jk = I; kj = -I;

ki = j; ik = -j;

一个四元数[w,(x,z)] 定义为复数w+xi+yj+zk

四元数P被解释为角位移的轴——角对方式,旋转轴n和旋转角度θ并不直接存储在四元数中,但的确是在四元数中。

P = [cos(θ/2),sin(θ/2)n]

= [ cos(θ/2),(sin(θ/2) x,sin(θ/2)ny,sin(θ/2)nz) ]

我们试着将旋转角度θ+360度的N数倍,旋转轴不变,不会改变P所代表的角位移,但却使P变成了-P。故任意角位移都有两种四元数的表示方法,它们互相为负。

注:-p = [-cos(θ/2),-sin(θ/2)n]

= [-cos(θ/2),(-sin(θ/2)nx,-sin(θ/2)ny,-sin(θ/2)nz) ]

[1,0],[-1,0]表示单位角位移,旋转角度为0度或者360度的整数倍时没有角位移,旋转轴是无交紧要的。

四元数的叉乘效果和矩阵乘法差不多。

[w1 v1][w2 v2] = [w1w2-v1*v2 w1v2+w2v1+v2 X v1]

(w1 x1i y1j z1k)(w2 x2i y2j z2k)

= w1w2 + w1x2i + w1y2j +w1z2k +

x1w2i + x1x2i2 + x1y2ij + x1z2ik +

y1w2j + y1x2ji + y1y2j2 + y1z2jk +

z1w2k + z1x2ki + z1y2kj + z1z2k2

= w1w2 – x1x2 – y1y2 – z1z2 +

(w1x2 + x1w2 + y1z2 – z1y2)i +

(w1y2 + x1z2 + y1w2 – z1x2)j +

(w1z2 + x1y2 + z1w2 – y1x2)k

= [ w1w2 + x1x2 + y1y2 - z1z2

( w1x2 + x1w2 + y1z2 - z1y2

w1y2 + x1z2 + y1w2 - z1x2

w1z2 + x1y2 +z1w2 – y1x2) ]

四元数叉乘满足结合律不满足交换律。

我们用[0,z)] 代表三维空间中的q点,[cos(θ/2),(sin(θ/2)nx,sin(θ/2)nz) ] 代表四元素p,进行以下运算后

q1 = pqp-1

你会发现得到的结果是q点绕n轴旋转了θ度。我们试着进行多次旋转,先进行a旋转再进行b旋转得到

q1 = b(aqa-1)b-1,由于四元数叉乘满足结合率不满足交换率,

= (ba)q(a-1b-1),sans-serif;">由于a-1b-1 = (ba)-1

=(ba) q (ba)-1

先执行a旋转再b旋转等于ba叉乘所代表的单一旋转。

通过四元素的叉乘我们可以将多次旋转连接起来,不过最终得到的结果连接顺序是由后到前的。为了解决这个问题,我们可以将四元素叉乘代表旋转的标准q1 = pqp-1改为 q1 = p-1qp ,得出q1 = b-1(a-1qa)b = (ab)-1q(ab)。本文将采取这种非标准的计算方法。在本文中非特别说明,没有符号的ab代表的ab 的叉乘。

||P||表示四元数的模。公式:(P145), 表示角位移的四元数的模为1

四元数叉乘的模等于模的乘积:

||q X p|| = ||q|| * ||p||

四元数逆的叉乘等于相反顺序的叉乘的逆:

q-1 X p-1 = (p X q)-1

四元数共轭和复数一样使虚部变负,记为:

q* = [w,-v]

四元数的逆等于共轭除以模,记为:

q-1 = q*/||q||

四元数的差

四元数的差可以代表从一个方位到另一个方位的角位移。已知角位移a和角位移b,求它们之间的角位移t,由于方位x先旋转a再旋转t等于方位x旋转b à at = b。我们要求出t,如果a是标量,两边同时除以a就可得出t。但我们不可以直接除以四元数,不过我们可以乘以四元数的逆以得到相同的效果

a-1at = a-1b

t= a-1b

四元数点乘

在本文中,点乘用*表示,叉乘用X表示

q1*q2 = [w1 v1] * [w2 v2]

= w1*w2 + v1*v2

= [w1 (x1 y1 z1) ] * [w2 (x2 y2 z2) ]

= w1*w2 + x1*x2 + y1*y2 + z1*z2

像向量的点乘一样,四元数的点乘也是一个标量,且点乘结果的正负并不重要,因为

q1*q2 = - (q1* -q2)

q2-q2代表相同的角位移。

对于单位四元数a,b,有 -1 <= a*b <= 1

四元数点乘的几何意义是,点乘绝对值越大,代表这两个角位移越“相似,四元数的点乘也代表两个四元数夹角的cos值。推导过程如下:

设两个角位移ab,要求它们的夹角的cos值。四元数(角位移)自身只代表一种转换,它们的夹角是指某个方位x经过角位移a后的方位要和方位x经过角位移b后的方位相同必须经过的角位移t的旋转角度θ。四元数的差可以求出这个t = a-1b,我们要求出角度θ就不难了,因为t的实部代表cos(θ/2)。我们先求出t

t= a-1b

= a* xb

= [wa -va][wb vb]

= [wawb–(-va)*vb wavb-wbva+vb x (-va)]

我们已经求出t的实部为wawb+va*vb,这和点乘的定义是一样的,所以我们说“四元数的点乘代表两个四元数夹角的cos值”。

四元数指数,对数,标量乘运算

对数:

log q = log([cosЄ sinЄn])

= [ 0,sans-serif;">Єn ]

指数:

exp( q )

exp([ 0,sans-serif;">Єn ]) = [ cosЄ sinЄn ]

exp( log(q) ) = q

标量乘:

k[w,v] = [kw,kv]

四元数幂:

四元数能作为底数,记作 qt (不要和指数运算混淆,指数运算只接受一个四元数作为参数,而四元数求幂有两个参数 ---- 四元数和指数)。四元数求幂的意义类似于实数求幂。回忆一下,a0 = 1 a1 = aa为非零标量。当t0变到1时,at1a。四元数求幂有类似的结论:当t0变到1[1,0 ] q。从四元数的叉乘可以证明这一结果。

这对四元数求幂非常有用,因为它可以从角位移中抽取"一部分"。例如,四元数代表一个角位移,现在想要得到代表1/3这个角位移的四元数,可以这样计算:1/3

指数超出[0,1]范围外的几何行为和预期的一样(但有一个重要的注意事项)。例如,2代表的角位移是的两倍。假设代表绕x轴顺时针旋转30度,那么代表绕x轴顺时针旋转60度,-1/3代表绕x轴逆时针旋转10度。

上面提到的注意事项是,四元数表达角位移时使用最短圆弧,不能"绕圈"。继续上面的例子,4不是预期的绕x轴顺时针旋转240度,而是逆时针80度。显然,向一个方向旋转240度等价于向相反的方向旋转80度,都能得到正确的"最终结果"。但是,在此基础上的进一步运算,产生的就可能不是预期的结果了。例如,(q4)1/2不是 2,尽管我们感觉应该是这样。一般来说,凡是涉及到指数运算的代数公式,如(as)t = a(st),对四元数都不适用。

现在,我们已经理解四元数求幂可以为我们做什么了。让我们看看它的数学定义,四元数求幂定义在前一节讨论的"有用"运算上,定义如公式10.18

注意,对于标量求幂,也有类似结论:

四元数常被用于线性插值,因为四元数的线性插值是最平滑的。最著名的就是slerp插值。具体算法见(p154).

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强制返回为文本 -------------------------------- 数字类型的格式化 --------------------------------     固定格式参数:     General Number 普通数字,如可以用来去掉千位分隔号     format$("100,1
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办法, Format 或者FormatDateTime 竟然结果和系统设置的区域语言的日期和时间格式相关。意思是尽管你用诸如 Format(Now, "MM/dd/yyyy"),如果系统的设置格式区域语言的日期和时间格式分隔符是"-",那他还会显示为 MM-dd-yyyy     只有拼凑: <%response.write
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace My ‘全局错误处理,新的解决方案直接添加本ApplicationEvents.vb 到工程即可 ‘添加后还需要一个From用来显示错误。如果到这步还不会则需要先打好基础啦 ‘======================================================== ‘以下事件
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用的爽呀,这篇文章写与2011年,看来我以前没有认真去找这个方法呀。 https://blog.csdn.net/chzjxgd/article/details/6176325 金蝶K3 BOS的插件官方是用VB6编写的,如果  能用.Net下的语言工具开发BOS插件是一件很愉快的事情,其中缘由不言而喻,而本文则是个人首创,实现在了用V
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选中的单元格进行处理 Dim m As Range, tmpStr As String, s As String Dim x As Integer, y As Integer, subStr As String If MsgBox("确定要分列处理吗?请确定分列的数据会覆盖它后面的单元格!", _
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single) 2 Dim path As String, hash As String 3 For Each fil
  Imports MySql.Data.MySqlClient Public Class Form1 ‘ GLOBAL DECLARATIONS Dim conString As String = "Server=localhost;Database=net2;Uid=root;Pwd=123456;" Dim con As New MySqlConnection
‘導入命名空間 Imports ADODB Imports Microsoft.Office.Interop   Private Sub A1() Dim Sql As String Dim Cnn As New ADODB.Connection Dim Rs As New ADODB.Recordset Dim S As String   S = "Provider=OraOLEDB.Oracl
Imports System.IO Imports System.Threading Imports System.Diagnostics Public Class Form1 Dim A(254) As String    Function ping(ByVal IP As Integer) As String Dim IPAddress As String IPAddress = "10.0.
VB运行EXE程序,并等待其运行结束 参考:https://blog.csdn.net/useway/article/details/5494084 Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long Pr
今天碰到一个问题,登陆的时候,如果不需要验证手机号为空,则不去验证手机号 因为登陆的时候所有的验证信息都存放在一个数组里 Dim CheckUserInfo() As String ={UserBirthday, SecEmail, UserMob, UserSex, RealNameFirst, RealName, CheckCardID, CheckCardType, Contactemail
在VB6.0中,数据访问接口有三种: 1、ActiveX数据对象(ADO) 2、远程数据对象(RDO) 3、数据访问对象(DAO) 1.使用ADO(ActiveX Data Objec,ActiveX数据对象)连接SQL Server 1)使用ADO控件连接 使用ADO控件的ConnectionString属性就可以连接SQL Server,该属性包含一个由分号分隔的argument=value语
注:大家如果没有VB6.0的安装文件,可自行百度一下下载,一般文件大小在200M左右的均为完整版的软件,可以使用。   特别提示:安装此软件的时候最好退出360杀毒软件(包括360安全卫士,电脑管家等,如果电脑上有这些软件的话),因为现如今的360杀毒软件直接会对VB6.0软件误报,这样的话就可能会在安装过程中被误报阻止而导致安装失败,或者是安装后缺乏很多必须的组件(其它的杀毒软件或安全卫士之类的
Private Sub Form_Load() Call conndb End Sub Private Function conndb() Dim cn As New ADODB.Connection Dim rs As New ADODB.Recordset Dim strCn, sql As String Dim db_host As String Dim db_user As String
  PPSM06S70:  Add  moddate  EDITSPRINTJOB:  MAX(TO_CHAR(ETRN.MODDATE, ‘yyyy/mm/dd/HH24:MI AM‘)) ACTUAL_SHIPDATE   4.Test Scenario (1) :Query SQL Test DN:8016578337 SELECT CTRN.TKCTID TRUCK_ID,        
  沒有出現CrystalReportViewer時,須安裝CRforVS_13_0. 新增1個數據集,新增1個數據表,添加二列,列名要和資料庫名一樣. 修改目標Framework 修改app.config, <startup >改成<startup useLegacyV2RuntimeActivationPolicy ="true">  CrystalReport1.rpt增加數據庫專家 在表單
Imports System.Threading Imports System Public Class Form1 Dim th1, th2 As Thread Public Sub Method1() Dim i As Integer For i = 1 To 100 If Me.Label1.BackColor =
Friend Const PROCESS_ALL_ACCESS = &H1F0FFF = 2035711 Friend Const PROCESS_VM_READ = &H10 Friend Const PROCESS_VM_WRITE = &H20 Friend Const PAGE_READONLY = &H2 Friend Const PAGE_READWRITE = &H4 Friend
以下代码随手写的 并没有大量测试 效率也有待提升 如果需要C#的请自行转换 Function SplitBytes(Data As Byte(), Delimiter As Byte()) As List(Of Byte()) Dim i = 0 Dim List As New List(Of Byte()) Dim bytes As New
Imports System.Data.SqlClient Public Class Form1 REM Public conn1 As SqlConnection = New SqlConnection("server=.; Integrated Security=False;Initial Catalog= mydatabase1; User ID= sa;password")