我有一个三维数组。把它想象成一块砖头。这种砖有24种可能的旋转(保持其边缘与坐标轴平行)。如何生成所有相应的三维数组?
答案 0 :(得分:3)
模具(半对骰子)便于观察24种不同的方向,并且可以建议操作序列来生成它们。您将看到六个面中的任何一个都可以位于最上面,下面的两个面可以旋转到四个不同的基本方向。让我们表示两个操作:“转动”和“滚动”,其中转动将模具绕z轴从一个基数旋转到下一个, roll 将模具旋转90°远离你,因此离面成为底面,近面成为顶面。这些操作可以使用Felipe Lopes答案中提到的旋转矩阵表示,也可以表示为给定(x,y,z)返回(-y,x,z)或(x,z, - 的简单函数)。 y),分别。
无论如何,如果你将模具放置在近面,2放在右边,3放在顶部,你会发现以下一系列步骤产生十二个不同的方向,顶部有1,2或3个点:RTTTRTTTRTTT。然后序列RTR暴露6,4,5,其中原来是1,2,3,并且序列RTTTRTTTRTTT的重复产生十二个取向,顶部有4,5或6个点。上面提到的序列嵌入在下面的python代码中。
def roll(v): return (v[0],v[2],-v[1])
def turn(v): return (-v[1],v[0],v[2])
def sequence (v):
for cycle in range(2):
for step in range(3): # Yield RTTT 3 times
v = roll(v)
yield(v) # Yield R
for i in range(3): # Yield TTT
v = turn(v)
yield(v)
v = roll(turn(roll(v))) # Do RTR
p = sequence(( 1, 1, 1))
q = sequence((-1,-1, 1))
for i in sorted(zip(p,q)):
print i
打印出变换点对的排序列表的基本原理是双重的:(i)任何面部方向都可以通过其两个角的位置来指定; (ii)然后很容易检查每对的唯一性,例如通过输出到uniq
。
以下是排序输出的开始方式:
((-1, -1, -1), (-1, 1, 1))
((-1, -1, -1), (1, -1, 1))
((-1, -1, -1), (1, 1, -1))
((-1, -1, 1), (-1, 1, -1))
((-1, -1, 1), (1, -1, -1))
((-1, -1, 1), (1, 1, 1))
((-1, 1, -1), (-1, -1, 1))
((-1, 1, -1), (1, -1, -1))
((-1, 1, -1), (1, 1, 1))
答案 1 :(得分:2)
您可以使用旋转矩阵。围绕x轴旋转3D阵列意味着位置(i,j,k)
处的元素将映射到位置(i,-k,j)
。当然,如果你的数组是0索引的,你可能不得不用-k
或类似的东西替换size-1-k
。
同样,围绕y轴旋转可将(i,j,k)
映射到(k,j,-i)
。这两个旋转可以表示为矩阵。对于x轴旋转:
|i'| |1 0 0| |i|
|j'| = |0 0 -1|*|j|
|k'| |0 1 0| |k|
对于y轴旋转:
|i'| |0 0 1| |i|
|j'| = |0 1 0|*|j|
|k'| |-1 0 0| |k|
任何一般旋转都可以描述为这两个旋转的序列。连续应用两个旋转只是乘以3x3矩阵。因此,如果您找到它们的所有可能产品,您将获得24个矩阵(包括标识),每个矩阵对应于数组的有效旋转。找到所有可能的乘法是有点棘手的,因为它们不会通勤。
我认为你可以蛮力强制(A^p)*(B^q)*(A^r)*(B^s)
形式的所有产品,其中A和B是之前的两个矩阵,p,q,r,s
是它们的幂,范围从0到3(指数A或者B到4会将它们带回单位矩阵。)
这样做,您可以生成所有24个有效的旋转矩阵,并使用每个旋转矩阵旋转3D数组,小心移动负索引,以便您不会访问越界。
答案 2 :(得分:0)
让X围绕X轴旋转90度,Y围绕Y轴旋转90度,然后24种可能的独特组合(除了旋转相同的四次之外,给出最多5次旋转的所有可能组合(例如, XXXX,XXXXY XYYYY等):
1. I
2. X
3. Y
4. XX = YXXY
5. XY
6. YX
7. YY = XYYX
8. XXX = XYXXY = YXXYX = YXYXY = YYXYY
9. XXY = YXXYY = YYYXX
10. XYX = YXY
11. XYY = XXYYX = YYXXX
12. YXX = XXYYY = YYXXY
13. YYX = XXXYY = XYYXX
14. YYY = XXYXX = XYXYX = XYYXY = YXYYX
15. XXXY
16. XXYX = XYXY = YXYY
17. XXYY = YYXX
18. XYXX = YXYX = YYXY
19. XYYY
20. YXXX
21. YYYX
22. XXXYX = XXYXY = XYXYY = YXYYY
23. XYXXX = YXYXX = YYXYX = YYYXY
24. XYYYX = YXXXY
当然,您可以使用任意两个90度旋转代替X和Y.例如,Y和Z.
或者,如果你也使用Z,绕Z轴旋转90度,那么4次旋转就足够了:
1. I
2. X = YXZ
3. Y = ZYX
4. Z = XZY
5. XX = XYXZ = YXXY = YXYZ = YXZX = YYZZ = YZXZ = ZXXZ = ZZYY
6. XY = YZ = ZX = XZYX = YXZY = ZYXZ
7. XZ = XXZY = YXZZ = YYYX = ZYYY
8. YX = XZZZ = YYXZ = ZYXX = ZZZY
9. YY = XXZZ = XYYX = YZYX = ZXYX = ZYXY = ZYYZ = ZYZX = ZZXX
10. ZY = XXXZ = XZYY = YXXX = ZZYX
11. ZZ = XXYY = XYZY = XZXY = XZYZ = XZZX = YYXX = YZZY = ZXZY
12. XXX
13. XXY = XYZ = XZX = YZZ = ZXZ
14. XXZ = ZYY
15. XYX = YXY = YYZ = YZX = ZXX
16. XYY = YZY = ZXY = ZYZ = ZZX
17. XZZ = YYX
18. YXX = ZZY
19. YYY
20. ZZZ
21. XXXY = XXYZ = XXZX = XYZZ = XZXZ = YZZZ = ZXZZ = ZYYX
22. XXYX = XYXY = XYYZ = XYZX = XZXX = YXYY = YYZY = YZXY = YZYZ = YZZX = ZXXY = ZXYZ = ZXZX = ZYZZ = ZZXZ
23. XYXX = XZZY = YXYX = YYXY = YYYZ = YYZX = YZXX = ZXXX
24. XYYY = YXXZ = YZYY = ZXYY = ZYZY = ZZXY = ZZYZ = ZZZX
这24个矩阵都存在三个列向量,每个向量存在两个零和一个减1或加1。在每一行上也有两个零。因此,它们很容易生成:第一列向量有六种可能性((1,0,0),( - 1,0,0),(0,-1,0),(0,1,0) ,(0,0,-1)和(0,0,1)),这对应于将正X轴移动到正或负x,y或z轴。第二列向量只有四种可能性,因为它必须包含零,其中第一列具有非零值。最后,第三列向量只剩下一个位置,其中加号或减号可以是。这给出了6 * 4 * 2 = 48个矩阵,其中一半也反映了原始矩阵(它们是镜子和可选的旋转的组合)。因此,只有24个是纯粹的旋转。作为镜像操作的矩阵将具有等于-1的行列式,纯旋转的行列式为1.
答案 3 :(得分:0)
James Waldby的答案令人鼓舞,我想添加一个只有两个for循环的稍有改进的版本。
我们知道有24种独特的方向。我通过想象一个骰子来计算:顶面有6种可能的选择,而顶面上的每个面都有4种可能的旋转。
如果我们重复这个想法怎么办?我想。如果我们能找到一种方法来移动骰子的所有6个面,那么我们只需观察每个面的4个旋转就可以了!
因此,我抓起了最近的“砖”(在我的情况下是Vitasoy纸箱),开始旋转以查看访问所有6张脸的最简单方式。如果我们引入一个额外的逆时针旋转,则我们的操作如下:
然后我们可以通过以下方式访问所有面孔:
Roll-> Turn CW-> Roll-> Turn CCW-> Roll-> Turn CW-> Roll-> Turn CCW-> Roll-> Turn CW-> Roll-> Turn CCW
最后一转,我们回到了原始方向。如您所见,这是重复的滚动+交替的CW转弯和CCW转弯。
现在,如果将其扩展为包括所访问的每个面孔的所有旋转,则它将变为:
滚动-> 3x反转CW->滚动-> 3x反转CCW->滚动-> 3x反转CW->滚动-> 3x反转CCW->滚动-> 3x反转CW->滚动-> 3x反转CCW < / p>
...然后我们回到了起点!可以将其转换为两个for循环(少一个!):
def sequence(m):
for roll_index in range(6):
m = roll(m)
yield(m)
for turn_index in range(3):
m = turn_cw(m) if roll_index % 2 == 0 else turn_ccw(m)
yield(m)