#!/usr/bin/env python


import sys
import math
from qt import *
from qtgl import *
from OpenGL.GL import *

def gear(inner_radius,outer_radius,width,teeth,tooth_depth):
  r0 = inner_radius
  r1 = outer_radius - tooth_depth/2.0
  r2 = outer_radius + tooth_depth/2.0

  da = 2.0*math.pi/teeth/4.0

  glShadeModel(GL_FLAT)

  glNormal3f(0.0,0.0,1.0)

  # draw front face

  glBegin(GL_QUAD_STRIP)

  for i in range(teeth+1):
    angle = i * 2.0*math.pi/teeth
    glVertex3f(r0*math.cos(angle),      r0*math.sin(angle),      width*0.5 )
    glVertex3f(r1*math.cos(angle),      r1*math.sin(angle),      width*0.5 )
    glVertex3f(r0*math.cos(angle),      r0*math.sin(angle),      width*0.5 )
    glVertex3f(r1*math.cos(angle+3*da), r1*math.sin(angle+3*da), width*0.5 )

  glEnd()

  # draw front sides of teeth

  da = 2.0*math.pi/teeth/4.0

  glBegin(GL_QUADS)

  for i in range(teeth):
    angle = i*2.0*math.pi/teeth

    glVertex3f( r1*math.cos(angle),      r1*math.sin(angle),      width*0.5 )
    glVertex3f( r2*math.cos(angle+da),   r2*math.sin(angle+da),   width*0.5 )
    glVertex3f( r2*math.cos(angle+2*da), r2*math.sin(angle+2*da), width*0.5 )
    glVertex3f( r1*math.cos(angle+3*da), r1*math.sin(angle+3*da), width*0.5 )

  glEnd()


  glNormal3f( 0.0, 0.0, -1.0 )

  # draw back face

  glBegin( GL_QUAD_STRIP )

  for i in range(teeth+1):
    angle = i*2.0*math.pi/teeth

    glVertex3f( r1*math.cos(angle),      r1*math.sin(angle),      -width*0.5 )
    glVertex3f( r0*math.cos(angle),      r0*math.sin(angle),      -width*0.5 )
    glVertex3f( r1*math.cos(angle+3*da), r1*math.sin(angle+3*da), -width*0.5 )
    glVertex3f( r0*math.cos(angle),      r0*math.sin(angle),      -width*0.5 )

  glEnd()

  # draw back sides of teeth

  da = 2.0*math.pi/teeth/4.0

  glBegin( GL_QUADS )

  for i in range(teeth):
    angle = i*2.0*math.pi/teeth

    glVertex3f( r1*math.cos(angle+3*da), r1*math.sin(angle+3*da), -width*0.5 )
    glVertex3f( r2*math.cos(angle+2*da), r2*math.sin(angle+2*da), -width*0.5 )
    glVertex3f( r2*math.cos(angle+da),   r2*math.sin(angle+da),   -width*0.5 )
    glVertex3f( r1*math.cos(angle),      r1*math.sin(angle),      -width*0.5 )

  glEnd()

  # draw outward faces of teeth

  glBegin( GL_QUAD_STRIP )

  for i in range(teeth):
    angle = i*2.0*math.pi/teeth

    glVertex3f( r1*math.cos(angle), r1*math.sin(angle),  width*0.5 )
    glVertex3f( r1*math.cos(angle), r1*math.sin(angle), -width*0.5 )

    u = r2*math.cos(angle+da) - r1*math.cos(angle)
    v = r2*math.sin(angle+da) - r1*math.sin(angle)

    len = math.sqrt( u*u + v*v )
    u /= len
    v /= len
    glNormal3f( v, -u, 0.0 )
    glVertex3f( r2*math.cos(angle+da), r2*math.sin(angle+da),  width*0.5 )
    glVertex3f( r2*math.cos(angle+da), r2*math.sin(angle+da), -width*0.5 )
    glNormal3f( math.cos(angle), math.sin(angle), 0.0 )
    glVertex3f( r2*math.cos(angle+2*da), r2*math.sin(angle+2*da),  width*0.5 )
    glVertex3f( r2*math.cos(angle+2*da), r2*math.sin(angle+2*da), -width*0.5 )
    u = r1*math.cos(angle+3*da) - r2*math.cos(angle+2*da)
    v = r1*math.sin(angle+3*da) - r2*math.sin(angle+2*da)
    glNormal3f( v, -u, 0.0 )
    glVertex3f( r1*math.cos(angle+3*da), r1*math.sin(angle+3*da),  width*0.5 )
    glVertex3f( r1*math.cos(angle+3*da), r1*math.sin(angle+3*da), -width*0.5 )
    glNormal3f( math.cos(angle), math.sin(angle), 0.0 )

  glVertex3f( r1*math.cos(0.0), r1*math.sin(0.0), width*0.5 )
  glVertex3f( r1*math.cos(0.0), r1*math.sin(0.0), -width*0.5 )

  glEnd()

  glShadeModel (GL_SMOOTH)

  # draw inside radius cylinder

  glBegin( GL_QUAD_STRIP )

  for i in range(teeth+1):
    angle = i * 2.0*math.pi / teeth
    glNormal3f( -math.cos(angle),   -math.sin(angle),   0.0 )
    glVertex3f( r0*math.cos(angle), r0*math.sin(angle), -width*0.5 )
    glVertex3f( r0*math.cos(angle), r0*math.sin(angle),  width*0.5 )

  glEnd()

