我正在尝试用Python创建一个魔方,我已经在视觉上代表了多维数据集。在如何实现旋转方面苦苦挣扎。
我想我正在征求关于如何做到这一点的反馈。我首先想到,旋转每个立方体顶点组,没有太多运气。
我基本上想从一组立方体对象(不同大小)中选择一个切片,在每个对象上执行旋转和平移。
import pygame
import random
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
vertices = (
(1, -1, -1),
(1, 1, -1),
(-1, 1, -1),
(-1, -1, -1),
(1, -1, 1),
(1, 1, 1),
(-1, -1, 1),
(-1, 1, 1)
)
edges = (
(0,1),
(0,3),
(0,4),
(2,1),
(2,3),
(2,7),
(6,3),
(6,4),
(6,7),
(5,1),
(5,4),
(5,7)
)
surfaces = (
(0,1,2,3),
(3,2,7,6),
(6,7,5,4),
(4,5,1,0),
(1,5,7,2),
(4,0,3,6)
)
colors = (
(1,0,0), #Red
(0,1,0), #Green
(1,0.5,0), #Orange
(1,1,0), #Yellow
(1,1,1), #White
(0,0,1), #Blue
)
class Cube():
'''set the vertices edges and surfaces(colored) for a Cube'''
def __init__(self):
'''initiate the display to show the cube'''
pygame.init()
display = (800,600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
glEnable(GL_DEPTH_TEST)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glTranslatef(1,1, -40)
def setVertices(self, xmove, ymove, zmove):
'''set predefined vertices'''
xValueChange = xmove
yValueChange = ymove
zValueChange = zmove
newVertices = []
for vert in vertices:
newVert = []
newX = vert[0] + xValueChange
newY = vert[1] + yValueChange
newZ = vert[2] + zValueChange
newVert.append(newX)
newVert.append(newY)
newVert.append(newZ)
newVertices.append(newVert)
return newVertices
def CreateCube(self, vertices):
'''create with OpenGL'''
glBegin(GL_QUADS)
x = 0
for surface in surfaces:
glColor3fv(colors[x])
x+=1
for vertex in surface:
glVertex3fv(vertices[vertex])
glEnd()
class EntireCube():
def __init__(self,typeOfCube):
self.typeOfCube = typeOfCube
self.NewCube = Cube()
def createEntireCube(self):
'''for each dimension x,y,z make a dictionary containing the vertices to be displayed'''
self.cubeDict = {}
count = 0
for x in range(self.typeOfCube):
for y in range(self.typeOfCube):
for z in range(self.typeOfCube):
self.cubeDict[count] = self.NewCube.setVertices(x*2.1,y*2.1,z*2.1)
count += 1
def mainloop(self):
'''key events, creates the matrix of cubes'''
rotateUpKey, rotateDownKey, rotateLeftKey, rotateRightKey = False, False, False, False
rotationalSensitivity = 2
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == KEYDOWN:
if event.key == K_UP:
rotateUpKey = True
if event.key == K_DOWN:
rotateDownKey = True
if event.key == K_LEFT:
rotateLeftKey = True
if event.key == K_RIGHT:
rotateRightKey = True
if event.type == KEYUP:
if event.key == K_UP:
rotateUpKey = False
if event.key == K_DOWN:
rotateDownKey = False
if event.key == K_LEFT:
rotateLeftKey = False
if event.key == K_RIGHT:
rotateRightKey = False
if rotateUpKey:
glRotatef(rotationalSensitivity,-rotationalSensitivity,0,0)
if rotateDownKey:
glRotatef(rotationalSensitivity,rotationalSensitivity,0,0)
if rotateLeftKey:
glRotatef(rotationalSensitivity,0,-rotationalSensitivity,0)
if rotateRightKey:
glRotatef(rotationalSensitivity,0,rotationalSensitivity,0)
#eventually implement keysbindings to call function to rotate a slice of the matrix created
# x = glGetDoublev(GL_MODELVIEW_MATRIX)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
for eachCube in self.cubeDict:
self.NewCube.CreateCube(self.cubeDict[eachCube])
# glPushMatrix()
# glRotatef(1,3,1,1)
# glPopMatrix()
pygame.display.flip()
pygame.time.wait(10)
def main():
NewEntireCube = EntireCube(3) #create a 3x3x3 cube
NewEntireCube.createEntireCube()
NewEntireCube.mainloop()
if __name__ == '__main__':
main()
pygame.quit()
quit()
我希望有更多了解此事的人可以就如何继续提供一些指导。
答案 0 :(得分:3)
魔方可以由3个3x3x3 多维数据集的3维数组组成。旋转多维数据集的一个切片似乎很容易,但是请注意,如果在切片上旋转了,则多维数据集的位置会发生变化,必须重新组织。不仅位置发生变化,(旋转的)单个立方体的方向也发生变化。
首先,从类Cube
的构造函数中删除PyGame和OpenGL初始化。这是错误的地方。下面将生成27个Cube类型的对象。
每个多维数据集都必须知道它的初始位置(self.init_i
)和经过一些旋转后当前的位置(self.current_i
)。此信息被编码为一个包含3个元素的列表,每个元素一个。值是 NxNxN 魔方的立方体的索引,范围为 [0,N []。
单个多维数据集的方向以3维Rotation matrix(self.rot
)进行编码。旋转矩阵必须由identity matrix初始化。
class Cube():
def __init__(self, id, N, scale):
self.N = N
self.scale = scale
self.init_i = [*id]
self.current_i = [*id]
self.rot = [[1 if i==j else 0 for i in range(3)] for j in range(3)]
创建27个立方体的列表
cr = range(3)
self.cubes = [Cube((x, y, z), 3, scale) for x in cr for y in cr for z in cr]
如果旋转了魔方的一部分,则必须检查哪个魔方受到了影响。这可以通过检查切片是否与当前位置的旋转轴输入匹配来完成。
def isAffected(self, axis, slice, dir):
return self.current_i[axis] == slice
要旋转立方体,位置和方向必须围绕axis
旋转90°。 3维旋转矩阵由3个方向向量组成。可以通过交换向量的坐标,并向右旋转结果的x坐标,向左旋转结果的y坐标,来旋转d维向量:
rotate right: (x, y) -> (-y, x)
rotate left: (x, y) -> (y, -x)
由于旋转矩阵的所有向量都在轴对齐的平面中,因此该算法可用于更改立方体的方向和位置。 axis
旋转轴(x = 0,y = 1,z = 2),dir
是旋转方向( 1 是右方向左 -1 )
要旋转轴矢量,必须交换矢量的两个分量,并将其中之一反转。
例如,绕Y轴向左旋转:
(x, y, z) -> (z, y, -x)
旋转位置时,必须交换索引。反转索引意味着将索引i
映射到索引N-1-i
:
例如,绕Y轴向左旋转:
(ix, iy, iz) -> (iz, iy, N-1-ix)
单个立方体的旋转:
i, j = (axis+1) % 3, (axis+2) % 3
for k in range(3):
self.rot[k][i], self.rot[k][j] = -self.rot[k][j]*dir, self.rot[k][i]*dir
self.current_i[i], self.current_i[j] = (
self.current_i[j] if dir < 0 else self.N - 1 - self.current_i[j],
self.current_i[i] if dir > 0 else self.N - 1 - self.current_i[i] )
当必须绘制多维数据集时,可以使用多维数据集的当前位置(self.current_i
和方向self.rot
来设置4x4转换矩阵:
def transformMat(self):
scaleA = [[s*self.scale for s in a] for a in self.rot]
scaleT = [(p-(self.N-1)/2)*2.1*self.scale for p in self.current_i]
return [
*scaleA[0], 0,
*scaleA[1], 0,
*scaleA[2], 0,
*scaleT, 1]
分别使用glPushMatrix
和glPushMatrix
。通过glMultMatrix
,可以将矩阵与当前矩阵相乘。
以下函数绘制一个多维数据集。参数angle
,axis
,slice
,dir
,甚至可以通过设置animate=True
和参数{{1}将动画应用于立方体},angle
,axis
,slice
:
dir
要绘制多维数据集,只需循环调用方法def draw(self, col, surf, vert, animate, angle, axis, slice, dir):
glPushMatrix()
if animate and self.isAffected(axis, slice, dir):
glRotatef( angle*dir, *[1 if i==axis else 0 for i in range(3)] )
glMultMatrixf( self.transformMat() )
glBegin(GL_QUADS)
for i in range(len(surf)):
glColor3fv(colors[i])
for j in surf[i]:
glVertex3fv(vertices[j])
glEnd()
glPopMatrix()
:
draw
类for cube in self.cubes:
cube.draw(colors, surfaces, vertices, animate, animate_ang, *action)
的实现适用于任何 NxNxN Rubik的多维数据集。
请参见示例程序,了解 3x3x3 多维数据集。通过 1 至 9 键向右旋转多维数据集的切片,并通过 F1 至 F9键向左旋转多维数据集:
当然,对于您的原始代码,代码使用Legacy OpenGL。但是方法Cube
为单个局部立方体设置通用的4x4模型矩阵。因此,可以轻松地将此代码移植到现代OpenGL。
Cube.transformMat