#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Posts
    3
    Rep Power
    0

    Need help with 3D rotation


    I am working on a 3D 2x2 rubix cube.
    As of right now, I am able to rotate the whole cube.
    The problem I have however is that I am not always able to rotate each individual side. For now I am trying to rotate the right side(the side that you see on the right of the screen). This rotation works if there has not been any rotation in the y plane.
    However, as soon as I rotate the cube in the y axis, and then rotate the side, it becomes deformed. I am using a 3D rotational
    matrix(http://en.wikipedia.org/wiki/Rotation_matrix).
    My question is how can make it so side does not become deformed. I also whant to be able to rotate that side couple degrees at a time so that there is a smooth animation of the rotating side.
    Also I will not be able to use any 3D library because I have no knowledge of any other library besides pygame.
    Thanks in advance.

    Here is my code:
    Code:
    import math
    import pygame
    from operator import itemgetter
    import sys
    import os
    
    os.environ['SDL_VIDEODRIVER']='windib'
    
    
    
    faces = [(0,1,3,2), (4,5,7,6), (0,2,6,4),(1,3,7,5),(2,3,7,6), (0,1,5,4),
             ]
    
    factor = 100
    win_width = 1000
    win_height = 600
    
    anglex = 0
    angley = 0
    anglez = 0
    
    
    
    def construct_matrix(x, y, z, theta):
        matrix = [
                  [[],[],[]],
                  [[],[],[]],
                  [[],[],[]]
                  ]
        constant = (math.sqrt(math.pow(x,2)+ math.pow(y,2)+ math.pow(z,2)))
        ux = x/constant
        uy = y/constant
        uz = z/constant
        rad_theta = theta * math.pi / 180
        aa = math.cos(rad_theta) + math.pow(ux,2)*(1-math.cos(rad_theta))
        ab = ux*uy*(1-math.cos(rad_theta))-uz*math.sin(rad_theta)
        ac = ux*uz*(1-math.cos(rad_theta)) + uy*math.sin(rad_theta)
        ba = uy*ux*(1-math.cos(rad_theta) + uz*math.sin(rad_theta))
        bb = math.cos(rad_theta) + (math.pow(uy,2)*(1-math.cos(rad_theta)))
        bc = uy*uz*(1-math.cos(rad_theta)) - ux*math.sin(rad_theta)
        print bc
        ca = uz*ux*(1-math.cos(rad_theta)) - uy*math.sin(rad_theta)
        cb = uz*uy*(1-math.cos(rad_theta)) + ux*math.sin(rad_theta)
        cc = math.cos(rad_theta) + math.pow(uz,2)*(1-math.cos(rad_theta))
        matrix[0][0] = (aa)
        matrix[0][1] = (ab)
        matrix[0][2] = (ac)
        matrix[1][0] = (ba)
        matrix[1][1] = (bb)
        matrix[1][2] = (bc)
        matrix[2][0] = (ca)
        matrix[2][1] = (cb)
        matrix[2][2] = (cc)
        return matrix
    
    
    
    class Cube:
        def trial2(self,cords):
            new_cords = cords
            new_xcord = new_cords[0]*factor+win_width/2
            new_ycord = new_cords[1]*factor+win_height/2
            twod_cords = (new_xcord, new_ycord, new_cords[2])
            return  twod_cords
    
    
        def screen_vert(self,vertices):
            dvertices = []
            for v in vertices:
                dvertices.append(self.trial2(v))
            return dvertices
    
        def avg_stat(self,vertices,position):
            avg_stat = 0
            for i in vertices:
                avg_stat = avg_stat + i[position]
            avg_stat = avg_stat / 8.0
            return avg_stat
    
        def __init__(self, vertices ,colors):
            
            self.vertices = vertices
            self.colors = colors
            self.screenvert = self.screen_vert(self.vertices)
            self.width = self.avg_stat(self.vertices,0)
            self.height = self.avg_stat(self.vertices,1)
            self.depth = self.avg_stat(self.vertices,2)
    
        def cube_point(self,x,y,z,x_angle,y_angle,z_angle):
            radx = x_angle * math.pi / 180
            rady = y_angle * math.pi / 180
            radz = z_angle * math.pi / 180
            
            xmidprime = x*math.cos(radz) - y*math.sin(radz)
            ymidprime = x*math.sin(radz) + y*math.cos(radz)
            
            yprime = ymidprime*math.cos(radx) - z*math.sin(radx)
            zmidprime = ymidprime*math.sin(radx) + z*math.cos(radx)   
            
            zprime = zmidprime*math.cos(rady) - xmidprime*math.sin(rady)
            xprime = zmidprime*math.sin(rady) + xmidprime*math.cos(rady)
            return(xprime,yprime,zprime)
    
    
        def make_new_vert(self,anglex,angley,anglez):
            current_vertices = []
            for v in self.vertices:
                current_vertices.append(self.cube_point(float(v[0]), float(v[1]), float(v[2]), float(anglex), float(angley), float(anglez)))  
            self.vertices = current_vertices
            self.screenvert = self.screen_vert(self.vertices)
            self.width = self.avg_stat(self.vertices,0)
            self.height = self.avg_stat(self.vertices,1)
            self.depth = self.avg_stat(self.vertices,2)
            
        def make_new_vert_matrix(self,matrix):
            current_vertices = []
            solving = []
            for v in self.vertices:
                print v
                a = matrix[0][0]*v[0] + matrix[0][1]*v[1] + matrix[0][2]*v[2]
                b = matrix[1][0]*v[0] + matrix[1][1]*v[1] + matrix[1][2]*v[2]
                c = matrix[2][0]*v[0] + matrix[2][1]*v[1] + matrix[2][2]*v[2]
                current_vertices.append((a,b,c))
                
            self.vertices = current_vertices
            self.screenvert = self.screen_vert(self.vertices)
            self.width = self.avg_stat(self.vertices,0)
            self.height = self.avg_stat(self.vertices,1)
            self.depth = self.avg_stat(self.vertices,2)
    
        def drawing(self):
            avg_depth = []
            i = 0
            for f in faces:
                z_avg = (self.screenvert[f[0]][2] + self.screenvert[f[1]][2] + self.screenvert[f[2]][2] + self.screenvert[f[3]][2]) / 4.0
                avg_depth.append([i,z_avg])
                i+=1
                
            for i in sorted(avg_depth,key=itemgetter(1),reverse=False):
                index = i[0]
                face = faces[index]
                points = [
                             (self.screenvert[face[0]][0], self.screenvert[face[0]][1]), (self.screenvert[face[1]][0], self.screenvert[face[1]][1]),
                             (self.screenvert[face[1]][0], self.screenvert[face[1]][1]), (self.screenvert[face[2]][0], self.screenvert[face[2]][1]),
                             (self.screenvert[face[2]][0], self.screenvert[face[2]][1]), (self.screenvert[face[3]][0], self.screenvert[face[3]][1]),
                             (self.screenvert[face[3]][0], self.screenvert[face[3]][1]), (self.screenvert[face[0]][0], self.screenvert[face[0]][1]),
                             ]
                pygame.draw.polygon(screen,self.colors[index],points)
    
    
    
    
    vertices0 = [(-1,1,-1),
                (0,1,-1),
                (-1,1,0),
                (0,1,0),
                (-1,0,-1),
                (0,0,-1),
                (-1,0,0),
                (0,0,0),
                ]
    
    vertices1 = [(0,1,-1),
                (1,1,-1),
                (0,1,0),
                (1,1,0),
                (0,0,-1),
                (1,0,-1),
                (0,0,0),
                (1,0,0),
                ]
    vertices2 = [(-1,1,0),
                (0,1,0),
                (-1,1,1),
                (0,1,1),
                (-1,0,0),
                (0,0,0),
                (-1,0,1),
                (0,0,1),
                ]
    
    vertices3 = [(0,1,0),
                (1,1,0),
                (0,1,1),
                (1,1,1),
                (0,0,0),
                (1,0,0),
                (0,0,1),
                (1,0,1),
                ]
    
    
    vertices4 = [(-1,0,-1),
                (0,0,-1),
                (-1,0,0),
                (0,0,0),
                (-1,-1,-1),
                (0,-1,-1),
                (-1,-1,0),
                (0,-1,0),
                ]
    
    vertices5 = [(0,0,-1),
                (1,0,-1),
                (0,0,0),
                (1,0,0),
                (0,-1,-1),
                (1,-1,-1),
                (0,-1,0),
                (1,-1,0),
                ]
    vertices6 = [(-1,0,0),
                (0,0,0),
                (-1,0,1),
                (0,0,1),
                (-1,-1,0),
                (0,-1,0),
                (-1,-1,1),
                (0,-1,1),
                ]
    
    vertices7 = [(0,0,0),
                (1,0,0),
                (0,0,1),
                (1,0,1),
                (0,-1,0),
                (1,-1,0),
                (0,-1,1),
                (1,-1,1),
                ]
    
    
    
    
    
    colors0 = [(255,0,0), (0,0,0), (0,0,255),(0,0,0), (0, 0, 0), (255, 255, 0)]
    
    colors1 = [(255,80,0), (0,0,0), (0,0,0),(255,255,0), (0, 0, 0), (255, 0, 255)]
    
    colors2 = [(255,0,80), (0,0,0), (25,0,25),(0,0,0), (255, 128, 0), (0, 0, 0)]
    
    colors3 = [(255,89,0), (0,0,0), (0,0,0),(255,200,0), (25, 128, 0), (0, 0, 0)]
    colors4 = [(0,0,0), (0,255,0), (0,0,255),(0,0,0), (0, 0, 0), (0, 255, 255)]
    
    colors5 = [(0,0,0), (0,55,43), (0,0,0),(255,255,0), (0, 0, 0), (255, 255, 255)]
    colors6 = [(0,0,0), (0,255,0), (0,0,255),(0,0,0), (255, 128, 200), (0, 0, 0)]
    
    colors7 = [(0,0,0), (0,255,0), (0,0,0),(55,255,0), (0, 128, 0), (0, 0, 0)]
    
    
    
    pygame.init()
    
    screen = pygame.display.set_mode((win_width, win_height))
    pygame.display.set_caption("Ilya")
            
    clock = pygame.time.Clock()
    
    array = [
            [[Cube(vertices0, colors0),Cube(vertices1, colors1)],[Cube(vertices2, colors2),Cube(vertices3, colors3)]],
            [[Cube(vertices4, colors4),Cube(vertices5, colors5)],[Cube(vertices6, colors6),Cube(vertices7, colors7)]]
            ]
    
    while True:
        clock.tick(50)
        screen.fill((0,32,0))
       
        
        order_for_drawing = []
        index = 0
        for i in range(2):
            for k in range(2):
                for j in range(2):
                    order_for_drawing.append([array[i][k][j].depth,array[i][k][j]])
                    
        for i in sorted(order_for_drawing,key=itemgetter(0),reverse=False):
            i[1].drawing()
    
        pressed = pygame.key.get_pressed()
    
        if pressed[pygame.K_UP]:
            anglex +=4
    
        if pressed[pygame.K_DOWN]:
            anglex -=4  
    
        if pressed[pygame.K_RIGHT]:
            angley +=4
    
        if pressed[pygame.K_LEFT]:
            angley -=4
    
        if pressed[pygame.K_s]:
            anglez +=4
    
        if pressed[pygame.K_a]:
            anglez -=4
    
        for i in range(2):
            for k in range(2):
                for j in range(2):
                    array[i][k][j].make_new_vert(anglex,angley,anglez)
      
        
        for event in pygame.event.get():
            #if event.type == pygame.KEYDOWN:
                
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
    
    
            if pressed[pygame.K_q] and event.type == pygame.KEYDOWN and event.key == pygame.K_UP:
                order_for_drawing1 = []
                index1 = 0
                list1 = []
                constant1 = 0
                widthavg = 0
                depthavg = 0
                heightavg = 0
                for i in range(2):
                    for k in range(2):
                        for j in range(2):
                            order_for_drawing1.append([array[i][k][j].width,array[i][k][j]])                        
    
    
                for i in sorted(order_for_drawing1,key=itemgetter(0),reverse=True):
                    index1+=1
                    list1.append(i[1])
                    if index1 == 4:
                        break
                for i in list1:
                    widthavg += i.width
                    depthavg += i.depth
                    heightavg += i.height
                widthavg = widthavg/4.0
                depthavg =  depthavg/4.0
                heightavg = heightavg/4.0
                constant = math.sqrt(math.pow(widthavg,2) + math.pow(heightavg,2) + math.pow(depthavg,2))
                ux = widthavg/constant
                uy = heightavg/constant
                uz = depthavg/constant
                print ux, uy, uz
                rotational_matrix = construct_matrix(ux, uy, uz, 90.0)
                print rotational_matrix
                #for i in range(45):
                for j in list1:
                    j.make_new_vert_matrix(rotational_matrix)
                
                    
    
    
                
        anglex = 0
        angley = 0
        anglez = 0
        pygame.display.update()
  2. #2
  3. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,841
    Rep Power
    480
    On removing
    os.environ['SDL_VIDEODRIVER']='windib'
    your program works such that the entire cube rotates using a, s, and arrow keys. What keys should I press to duplicate the deformation? And provide any other information I might need to duplicate the problem.

    Also, I'm not sure why you have more than 6 colors.
    Last edited by b49P23TIvg; May 16th, 2013 at 09:02 AM.
    [code]Code tags[/code] are essential for python code and Makefiles!
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Posts
    3
    Rep Power
    0
    Originally Posted by b49P23TIvg
    On removing
    os.environ['SDL_VIDEODRIVER']='windib'
    your program works such that the entire cube rotates using a, s, and arrow keys. What keys should I press to duplicate the deformation? And provide any other information I might need to duplicate the problem.

    Also, I'm not sure why you have more than 6 colors.
    I have more than six colours for testing purposes so that you can see each individual cube.
    Hold Q and the press the up arrow to move the right side.
    Rotate the cube before hand so that 3 faces can be seen, then hold Q and press the up arrow.
  6. #4
  7. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,841
    Rep Power
    480
    This will take some work to figure out.

    If you separated the logical blocks of code with
    elif
    to make rotating the entire cube ... What I'm getting at is that if "q" is held down then only 4 cubes should rotate.

    As it is, looks like you rotate the 4 cubes upon release of "up arrow" (or down), all the while all 8 cubes rotate as long as the arrow key is depressed. This makes me accept that the 4 blocks lose synchronization with the physically correct plane. (Rubik's plane?) I'm not so clear on why they shear into ever higher aspect ratio shapes.

    Before sleeping on it I'll bet that taking care to rotate half the blocks while the other part is stationary will fix the problem.
    [code]Code tags[/code] are essential for python code and Makefiles!
  8. #5
  9. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Posts
    3
    Rep Power
    0
    Originally Posted by b49P23TIvg
    This will take some work to figure out.

    If you separated the logical blocks of code with
    elif
    to make rotating the entire cube ... What I'm getting at is that if "q" is held down then only 4 cubes should rotate.

    As it is, looks like you rotate the 4 cubes upon release of "up arrow" (or down), all the while all 8 cubes rotate as long as the arrow key is depressed. This makes me accept that the 4 blocks lose synchronization with the physically correct plane. (Rubik's plane?) I'm not so clear on why they shear into ever higher aspect ratio shapes.

    Before sleeping on it I'll bet that taking care to rotate half the blocks while the other part is stationary will fix the problem.
    Thanks for your response, I didn't even think about that so I will try to see if your suggestion works

IMN logo majestic logo threadwatch logo seochat tools logo