类 Rotation
- 所有已实现的接口:
-
Serializable
旋转可以用几种不同的数学实体表示(矩阵、轴和角、Cardan或Euler角、四元数)。该类提供了一个更高级的抽象,更加面向用户并隐藏了这些实现细节。好吧,对于好奇的人来说,我们在内部表示中使用四元数。用户可以从任何这些表示构建旋转,并且可以从Rotation
实例中检索任何这些表示(请参阅各种构造函数和getter)。此外,旋转还可以从一组向量及其映像隐式构建。
这意味着这个类可以用于将一种表示转换为另一种表示。例如,将旋转矩阵转换为一组Cardan角可以使用以下一行代码完成:
double[] angles = new Rotation(matrix, 1.0e-10).getAngles(RotationOrder.XYZ);
重点放在旋转的作用上,而不是其基础表示。一旦构建完成,无论其内部表示如何,旋转都是一个操作器,基本上将三维向量
转换为其他三维向量
。根据应用程序,这些向量的含义可能会有所不同,旋转的语义也会有所不同。
例如,在一个航天器姿态模拟工具中,用户通常会认为向量是固定的(例如地球方向),而框架会发生变化。旋转将向量在惯性框架中的坐标转换为卫星框架中相同向量的坐标。在这种情况下,旋转隐含地定义了两个框架之间的关系。
另一个例子可能是望远镜控制应用程序,其中旋转将静止时的瞄准方向转换为当望远镜指向感兴趣的对象时所需的观测方向。在这种情况下,旋转将静止时的方向在地心框架中转换为相同地心框架中的瞄准方向。这意味着在这种情况下,框架是固定的,而向量在移动。
在许多情况下,这两种方法会结合在一起。在我们的望远镜示例中,我们可能还需要将地心框架中的观测方向转换为惯性框架中的观测方向,考虑到天文台位置和地球旋转,这本质上是第一种方法的应用。
这些示例表明,旋转是用户希望它成为的样子。该类不会将用户引向特定的定义,因此不提供像projectVectorIntoDestinationFrame
或computeTransformedDirection
这样的方法。它提供更简单和更通用的方法:applyTo(Vector3D)
和applyInverseTo(Vector3D)
。
由于旋转基本上是一个矢量运算符,因此可以将多个旋转组合在一起,复合操作r = r1 o r2
(这意味着对于每个向量u
,r(u) = r1(r2(u))
)也是一个旋转。因此,我们可以认为除了向量之外,旋转也可以应用于其他旋转(或自身)。根据我们之前的符号,我们会说我们可以将r1
应用于r2
,而我们得到的结果是r = r1 o r2
。为此,该类提供了方法:applyTo(Rotation)
和applyInverseTo(Rotation)
。
旋转保证是不可变对象。
- 另请参阅:
-
字段概要
-
构造器概要
构造器说明Rotation
(double[][] m, double threshold) 从3X3矩阵构建旋转。Rotation
(double q0, double q1, double q2, double q3, boolean needsNormalization) 从四元数坐标构建旋转。Rotation
(RotationOrder order, RotationConvention convention, double alpha1, double alpha2, double alpha3) 从三个Cardan或Euler基本旋转构建旋转。Rotation
(Vector3D axis, double angle, RotationConvention convention) 从轴和角度构建旋转。构建将一个向量转换为另一个向量的旋转之一。构建将一对向量转换为另一对向量的旋转。 -
方法概要
修饰符和类型方法说明void
applyInverseTo
(double[] in, double[] out) 将旋转的逆应用于存储在数组中的向量。将实例的逆应用于另一个旋转。将旋转的逆应用于向量。void
applyTo
(double[] in, double[] out) 将旋转应用于存储在数组中的向量。将实例应用于另一个旋转。将旋转应用于向量。compose
(Rotation r, RotationConvention convention) 将实例与另一个旋转组合。composeInverse
(Rotation r, RotationConvention convention) 将实例的逆与另一个旋转组合。static double
计算两个旋转之间的距离。double
getAngle()
获取旋转的角度。double[]
getAngles
(RotationOrder order, RotationConvention convention) 获取与实例对应的Cardan或Euler角。getAxis
(RotationConvention convention) 获取旋转的归一化轴。double[][]
获取与实例对应的3X3矩阵double
getQ0()
获取四元数的标量坐标。double
getQ1()
获取四元数的矢量部分的第一个坐标。double
getQ2()
获取四元数的矢量部分的第二个坐标。double
getQ3()
获取四元数的矢量部分的第三个坐标。revert()
反转旋转。
-
字段详细资料
-
IDENTITY
单位旋转。
-
-
构造器详细资料
-
Rotation
public Rotation(double q0, double q1, double q2, double q3, boolean needsNormalization) 从四元数坐标构建旋转。可以从一个归一化四元数构建旋转,即一个满足q02 + q12 + q22 + q32 = 1的四元数。如果四元数未归一化,则构造函数可以在预处理步骤中对其进行归一化。
请注意,一些约定将四元数的标量部分放在第4个分量,矢量部分放在前三个分量。这不是我们的约定。我们将标量部分放在第一个分量。
- 参数:
-
q0
- 四元数的标量部分 -
q1
- 四元数的矢量部分的第一个坐标 -
q2
- 四元数的矢量部分的第二个坐标 -
q3
- 四元数的矢量部分的第三个坐标 -
needsNormalization
- 如果为true,则认为坐标未归一化,在使用之前执行归一化预处理步骤
-
Rotation
public Rotation(Vector3D axis, double angle, RotationConvention convention) throws MathIllegalArgumentException 从轴和角度构建旋转。- 参数:
-
axis
- 绕其旋转的轴 -
angle
- 旋转角度 -
convention
- 用于角度语义的约定 - 抛出:
-
MathIllegalArgumentException
- 如果轴的范数为零
-
Rotation
从3X3矩阵构建旋转。旋转矩阵是正交矩阵,即单位矩阵(其满足m.mT = I的矩阵)具有实系数。单位矩阵的行列式模为1,在正交3X3矩阵中,只有行列式为正(+1)的矩阵是旋转矩阵。
当一个旋转由一个具有截断值的矩阵定义时(通常当它从技术说明中提取时,只有四到五个有效数字可用),该矩阵不再是正交的。此构造函数通过使用给定矩阵的副本并对副本应用校正来完善其正交性来透明地处理此情况。如果所需校正的Frobenius范数超过给定阈值,则认为该矩阵离真实旋转矩阵太远,并抛出异常。
- 参数:
-
m
- 旋转矩阵 -
threshold
- 迭代正交性校正的收敛阈值(当校正的Frobenius范数两个步骤之间的差小于此阈值时达到收敛) - 抛出:
-
MathIllegalArgumentException
- 如果矩阵不是3X3矩阵,或者无法使用给定阈值将其转换为正交矩阵,或者结果正交矩阵的行列式为负
-
Rotation
构建将一对向量转换为另一对向量的旋转。除了可能的比例因子外,如果该实例应用于一对(u1, u2),它将产生一对(v1, v2)。
如果u1和u2之间的角度分离与v1和v2之间的角度分离不同,则将使用校正后的v'2而不是v2,校正后的向量将位于(±v1,+v2)半平面。
- 参数:
-
u1
- 原始向量对的第一个向量 -
u2
- 原始向量对的第二个向量 -
v1
- 旋转后u1的期望图像 -
v2
- 旋转后u2的期望图像 - 抛出:
-
MathRuntimeException
- 如果一个向量的范数为零,或者一对向量是退化的(即一对向量共线)
-
Rotation
构建将一个向量转换为另一个向量的旋转之一。除了可能的比例因子外,如果该实例应用于向量u,它将产生向量v。有无限多个这样的旋转,此构造函数选择与最小关联角度的旋转(即轴与(u,v)平面正交的旋转)。如果u和v共线,则选择任意旋转轴。
- 参数:
-
u
- 原始向量 -
v
- 旋转后u的期望图像 - 抛出:
-
MathRuntimeException
- 如果一个向量的范数为零
-
Rotation
public Rotation(RotationOrder order, RotationConvention convention, double alpha1, double alpha2, double alpha3) 从三个Cardan或Euler基本旋转构建旋转。Cardan旋转是绕规范轴X、Y和Z的三次连续旋转,每个轴只使用一次。有6组这样的旋转(XYZ、XZY、YXZ、YZX、ZXY和ZYX)。Euler旋转是绕规范轴X、Y和Z的三次连续旋转,第一次和最后一次旋转是围绕同一轴进行的。有6组这样的旋转(XYX、XZX、YXY、YZY、ZXZ和ZYZ),最流行的是ZXZ。
请注意,许多人通常将Euler角的术语用于实际上是Cardan角的情况(这种混淆在航空航天业特别普遍,其中横滚、俯仰和偏航角经常错误地标记为Euler角)。
- 参数:
-
order
- 要组合的旋转顺序,从左到右(即我们将使用r1.compose(r2.compose(r3, convention), convention)
) -
convention
- 角度语义使用的约定 -
alpha1
- 第一个基本旋转的角度 -
alpha2
- 第二个基本旋转的角度 -
alpha3
- 第三个基本旋转的角度
-
-
方法详细资料
-
revert
反转旋转。构建一个反转另一个旋转效果的旋转。这意味着如果r(u) = v,则r.revert(v) = u。实例不会改变。- 返回:
- 一个新的旋转,其效果与实例的效果相反
-
getQ0
public double getQ0()获取四元数的标量坐标。- 返回:
- 四元数的标量坐标
-
getQ1
public double getQ1()获取四元数的矢量部分的第一个坐标。- 返回:
- 四元数的矢量部分的第一个坐标
-
getQ2
public double getQ2()获取四元数的矢量部分的第二个坐标。- 返回:
- 四元数的矢量部分的第二个坐标
-
getQ3
public double getQ3()获取四元数的矢量部分的第三个坐标。- 返回:
- 四元数的矢量部分的第三个坐标
-
getAxis
获取旋转的归一化轴。请注意,由于
getAngle()
始终返回0到π之间的角度,更改约定会更改轴的方向,而不是角度的符号。- 参数:
-
convention
- 角度语义使用的约定 - 返回:
- 旋转的归一化轴
- 另请参阅:
-
getAngle
public double getAngle()获取旋转的角度。- 返回:
- 旋转的角度(在0到π之间)
- 另请参阅:
-
getAngles
public double[] getAngles(RotationOrder order, RotationConvention convention) throws MathIllegalStateException 获取与实例对应的Cardan或Euler角。方程表明每个旋转可以由Cardan或Euler角集的两个不同值定义。例如,如果使用Cardan角,由角度a1、a2和a3定义的旋转与由角度π + a1、π - a2和π + a3定义的旋转相同。此方法实现以下任意选择:
- 对于Cardan角,所选集是第二个角度在-π/2到π/2之间(即其余弦为正)的集合,
- 对于Euler角,所选集是第二个角度在0到π之间(即其正弦为正)的集合。
Cardan和Euler角有一个非常令人失望的缺点:它们都有奇点。这意味着如果实例太接近给定旋转顺序对应的奇点,将无法检索角度。对于Cardan角,这通常称为万向节锁定。无法防止这种情况发生,这是Cardan和Euler表示的固有问题(但不是旋转本身的问题,旋转本身是完全定义的)。对于Cardan角,当第二个角度接近-π/2或+π/2时会出现奇点,对于Euler角,当第二个角度接近0或π时会出现奇点,这意味着对于Euler角,单位旋转始终对应奇点!
- 参数:
-
order
- 要使用的旋转顺序 -
convention
- 角度语义使用的约定 - 返回:
- 三个角度的数组,按照指定的顺序
- 抛出:
-
MathIllegalStateException
- 如果旋转对指定的角度集是奇异的
-
getMatrix
public double[][] getMatrix()获取与实例对应的3X3矩阵- 返回:
- 与实例对应的矩阵
-
applyTo
将旋转应用于向量。- 参数:
-
u
- 要应用旋转的向量 - 返回:
- 一个新的向量,是旋转后u的图像
-
applyTo
public void applyTo(double[] in, double[] out) 将旋转应用于存储在数组中的向量。- 参数:
-
in
- 一个包含三个项目的数组,存储要旋转的向量 -
out
- 一个包含三个项目的数组,用于放置结果(可以是与in相同的数组)
-
applyInverseTo
将旋转的逆应用于向量。- 参数:
-
u
- 要应用旋转的逆的向量 - 返回:
- 一个新的向量,使得u是旋转的图像
-
applyInverseTo
public void applyInverseTo(double[] in, double[] out) 将旋转的逆应用于存储在数组中的向量。- 参数:
-
in
- 一个包含三个项目的数组,存储要旋转的向量 -
out
- 一个包含三个项目的数组,用于放置结果(可以是与in相同的数组)
-
applyTo
将实例应用于另一个旋转。- 参数:
-
r
- 要应用旋转的旋转 - 返回:
- 一个新的旋转,是实例与r的组合
-
compose
与另一个旋转实例进行组合。如果旋转组合的语义对应于
矢量运算符
约定,将实例应用于旋转是按照以下规则计算组合的顺序:设u
为任意矢量,v
为r1
作用于u
的图像(即r1.applyTo(u) = v
)。设w
为旋转r2
作用于v
的图像(即r2.applyTo(v) = w
)。那么w = comp.applyTo(u)
,其中comp = r2.compose(r1, RotationConvention.VECTOR_OPERATOR)
。如果旋转组合的语义对应于
框架变换
约定,应用顺序将被颠倒。因此,保持所有r1
、r2
、u
、v
、w
和comp
的确切含义与上述相同,comp
也可以计算为comp = r1.compose(r2, RotationConvention.FRAME_TRANSFORM)
。- 参数:
-
r
- 要应用旋转的旋转 -
convention
- 用于角度语义的约定 - 返回:
- 一个新的旋转,是r与实例的组合
-
applyInverseTo
将实例的逆应用于另一个旋转。调用此方法等效于调用
composeInverse(r, RotationConvention.VECTOR_OPERATOR)
。- 参数:
-
r
- 要应用旋转的旋转 - 返回:
- 一个新的旋转,是r与实例的逆的组合
-
composeInverse
将实例的逆与另一个旋转组合。如果旋转组合的语义对应于
矢量运算符
约定,将实例的逆应用于旋转是按照以下规则计算组合的顺序:设u
为任意矢量,v
为r1
作用于u
的图像(即r1.applyTo(u) = v
)。设w
为v
的逆图像,通过r2
(即r2.applyInverseTo(v) = w
)。那么w = comp.applyTo(u)
,其中comp = r2.composeInverse(r1)
。如果旋转组合的语义对应于
框架变换
约定,应用顺序将被颠倒,这意味着将反转最内部的旋转。因此,保持所有r1
、r2
、u
、v
、w
和comp
的确切含义与上述相同,comp
也可以计算为comp = r1.revert().composeInverse(r2.revert(), RotationConvention.FRAME_TRANSFORM)
。- 参数:
-
r
- 要应用旋转的旋转 -
convention
- 用于角度语义的约定 - 返回:
- 一个新的旋转,是r与实例的逆的组合
-
distance
计算两个旋转之间的距离。这里的距离是一种检查两个旋转是否几乎相似(即它们以相同方式转换矢量)或非常不同的方法。在数学上,它被定义为前置到其中一个旋转的旋转r的角度:\(r_1(r) = r_2\)
这个距离是介于0和π之间的角度。它的值是r1(v)和r2(v)之间的所有可能矢量v的弧度角的最小可能上界。对于某些v,这个上界是达到的。如果两个旋转完全相同,则距离等于0。
比较两个旋转应该始终使用这个值,而不是例如比较四元数的分量。它更加稳定,并且具有几何意义。此外,比较四元数分量是容易出错的,因为例如四元数(0.36, 0.48, -0.48, -0.64)和(-0.36, -0.48, 0.48, 0.64)表示完全相同的旋转,尽管它们的分量不同(它们是完全相反的)。
- 参数:
-
r1
- 第一个旋转 -
r2
- 第二个旋转 - 返回:
- r1和r2之间的距离
-