##############################################################################
class GearWidget(QGLWidget):
  def __init__(self,parent=None,name=None):
    QGLWidget.__init__(self,parent,name)

    self.angle=0.0
    self.view_rotx=0.0
    self.view_roty=0.0
    self.view_rotz=0.0

    self.startTimer(10)

  def timerEvent(self,event):
    self.updateGL()

  def paintGL(self):
    self.angle = self.angle + 2.0
    self.view_rotx = self.view_rotx + 1.0
    self.view_roty = self.view_roty + 3.0
    self.view_rotz = self.view_rotz + 2.0

    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )

    glPushMatrix()
    glRotatef( self.view_rotx, 1.0, 0.0, 0.0 )
    glRotatef( self.view_roty, 0.0, 1.0, 0.0 )
    glRotatef( self.view_rotz, 0.0, 0.0, 1.0 )

    glPushMatrix()
    glTranslatef( -3.0, -2.0, 0.0 )
    glRotatef( self.angle, 0.0, 0.0, 1.0 )
    glCallList(self.gear1)
    glPopMatrix()

    glPushMatrix()
    glTranslatef( 3.1, -2.0, 0.0 )
    glRotatef( -2.0*self.angle-9.0, 0.0, 0.0, 1.0 )
    glCallList(self.gear2)
    glPopMatrix()

    glPushMatrix()
    glTranslatef( -3.1, 2.2, -1.8 )
    glRotatef( 90.0, 1.0, 0.0, 0.0 )
    glRotatef( 2.0*self.angle-2.0, 0.0, 0.0, 1.0 )
    glCallList(self.gear3)
    glPopMatrix()

    glPopMatrix()

  def resizeGL(self,width,height):
    w = width / float(height)
    h = 1.0

    glViewport( 0, 0, width, height )
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glFrustum( -w, w, -h, h, 5.0, 60.0 )
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    glTranslatef( 0.0, 0.0, -40.0 )

  def initializeGL(self):
    pos=(5.0, 5.0, 10.0, 1.0 )
    ared=(0.8, 0.1, 0.0, 1.0 )
    agreen=(0.0, 0.8, 0.2, 1.0 )
    ablue=(0.2, 0.2, 1.0, 1.0 )

    glLightfv(GL_LIGHT0,GL_POSITION,pos)
    glEnable(GL_CULL_FACE)
    glEnable(GL_LIGHTING)
    glEnable(GL_LIGHT0)
    glEnable(GL_DEPTH_TEST)

    self.gear1=glGenLists(1)
    glNewList(self.gear1,GL_COMPILE)
    glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,ared)
    gear(1.0,4.0,1.0,20,0.7)
    glEndList()

    self.gear2=glGenLists(1)
    glNewList(self.gear2,GL_COMPILE)
    glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,agreen)
    gear(0.5,2.0,2.0,10,0.7)
    glEndList()

    self.gear3=glGenLists(1)
    glNewList(self.gear3,GL_COMPILE)
    glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,ablue)
    gear(1.3,2.0,0.5,10,0.7)
    glEndList()

    glEnable(GL_NORMALIZE)

##############################################################################
if __name__=='__main__':
  QApplication.setColorSpec(QApplication.CustomColor)
  app=QApplication(sys.argv)

  if not QGLFormat.hasOpenGL():
    raise 'No Qt OpenGL support.'

  widget=GearWidget()
  app.setMainWidget(widget)
  widget.show()
  app.exec_loop()
