如何使用4D转子。

5
我正在尝试创建一个类似于Miegakure的4D环境。
我在理解如何表示旋转方面遇到了困难。Miegakure的创作者写了一篇小文章,解释了他是如何创建一个用于4D旋转的类的。 http://marctenbosch.com/news/2011/05/4d-rotations-and-the-4d-equivalent-of-quaternions/ 我该如何实现这个类的函数?特别是旋转向量和其他旋转体以及获取逆的函数?
我会很感激一些伪代码示例。
非常感谢任何愿意回答的人。

他不是已经提供了实现吗? - meowgoesthedog
@spug 我没有看到任何...那些只是标题,但我懒得去挖掘那里的档案... - Spektre
3个回答

6
在计算机中,表示几何代数多重向量(包括旋子)最常见的方法是通过系数数组,每个规范形式代数基元素(规范基元刀片)对应一个系数。例如,在4D基空间中,您将拥有一个2 ^ 4维代数,并具有2 ^ 4维系数数组。另一种但可能更快的表示它们的方式是使用动态调整大小的列表,每个元素包含一个刀片的索引和相关刀片的系数。在这种情况下,两个多重向量的乘法仅使用非零基础刀片,因此应该在算法上更便宜且内存使用较少。
就实际使用而言,我发现用Python玩转几何代数的最简单方法可能是使用https://github.com/pygae/clifford。完全声明,我每天都使用这个库并广泛贡献于它。这个库使用系数的平坦数组方法。使用这个Python库,您可以通过三明治积分应用4D旋子,并通过波浪操作符进行反演(旋子的倒置):
# Create a 4D geometric algebra with euclidean metric
from clifford.g4 import *

# Create a rotor
R = layout.randomRotor()

# Create a vector to rotate
V = layout.randomV()

# Apply the rotor to the vector
V2 = R*V*~R

在Chris Doran和Anthony Lasenby的《物理学家的几何代数》第四章中可以找到来自N维几何代数的多向量的几何积和反转的具体定义。

Leo Dorst的书《物理学家的几何代数》或他的网站http://www.geometricalgebra.net/code.html 中可以找到使用元素列表方法的N维GA的良好C++ GA参考实现。总的来说,这是GA的一个很好的资源,特别是共形模型和数字实现及其相关问题。


3
我在学习更多关于几何代数的内容后,通过这个Youtube系列视频成功地使用了转子: https://www.youtube.com/watch?v=PNlgMPzj-7Q&list=PLpzmRsG7u_gqaTo_vEseQ7U8KFvtiJY4K。该系列视频解释得非常好,我向所有希望使用几何代数的人推荐。
如果你已经了解四元数乘法,那么转子乘法就不会有任何不同,而四元数的 i、j、k 单位则类似于几何代数的基双矢量:e12、e13、e23(或 e01、e02、e12)。
因此,4D中的转子将是(A + B*e12 + C*e13 + D*e14 + E*e23 + F*e24 + G*e34 + H*e1234)。
可以在此页面上找到一个表格,展示如何相乘这些单位:http://www.euclideanspace.com/maths/algebra/clifford/d4/arithmetic/index.htm
为了理解它,考虑2D转子。
它们的形式为:R = A + B*e12
现在,如果我们计算两个任意转子 R_1 和 R_2 之间的乘积,我们得到:
R_1*R_2 = (
  R_1.a     * R_2.a
+ R_1.a     * R_2.b*e12
+ R_1.b*e12 * R_2.a
+ R_1.b*e12 * R_2.b*e12 )
// but: e12*e12 = e1e2e1e2 = -e1e2e2e1= -e1e1 = -1
// this is confirmed by the computation rules I linked above
=
( (R_1.a * R_1.a - R_2.b * R_2.b)
+ (R_1.a * R_2.b + R_1.b * R_2.a) * e12 )

所以在代码中,你需要做以下操作:
R_3.a = R_1.a * R_2.a - R_1.b * R_2.b
R_3.b = R_1.a * R_2.b + R_1.b * R_2.a

