栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

如何在python PyOpenGL中旋转Rubik's Cube的切片?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何在python PyOpenGL中旋转Rubik's Cube的切片?

魔方可以通过 3x3x3
多维数据集的3维数组来组织。旋转多维数据集的一个切片似乎很容易,但是请注意,如果在切片上旋转,则多维数据集的位置会发生变化,必须重新组织。不仅位置发生变化,(旋转的)单个立方体的方向也发生变化。

首先,从类的构造函数中删除PyGame和OpenGL初始化

Cube
。这是错误的地方。在下面将生成27个Cube类型的对象。

每个多维数据集都必须知道它最初位于的位置(

self.init_i
)和经过一些旋转后当前的位置(
self.current_i
)。该信息被编码为一个包含3个元素的列表,每个元素一个。的值是在该立方体的索引
NxNxN 魔方在范围 [0,N [
单个立方体的方向编码为3维旋转矩阵(
self.rot
)。旋转矩阵必须由恒等矩阵初始化。

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

要旋转立方体,位置和方向必须围绕旋转90°

axis
。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 左)要旋转轴矢量,必须交换矢量的2个分量,并将其中之一反转。

例如,绕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) % 3for k in range(3):    self.rot[k][i], self.rot[k][j] = -self.rot[k][j]*dir, self.rot[k][i]*dirself.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
和参数设置
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)

该类的实现

Cube
适用于任何 NxNxN Rubik的多维数据集。

有关 3x3x3 立方体的信息,请参见示例程序。多维数据集的片由键向右旋转

1
9
和通过按键左
F1
F9

当然,对于原始代码,该代码使用 旧版
OpenGL。但是该方法

Cube.transformMat
为单个局部立方体设置了通用的4x4模型矩阵。因此,可以轻松地将此代码移植到现代OpenGL。

import pygameimport randomfrom 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), (0, 1, 0), (1, 0.5, 0), (1, 1, 0), (1, 1, 1), (0, 0, 1))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)]    def isAffected(self, axis, slice, dir):        return self.current_i[axis] == slice    def update(self, axis, slice, dir):        if not self.isAffected(axis, slice, dir): return        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] )    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]    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()class EntireCube():    def __init__(self, N, scale):        self.N = N        cr = range(self.N)        self.cubes = [Cube((x, y, z), self.N, scale) for x in cr for y in cr for z in cr]    def mainloop(self):        rot_cube_map  = { K_UP: (-1, 0), K_DOWN: (1, 0), K_LEFT: (0, -1), K_RIGHT: (0, 1)}        rot_slice_map = { K_1: (0, 0, 1), K_2: (0, 1, 1), K_3: (0, 2, 1), K_4: (1, 0, 1), K_5: (1, 1, 1), K_6: (1, 2, 1), K_7: (2, 0, 1), K_8: (2, 1, 1), K_9: (2, 2, 1), K_F1: (0, 0, -1), K_F2: (0, 1, -1), K_F3: (0, 2, -1), K_F4: (1, 0, -1), K_F5: (1, 1, -1), K_F6: (1, 2, -1), K_F7: (2, 0, -1), K_F8: (2, 1, -1), K_F9: (2, 2, -1),        }        ang_x, ang_y, rot_cube = 0, 0, (0, 0)        animate, animate_ang, animate_speed = False, 0, 5        action = (0, 0, 0)        while True: for event in pygame.event.get():     if event.type == pygame.QUIT:         pygame.quit()         quit()     if event.type == KEYDOWN:         if event.key in rot_cube_map:  rot_cube = rot_cube_map[event.key]         if not animate and event.key in rot_slice_map:  animate, action = True, rot_slice_map[event.key]     if event.type == KEYUP:         if event.key in rot_cube_map:  rot_cube = (0, 0) ang_x += rot_cube[0]*2 ang_y += rot_cube[1]*2 glMatrixMode(GL_MODELVIEW) glLoadIdentity() glTranslatef(0, 0, -40) glRotatef(ang_y, 0, 1, 0) glRotatef(ang_x, 1, 0, 0) glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) if animate:     if animate_ang >= 90:         for cube in self.cubes:  cube.update(*action)         animate, animate_ang = False, 0 for cube in self.cubes:     cube.draw(colors, surfaces, vertices, animate, animate_ang, *action) if animate:     animate_ang += animate_speed pygame.display.flip() pygame.time.wait(10)def main():    pygame.init()    display = (800,600)    pygame.display.set_mode(display, DOUBLEBUF|OPENGL)    glEnable(GL_DEPTH_TEST)    glMatrixMode(GL_PROJECTION)    gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)    NewEntireCube = EntireCube(3, 1.5)     NewEntireCube.mainloop()if __name__ == '__main__':    main()    pygame.quit()    quit()


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/626547.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号