   Problems with 3D Rotations
  I'm trying to do some basic 3D drawing with python and pygame.  Here's my source code:Cube.pyimport pygamefrom pygame.locals import *import transformsfrom math import cosfrom math import sinX = 0Y = 1Z = 2def project( point ):    d = 400 - point[ Z ]    scr_x = ( 400 * point[ X ] / d ) + 400    scr_y = 300 - ( 400 * point[ Y ] / d )   return ( scr_x, scr_y )    class Cube:    def __init__( self, center=[ 0, 0, 0 ], size=[ 10, 10, 10 ] ): self.center = center   self.size = size   self.rotation = [ 0, 0, 0 ] cx = self.center[ X ]   cy = self.center[ Y ]   cz = self.center[ Z ] sx = self.size[ X ] / 2   sy = self.size[ Y ] / 2   sz = self.size[ Z ] / 2 self.model = [ [ -sx, sy, -sz ], [ sx, sy, -sz ], [ sx, -sy, -sz ], [ -sx, -sy, -sz ],    [ -sx, sy, sz ], [ sx, sy, sz ], [ sx, -sy, sz ], [ -sx, -sy, sz ] ] self.points = [ [ cx - sx, cy + sy, cz - sz ], [ cx + sx, cy + sy, cz - sz ], [ cx + sx, cy - sy, cz - sz ], [ cx - sx, cy - sy, cz - sz ],    [ cx - sx, cy + sy, cz + sz ], [ cx + sx, cy + sy, cz + sz ], [ cx + sx, cy - sy, cz + sz ], [ cx - sx, cy - sy, cz + sz ] ]  self.edges = [ ( 0, 1 ), ( 0, 3 ), ( 1, 2 ), ( 2, 3 ),   ( 0, 4 ), ( 1, 5 ), ( 2, 6 ), ( 3, 7 ),   ( 4, 5 ), ( 4, 7 ), ( 5, 6 ), ( 6, 7 ) ]   self.dirty = False  def draw_points( self, surface ):   if not pygame:  return scr_pt = None for point in self.points:  #print "3D point =",  point  scr_pt = project( point )  #print "Screen point =", scr_pt  pygame.draw.circle( surface, ( 0, 255, 0 ), scr_pt, 2, 0 )   #print "-----------------------"    def draw_wireframe( self, surface ):   if not pygame:  return scr_pts = []   i = 0print "----------Drawing-------------"   for point in self.points: print "3D point =",  point  scr_pts.append( project( point ) )  print "Screen point =", scr_pts  <span class="vb-comment">#pygame.draw.circle( surface, ( 0, 255, 0 ), scr_pts, 2, 0 )</span>    i += <span class="cpp-number">1</span>   <span class="vb-keyword">for</span> edge <span class="vb-keyword">in</span> self.edges:    pygame.draw.line( screen, ( <span class="cpp-number">0</span>, <span class="cpp-number">255</span>, <span class="cpp-number">0</span> ), scr_pts[ edge[ <span class="cpp-number">0</span> ] ], scr_pts[ edge[ <span class="cpp-number">1</span> ] ] )  <span class="vb-keyword">def</span> update( self ):   <span class="vb-keyword">if</span> self.dirty:  cx = self.center[ X ]  cy = self.center[ Y ]  cz = self.center[ Z ]    sx = self.size[ X ] / <span class="cpp-number">2</span>  sy = self.size[ Y ] / <span class="cpp-number">2</span>  sz = self.size[ Z ] / <span class="cpp-number">2</span>    self.model = [ [ -sx, sy, -sz ], [ sx, sy, -sz ], [ sx, -sy, -sz ], [ -sx, -sy, -sz ],   [ -sx, sy, sz ], [ sx, sy, sz ], [ sx, -sy, sz ], [ -sx, -sy, sz ] ]  <span class="vb-keyword">print</span> <span class="vb-literal">"==============Updating============="</span>  <span class="vb-keyword">print</span> <span class="vb-literal">"Rotation:"</span>, self.rotation    <span class="vb-keyword">print</span> <span class="vb-literal">"Center:"</span>, self.center    <span class="vb-keyword">print</span> <span class="vb-literal">"Original points"</span>, self.points    <span class="vb-comment">#self.points = transforms.rotate_solid( self.model, self.rotation )</span>  <span class="vb-keyword">print</span> <span class="vb-literal">"Points after rotation:"</span>, self.points   <span class="vb-keyword">for</span> i <span class="vb-keyword">in</span> range( <span class="cpp-number">8</span> ):px = self.points[ X ]py = self.points[ Y ]pz = self.points[ Z ]self.points = [ px + cx, py + cy, pz + cz ] <span class="vb-comment">#self.points = [ [ cx - sx, cy + sy, cz - sz ], [ cx + sx, cy + sy, cz - sz ], [ cx + sx, cy - sy, cz - sz ], [ cx - sx, cy - sy, cz - sz ],</span>  <span class="vb-comment"># [ cx - sx, cy + sy, cz + sz ], [ cx + sx, cy + sy, cz + sz ], [ cx + sx, cy - sy, cz + sz ], [ cx - sx, cy - sy, cz + sz ] ]</span>  <span class="vb-keyword">print</span> <span class="vb-literal">"Points leaving update():"</span>, self.points  self.dirty = False    <span class="vb-keyword">def</span> rotate( self, angle ):   self.rotation[ X ] += angle[ X ]   self.rotation[ Y ] += angle[ Y ]   self.rotation[ Z ] += angle[ Z ]   self.dirty = True   <span class="vb-keyword">def</span> change_size( self, size ):   self.size = size   self.dirty = True  <span class="vb-keyword">def</span> set_center( self, center ):   self.center = center   self.dirty = True  <span class="vb-keyword">def</span> move( self, offset ):   self.center[ X ] += offset[ X ]   self.center[ Y ] += offset[ Y ]   self.center[ Z ] += offset[ Z ]   self.dirty = True    <span class="vb-keyword">if</span> __name__ == <span class="vb-literal">"__main__"</span>:    <span class="vb-keyword">import</span> sys    pygame.init()    screen = pygame.display.set_mode( ( <span class="cpp-number">800</span>, <span class="cpp-number">600</span> ) )   cube = Cube( [ <span class="cpp-number">0</span>, <span class="cpp-number">0</span>, <span class="cpp-number">0</span> ], [ <span class="cpp-number">200</span>, <span class="cpp-number">200</span>, <span class="cpp-number">200</span> ] )    test_pt = [ <span class="cpp-number">0</span>, <span class="cpp-number">0</span> ]   <span class="vb-keyword">while</span> <span class="cpp-number">1</span>:   <span class="vb-keyword">for</span> event <span class="vb-keyword">in</span> pygame.event.get():  <span class="vb-keyword">if</span> event.type == QUIT: sys.exit() screen.fill( ( <span class="cpp-number">0</span>, <span class="cpp-number">0</span>, <span class="cpp-number">0</span> ) )  <span class="vb-comment">#cube.rotate( [ transforms.convert_degrees( .1 ), 0.0, 0.0 ] )</span>cube.move( [ <span class="cpp-number">1</span>, <span class="cpp-number">0</span>, <span class="cpp-number">0</span> ] )    cube.update()   cube.draw_wireframe( screen )pygame.draw.circle( screen, ( <span class="cpp-number">255</span>, <span class="cpp-number">255</span>, <span class="cpp-number">255</span> ), test_pt, <span class="cpp-number">5</span> )test_pt[ X ] += <span class="cpp-number">2</span>test_pt[ Y ] += <span class="cpp-number">2</span>   pygame.display.flip()</pre></div><!–ENDSCRIPT–>andtransforms.py<!–STARTSCRIPT–><!–source lang="python"–><div class="source"><pre><span class="vb-keyword">from</span> math <span class="vb-keyword">import</span> cos<span class="vb-keyword">from</span> math <span class="vb-keyword">import</span> sin<span class="vb-keyword">from</span> math <span class="vb-keyword">import</span> piX = <span class="cpp-number">0</span>Y = <span class="cpp-number">1</span>Z = <span class="cpp-number">2</span><span class="vb-keyword">def</span> rotate( point, angle ):<span class="vb-comment"># point and angles are both 3-element lists</span>orig = point<span class="vb-comment"># rotate about x</span>point[ Y ] = cos( angle[ X ] ) * orig[ Y ] - sin( angle[ X ] ) * orig[ Z ]point[ Z ] = sin( angle[ X ] ) * orig[ Y ] + cos( angle[ X ] ) * orig[ Z ]orig = point<span class="vb-comment"># rotate about z</span>point[ X ] = cos( angle[ Y ] ) * orig[ X ] - sin( angle[ Y ] ) * orig[ Y ]point[ Y ] = sin( angle[ Y ] ) * orig[ X ] + cos( angle[ Y ] ) * orig[ Y ]orig = point<span class="vb-comment"># rotate about y</span>point[ X ] = cos( angle[ Z ] ) * orig[ X ] - sin( angle[ Z ] ) * orig[ Y ]point[ Z ] = sin( angle[ Z ] ) * orig[ X ] + cos( angle[ Z ] ) * orig[ Y ]<span class="vb-keyword">return</span> point<span class="vb-keyword">def</span> translate( point, offset ):point[ X ] += offset[ X ]point[ Y ] += offset[ Y ]point[ Z ] += offset[ Z ]<span class="vb-keyword">def</span> scale( point, scalar ):point[ X ] *= scalar[ X ]point[ Y ] *= scalar[ Y ]point[ Z ] *= scalar[ Z ]<span class="vb-keyword">def</span> rotate_solid( solid, angles ):solid2 = solid<span class="vb-keyword">for</span> point <span class="vb-keyword">in</span> solid2:point = rotate( point, angles )<span class="vb-keyword">return</span> solid2<span class="vb-keyword">def</span> translate_solid( solid, offset ):solid2 = solid<span class="vb-keyword">for</span> point <span class="vb-keyword">in</span> solid2:translate( point, offset )<span class="vb-keyword">return</span> solid2<span class="vb-keyword">def</span> scale_solid( solid, scalar ):solid2 = solid<span class="vb-keyword">for</span> point <span class="vb-keyword">in</span> solid2:scale( point, scalar )<span class="vb-keyword">return</span> solid2<span class="vb-keyword">def</span> convert_degrees( degree ):<span class="vb-keyword">return</span> degree * pi / <span class="cpp-number">180</span></pre></div><!–ENDSCRIPT–>Some of this code is junk that I'm not using, but if there's anything blatantly wrong about it, I'd be happy if you pointed it out.Something is messed up with my rotations.  Without using my rotation function, the cube is rendered correctly, and moves around like I want it to, but as soon as I try to rotate it, it becomes all trapezoidy.  Probably I've got something screwed in my trig equations, but I can't find it; they seem to be the same as in this <a href="http://www.gamedev.net/reference/articles/article796.asp">article</a> Help would be greatly appreciated.P.S.  I originally posted this in For Beginners, but it's been a couple days with no replies, so I figured this might be a better place to try.  Any mods, feel free to delete the other post.