现在只需要用同样的方法处理那些大型的四维转子,并应用上述链接中与四维相关的乘法规则即可。以下是处理结果的代码(使用 e0、e1、e2、e3 作为基向量):
e: self.e*other.e - self.e01*other.e01 - self.e02*other.e02 - self.e03*other.e03 - self.e12*other.e12 - self.e13*other.e13 - self.e23*other.e23 + self.e0123*other.e0123,
e01: self.e*other.e01 + self.e01*other.e - self.e02*other.e12 - self.e03*other.e13 + self.e12*other.e02 + self.e13*other.e03 - self.e23*other.e0123 - self.e0123*other.e23,
e02: self.e*other.e02 + self.e01*other.e12 + self.e02*other.e - self.e03*other.e23 - self.e12*other.e01 + self.e13*other.e0123 + self.e23*other.e03 + self.e0123*other.e13,
e03: self.e*other.e03 + self.e01*other.e13 + self.e02*other.e23 + self.e03*other.e - self.e12*other.e0123 - self.e13*other.e01 - self.e23*other.e02 - self.e0123*other.e12,
e12: self.e*other.e12 - self.e01*other.e02 + self.e02*other.e01 - self.e03*other.e0123 + self.e12*other.e - self.e13*other.e23 + self.e23*other.e13 - self.e0123*other.e03,
e13: self.e*other.e13 - self.e01*other.e03 + self.e02*other.e0123 + self.e03*other.e01 + self.e12*other.e23 + self.e13*other.e - self.e23*other.e12 + self.e0123*other.e02,
e23: self.e*other.e23 - self.e01*other.e0123 - self.e02*other.e03 + self.e03*other.e02 - self.e12*other.e13 + self.e13*other.e12 + self.e23*other.e - self.e0123*other.e01,
e0123: self.e*other.e0123 + self.e01*other.e23 - self.e02*other.e13 + self.e03*other.e12 + self.e12*other.e03 - self.e13*other.e02 + self.e23*other.e01 + self.e0123*other.e,

你能在回答中提供一个关于这个转子的数值例子吗? - Jocer
如果你将这与简单的矩阵乘法数学进行比较,你会发现几何代数更加复杂,不太适合现今的计算系统,这也是我使用齐次矩阵的原因之一(它们更简单,对于ND甚至更快,并且可以堆叠更多的旋转...)。这也是为什么它通常在大多数3D图形引擎和库中本地化(如OpneGL,DirectX等),而不是几何代数的原因。 - Spektre

0
解决绕任意向量旋转在4D下会让你发疯。是的,有一些方程可以解决这个问题,比如3D旋转的欧拉-罗德里格斯公式扩展到4D, 但所有方程都需要解决方程组,而且对于我们在4D中使用起来真的不直观。
我正在使用平行于平面的旋转(类似于3D中围绕主轴的旋转)。在4D中有6个主轴(XY、YZ、ZX、XW、YW、ZW),所以只需创建旋转矩阵(类似于3D)。我在4D中使用5x5齐次变换矩阵,因此旋转看起来像这样:
xy: 
( c , s ,0.0,0.0,0.0)
(-s , c ,0.0,0.0,0.0)
(0.0,0.0,1.0,0.0,0.0)
(0.0,0.0,0.0,1.0,0.0)
(0.0,0.0,0.0,0.0,1.0)
yz: 
(1.0,0.0,0.0,0.0,0.0)
(0.0, c , s ,0.0,0.0)
(0.0,-s , c ,0.0,0.0)
(0.0,0.0,0.0,1.0,0.0)
(0.0,0.0,0.0,0.0,1.0)
zx:
( c ,0.0,-s ,0.0,0.0)
(0.0,1.0,0.0,0.0,0.0)
( s ,0.0, c ,0.0,0.0)
(0.0,0.0,0.0,1.0,0.0)
(0.0,0.0,0.0,0.0,1.0)
xw:
( c ,0.0,0.0, s ,0.0)
(0.0,1.0,0.0,0.0,0.0)
(0.0,0.0,1.0,0.0,0.0)
(-s ,0.0,0.0, c ,0.0)
(0.0,0.0,0.0,0.0,1.0)
yw:
(1.0,0.0,0.0,0.0,0.0)
(0.0, c ,0.0,-s ,0.0)
(0.0,0.0,1.0,0.0,0.0)
(0.0, s ,0.0, c ,0.0)
(0.0,0.0,0.0,0.0,1.0)
zw:
(1.0,0.0,0.0,0.0,0.0)
(0.0,1.0,0.0,0.0,0.0)
(0.0,0.0, c ,-s ,0.0)
(0.0,0.0, s , c ,0.0)
(0.0,0.0,0.0,0.0,1.0)

其中c=cos(a),s=sin(a)a是旋转角度。旋转轴通过坐标系原点(0,0,0,0)。更多信息请参见以下内容:


有任何想法负号出现在哪里吗?一个描述AB(i,j)的一般公式的链接(其中A、B是XYZW之一)会很好。我想知道符号是否基于旋转的某种右手性而被捕获。如果是这样,在4D中如何定义呢? - DolphinDream
@DolphinDream 不确定你所说的 AB(i,j) 和减号是什么意思(因为评论中两者都只是4D向量)?如果你指的是 matrix * vector,那么你提到的减号是什么意思?如果 -s=-sin(dangle) 那么是的,它决定了顺时针/逆时针旋转。你可以使用旋转和未旋转向量的点积符号来确定旋转方向。如果你在写 欧拉-罗德里格斯公式,那么没有直接的公式,而是需要在运行时为每个旋转解决一组方程。这就是为什么使用增量平面旋转更好/更容易实现的原因。 - Spektre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接