from math import *
from fractions import *
import numpy as np
import matplotlib.pyplot as plt
from tkinter import *
from tkinter import ttk

def orthogonal(ratio,phase,friction):
    
    def undamped(a,b,phi):
        
        def lissajous(t):
            xt=np.sin(a*t)
            yt=np.sin(b*t+phi)
            return xt,yt
    
        size=int(np.pi*20000)
        xs,ys=np.zeros(size),np.zeros(size)

        for index in range(size):
            (xs[index],ys[index])=lissajous(index/10000)
    
        return (xs,ys)

    def damped(a,b,phi):

        def harmonograph(t):
            xt=np.sin(a*t)*np.exp(-t/100)
            yt=np.sin(b*t+phi)*np.exp(-t/100)
        return xt,yt

        size=int(np.pi*200000)
        xs,ys=np.zeros(size),np.zeros(size)

        for index in range(size):
            (xs[index],ys[index])=harmonograph(index/10000)
    
        return (xs,ys)
    
    a,b,phi=ratio.numerator,ratio.denominator,phase*np.pi/180

    (xs,ys)=damped(a,b,phi) if friction else undamped(a,b,phi)
    
    plt.ion()
    plt.figure(1)
    plt.plot(xs,ys)
    
    return None

def getInterval(*args):
    intervalStr=interval.get()
    if intervalStr=='unison':
        intervalValue=Fraction(1,1)
    elif intervalStr=='octave':
        intervalValue=Fraction(1,2)
    elif intervalStr=='perfect fifth':
        intervalValue=Fraction(2,3)
    elif intervalStr=='perfect fourth':
        intervalValue=Fraction(3,4)
    elif intervalStr=='major third':
        intervalValue=Fraction(4,5)
    elif intervalStr=='minor third':
        intervalValue=Fraction(5,6)
    elif intervalStr=='tone':
        intervalValue=Fraction(8,9)
    else:
        intervalValue=Fraction(9,10)
    return intervalValue

def getPhase(*args):
    phaseValue=float(phase.get())
    return phaseValue

def getDisplay(*args):
    displayStr=display.get()
    displayValue=(displayStr=='Harmonograph')
    return displayValue

def start(*args):
    i=getInterval()
    p=getPhase()
    f=getDisplay()
    (xs,ys)=orthogonal(i,p,f)
    return None

root=Tk()
root.title('Pendulums')
frame=ttk.Frame(root,padding=10,borderwidth=10,relief='raised')
frame.grid(column=0,row=0,sticky=(N,W,E,S))

ttk.Label(frame,text='Interval is ').grid(column=1,row=1)
ttk.Label(frame,text='Phase is ').grid(column=1,row=2)
ttk.Label(frame,text='Display type ').grid(column=1,row=3)
ttk.Label(frame,text='Push when ready ').grid(column=1,row=4)

intervalVar=StringVar()
intervalList=['unison','octave','perfect fifth',
              'perfect fourth','major third',
              'minor third','tone','semitone']
interval=ttk.Combobox(frame,textvariable=intervalVar)
interval['values']=intervalList
interval.set('unison')
interval.bind('<<ComboboxSelected>>',getInterval)
interval.grid(column=2,row=1)

phaseVar=StringVar()
phaseList=['0','15','30','45','60','75','90']
phase=ttk.Combobox(frame,textvariable=phaseVar)
phase['values']=phaseList
phase.set('0')
phase.bind('<<ComboboxSelected>>',getPhase)
phase.grid(column=2,row=2)

displayVar=StringVar()
displayList=['Lissajous','Harmonograph']
display=ttk.Combobox(frame,textvariable=displayVar)
display['values']=displayList
display.set('Lissajous')
display.bind('<<ComboboxSelected>>',getDisplay)
display.grid(column=2,row=3)

btn=ttk.Button(frame,text='Blast off!',command=start)
btn.grid(column=2,row=4)

root.mainloop()