""" sohCahToa01.py Eric Pavey - 2009-08-08 Understand how sine, cosine, and tangent work in relationship to the opposite, adjacent, and hypotenuse triangle sides. """ #-------------- # imports & initis import math import sys import pygame from pygame.locals import * pygame.init() #-------------- # constants & global vars WIDTH = 800 HEIGHT = WIDTH FRAMERATE = 60 # size our circle is relative to screen size CIRCLESIZE = .75 font16 = pygame.font.SysFont("courier", 16) circleRadius = int(WIDTH/2 * CIRCLESIZE) #------------- # screen setup screen = pygame.display.set_mode((WIDTH, HEIGHT)) screenRect = screen.get_rect() pygame.display.set_caption("sohCahToa01.py") clock = pygame.time.Clock() #------------- # background setup: background = screen.copy() # draw the inner circle: pygame.draw.circle(background, Color("red"), screenRect.center, 4, 2) # draw the outer circle: pygame.draw.circle(background, Color("red"), screenRect.center, circleRadius, 2) lblDirections = font16.render("Press space to pause...", 1, Color("white")) background.blit(lblDirections, (8,8)) #--------- # functions def lerp2D(p1, p2, amt): # return back a point some percentage between two other points. # amt : 0.0->1.0 x = p1[0] + (p2[0] - p1[0]) * amt y = p1[1] + (p2[1] - p1[1]) * amt return [x,y] def degreesToRadians(deg): # Convert degrees to radians, returns float return (deg * math.pi) / 180.0 def degreesToPi(deg): return deg / 180.0 def distanceBetweenPoints2D(a, b): # return the distance between two points. Points are tuple (#,#) return math.sqrt(abs(pow(b[0]-a[0], 2) + pow(b[1]-a[1], 2))) def drawTriangle(radians): hypCol = Color("green") oppCol = Color("pink") adjCol = Color("orange") cx, cy = screenRect.center # define the end point of our radius \ hypotenuse: x = math.cos(radians) * circleRadius + screenRect.center[0] # Reverse Y, since the coordinate system used for the math is opposite # to that as used in pygame: y = -math.sin(radians) * circleRadius + screenRect.center[1] # draw hypotenuse: pygame.draw.line(screen, hypCol, (cx, cy), (x,y)) hypLen = distanceBetweenPoints2D((cx, cy), (x,y)) / circleRadius hypMid = lerp2D((cx, cy), (x,y), .75) # hypotenuse text: hypText = "hyp len: %.2f" % hypLen hypLbl = font16.render(hypText, 1, hypCol) screen.blit(hypLbl, (hypMid[0]-hypLbl.get_width()/2, hypMid[1])) # draw opposite: pygame.draw.line(screen, oppCol, (x,cy), (x,y)) oppLen = distanceBetweenPoints2D((x,cy), (x,y)) / circleRadius oppMid = lerp2D((x,cy), (x,y), .25) # opposite text: oppText = "opp len: %.2f" % oppLen oppLbl = font16.render(oppText, 1, oppCol) screen.blit(oppLbl, (oppMid[0]-oppLbl.get_width()/2, oppMid[1])) # draw adjacent: pygame.draw.line(screen, adjCol, (cx, cy), (x,cy)) adjLen = distanceBetweenPoints2D((cx, cy), (x,cy)) / circleRadius adjMid = lerp2D((cx,cy), (x,cy), .5) # adjacent text: adjText = "adj len: %.2f" % adjLen adjLbl = font16.render(adjText, 1, adjCol) screen.blit(adjLbl, (adjMid[0]-adjLbl.get_width()/2, adjMid[1]-20)) # calculate values from lengths: sin = 0.0 try: sin = oppLen/hypLen except ZeroDivisionError: pass cos = 0.0 try: cos = adjLen/hypLen except ZeroDivisionError: pass tan = 0.0 try: tan = oppLen/adjLen # hack: #if math.pi > radians > math.pi/2 or math.pi*1.5 < radians < math.pi*2: # tan *= -1 except ZeroDivisionError: pass # print text at bottom of screen: hypTxt = font16.render("hyp", 1, hypCol) oppTxt = font16.render("opp", 1, oppCol) adjTxt = font16.render("adj", 1, adjCol) hypNum = font16.render("%.2f"%hypLen, 1, hypCol) oppNum = font16.render("%.2f"%oppLen, 1, oppCol) adjNum = font16.render("%.2f"%adjLen, 1, adjCol) col = (128, 187, 248, 318) sohTxt = "(SOH) sin = / = / = %.2f" % sin sohLbl = font16.render(sohTxt, 1, Color("white")) screen.blit(sohLbl, (8, HEIGHT-60)) screen.blit(oppTxt, (col[0], HEIGHT-60)) screen.blit(hypTxt, (col[1], HEIGHT-60)) screen.blit(oppNum, (col[2], HEIGHT-60)) screen.blit(hypNum, (col[3], HEIGHT-60)) cahTxt = "(CAH) cos = / = / = %.2f" % cos cahLbl = font16.render(cahTxt, 1, Color("white")) screen.blit(cahLbl, (8, HEIGHT-40)) screen.blit(adjTxt, (col[0], HEIGHT-40)) screen.blit(hypTxt, (col[1], HEIGHT-40)) screen.blit(adjNum, (col[2], HEIGHT-40)) screen.blit(hypNum, (col[3], HEIGHT-40)) toaTxt = "(TOA) tan = / = / = %.2f" % tan toaLbl = font16.render(toaTxt, 1, Color("white")) screen.blit(toaLbl, (8, HEIGHT-20)) screen.blit(oppTxt, (col[0], HEIGHT-20)) screen.blit(adjTxt, (col[1], HEIGHT-20)) screen.blit(oppNum, (col[2], HEIGHT-20)) screen.blit(adjNum, (col[3], HEIGHT-20)) #------------ # main loop def main(): print "Running Python version:", sys.version print "Running PyGame version:", pygame.ver looping = True pause = 0 degrees = 0.0 while looping: if degrees > 360: degrees = 0.0 # detect for events for event in pygame.event.get(): if event.type == pygame.QUIT: looping = False elif event.type == KEYDOWN: if event.key == K_ESCAPE: looping = False if event.key == K_SPACE: pause = abs(pause-1) screen.blit(background, (0,0)) drawTriangle(degreesToRadians(degrees)) # draw the text for degrees, radians, and pi lblText = "deg: %03d, rad %.2f, pi %.02f" %(degrees, degreesToRadians(degrees), degreesToPi(degrees)) lblDegrees = font16.render(lblText, 1, Color("white")) screen.blit(lblDegrees, screenRect.center) # draw representation arc: arcRec = pygame.Rect((screenRect.center[0]-WIDTH/16, screenRect.center[1]-WIDTH/16), (WIDTH/8,WIDTH/8)) pygame.draw.arc(screen, Color("white"), arcRec, 0, degreesToRadians(degrees)) # update our display to screen: pygame.display.update() clock.tick(FRAMERATE) if not pause: degrees += .25 if __name__ == "__main__": main()