diff --git a/rimbalzi-1.3.py b/rimbalzi-1.3.py new file mode 100644 index 0000000..6dabdf4 --- /dev/null +++ b/rimbalzi-1.3.py @@ -0,0 +1,1001 @@ +#!/usr/bin/env python3 +from tkinter import * +from numpy import * +from struct import * +import getopt +import sys +from tkinter import filedialog as fd +from tkinter import messagebox as ms +##################################################################### +# +# rimbalzi.py 2022.06.08 Sergio Steffe' Pisa +# port in pyton del programma rimbalzi per Mac in Tthink-C del 1993, +# scritto come esercizio di python del corso di +# Algoritmi di Spettrografia del Prof. Giovanni Moruzzi 2021/22. +# +# +#################################################################### +# versioni: +# versione 1.0: 2022.06.08 versione iniziale +# versione 1.1: 2022.06.16 +# pulizia dal software delle righe usate per il debugging +# aggiunti tasti SaveAll e LoadAll, aggiornato help +# aggiunta scalatura dei dati dei files tra -s e -b e normale +# aggiunte finestre apertura files e segnalazione errori io files +# aggiunta logica per disabilitare/abilitare i bottoni +# il Fast puo' dare lampeggiamenti del disegno sul canvas +# versione 1.2: 2022.06.22 +# corretto errore in riga 580 di calcola: era scritto denom=yyas*xxs invece di + +# essendo un fattore di normalizzazione saltavano fuori errori solo nelle rare +# condizioni in cui veniva denom=0 ! +# versione 1.3: 2022.07.01 +# corretto misprints qui e li, ingranditi i punti di ancora +# versione 1.3c: 2022.07.01 +# versione per cellulari: effetto ottico per confermare il grab e punti piu' grossi. +# +################################################################### +# rimbalzi accetta i flag -s (small) -b (big) -S (Slow) -F (Fast) -v (versione) e -h (help) +# +def main(argv): + global big,small,Slow,Fast + try: + opts,args = getopt.getopt(argv,"bhsSFv") + except getopt.GetoptError: + print ('rimbalzi:\n\ + unknown option !\n\ + -b big\n\ + -s small\n\ + -S Slow\n\ + -F Fast\n\ + -v version\n\ + -h help\n') + exit(1) + big=False + small=False + Slow=False + Fast=False + for opt,arg in opts: + if opt == '-h': + print ('rimbalzi:\n\ + -b big\n\ + -s small\n\ + -S Slow\n\ + -F Fast\n\ + -v version\n\ + -h help\n') + exit() + elif opt in ('-b'): + big=True + elif opt in ('-s'): + small=True + elif opt in ('-S'): + Slow=True + elif opt in ('-F'): + Fast=True + elif opt in ('-v'): + print('rimbalzi 1.3 2022.07.01\n') + exit() +#---------------------------------------- +if __name__ == "__main__": + main(sys.argv[1:]) +#--------------------------------------- +# +# senza la parte con le chiamate a getopt occorre definire tra le globali anche +# big=False/True e small=False/True e Slow=False/True +# +# globali +RunAll=True +IsSetup=True # nel setup si possono modificare le posizioni +RunMotion=False # nel runmotion non si possono modificare le posizioni +GetData=False # per inserimento diretto numeri nelle finestre +CenterGrabbed=RadiusGrabbed=PointGrabbed=VectorGrabbed=False # per modificare graficamente le posizioni +IsLoadedall=False # i dati e le traiettorie sono stati caricati da file. +IsLoaded=False # i dati iniziali sono stati caricati da file +# due canvas e una zona comandi e finestre dati +# canvas cerchi +# quadrato di lato cl; il centro e' Ox,Oy; il cerchio fisso ha lato CR=cl/2 +# se x,y sono coordinate naturali, vanno disegnate in Ox+x,Oy-y ! e analogamente vanno convertiti gli eventi. +# +cl=800 # per canvas cerchi, quadrata, di lato cl +if big: + cl=1200 +if small: + cl=400 +CR=cl/2 # raggio cerchio fisso inscritto +Ox=400 # centro del canvasc +Oy=400 # centro del canvasc +if big: + Ox=600 + Oy=600 +if small: + Ox=200 + Oy=200 +c1=cl/5 # lunghezza vettore iniziale +cp=5 # raggio punti degli handle +# per canvas fasi : due quadrati 400x400 per rappresentare 0~180 x -90~+90 posizione e angolo rimbalzo. +fw=400 +fh=800 #fh=cl +# +if big: + fw=600 + fh=1200 #fh=cl +if small: + fw=200 + fh=400 #fh=cl +#---------------------- +Cr=cl/4 #raggio cerchio interno +Ca=cl/8 #centro cerchio interno +X0=x0=-cl/4 #punto iniziale (copia fissa e copia operativa) +Y0=y0=-cl/4 #punto iniziale (copia fissa e copia operativa) +xx=0 #variabili per il calcolo del rimbalzo +yy=0 #variabili per il calcolo del rimbalzo +angolo=0 +angolov=0 +#X0,Y0,VX0,VY0 sono quelli del save e load e appaiono nelle caselle. +#x0,y0,vx0,vy0 sono usati nei calcoli e cambiano man mano, +# e sono usati da start e restart. +vx0=30 #velocita iniziale +vy0=30 #velocita iniziale +# normalizzazione velocita +vs=sqrt(vx0*vx0+vy0*vy0) +VX0=vx0=vx0/vs +VY0=vy0=vy0/vs +# +rr=[] #punti di rimbalzo nel canvas cerchi - coppie x,y +ff=[] #punti di rimbalzo nel canvas fasi - coppie angolo, angolov +rextern=0 # numero di rimbalzi su cerchio esterno +rintern=0 # numero di rimbalzi su cerchio interno +# +# ............................................................ InRange +def InRange(xmin,x,xmax): + if x>=xmax: + return xmax + if x<=xmin: + return xmin + return x +# ................................................. Start/Stop motion +def StartStop(): + global RunMotion,IsSetup,IsLoadedall,IsLoaded + RunMotion=not RunMotion + if RunMotion: + StartButton["text"]="Stop" + else: + if IsSetup: + StartButton["text"]="Start" + else: + StartButton["text"]="Restart" + +# ...................................................... Exit program +def StopAll(): + global RunAll + RunAll=False +#........................................................ +def Setup(): + global IsSetup,rr,ff,RunMotion,x0,y0,xx,yy,vx0,vy0,rr,ff,rextern,rintern,cl,X0,Y0,VX0,VY0,IsLoadedall,IsLoaded + IsLoaded=False + IsLoadedall=False + if RunMotion==False: + IsSetup=True + xx=0 + yy=0 + x0=X0 #riinizializzazione valori operativi + y0=Y0 + vx0=VX0 + vy0=VY0 + rr=[] + ff=[] + rextern=0 + rintern=0 +# + Entryrext.delete(0,END) + Entryrint.delete(0,END) + Entryrtot.delete(0,END) + Entryrrapp.delete(0,END) +# + StartButton["text"]="Start" +#....................................................... +def Help(): + newWindow=Toplevel(root) + newWindow.title("Help") + newWindow.geometry("600x600") + Label(newWindow,text="Rimbalzi in una corona circolare asimmetrica. v.1.1\n\ +\n\ +Nella fase di SETUP, usando il mouse (cursore blu) sui punti neri, si puo' spostare\n\ +il centro del cerchio interno e cambiarne il raggio e posizionare\n\ +il vettore iniziale su cui iniziera' a muoversi un punto.\n\ +In alternativa, invece di fissare punto e vettore iniziale, si puo' scegliere\n\ +una 'fase' di partenza (cursore rosso) e in tal caso appena si clicca il\n\ +programma effettua uno START partendo dal punto della circonferenza scelto e con\n\ +l'angolo scelto con la normale al cerchio.(preview in verde mentre si muove il cursore)\n\ +All'apertura il programma e' nel modo di SETUP\n\ +\n\ +Allo START il punto inizia a rimbalzare elasticamente sulle due circonferenze.\n\ +Si puo' fermare con STOP e rilanciare con RESTART, ma se si chiama il SETUP\n\ +i dati dei rimbalzi vengono cancellati e riinizializzati.\n\ +\n\ +SAVE salva i dati di partenza (centro e raggio del cerchio interno Ca e Cr, \n\ +e posizione e velocita' iniziale del punto, X0,Y0,VX0,VY0) nel file \n\ +rimbalzi-data.txt in formato binario, e LOAD li carica da detto file.\n\ +\n\ +E' possibile durante il SETUP immettere direttamente questi dati da tastiera,\n\ +ma occorre dare un ENTER per farli accettare dal programma\n\ +\n\ +SAVEALL salva tutto nel file rimbalzi-alldata.txt in formato binario,\n\ +e LOADALL li carica da detto file. (tasti non disponibili nel formato small (-s))\n\ +\n\ +Nella parte di sinistra si vedono i cerchi e le traiettorie del punto\n\ +in movimento. Nella parte di destra sia per il cerchio EXTerno che per\n\ +quello INTerno sono segnati i punti di contatto sul cerchio (tra 0 e 360 gradi)\n\ +e l'angolo di rimbalzo rispetto la normale (tra -90 e +90 gradi).\n\ +\n\ +Questo programma e' il port in python3 con tkinter dell'analogo programma\n\ +scritto per il macintosh nel 1993 in Tkink-C.\n\ +\n\ +Sergio Steffe' Pisa 16/6/2022 ").pack() +#......................................................Save CR,Cr,Ca,X0,Y0,VX0,VY0 +def Save(): + global CR,Cr,Ca,X0,Y0,VX0,VY0 + try: + hnd=fd.asksaveasfile(mode="wb") + s=pack("7d",CR,Cr,Ca,X0,Y0,VX0,VY0) + hnd.write(s) + except : + ms.showerror(title='errore',message='non ho potuto salvare i dati') + # uuu=sys.exc_info()[0] + # ms.showerror(title='errore',message=uuu) + finally: + hnd.close() +#.......................................................Load CR,Cr,Ca,X0,Y0,VX0,VY0 +def Load(): + global CR,Cr,Ca,x0,y0,vx0,vy0,CR,X0,Y0,VX0,VY0,IsLoaded,rr,ff,rextern,rintern,RunMotion,IsLoaded,IsSetup,IsLoadedall + filename=fd.askopenfilename() + if len(filename)==0: + return None + try: + hnd=open(filename,"rb") + s=hnd.read(7*8) # 8 bytes ogni numero, 7 numeri + xin=array(unpack('d'*7, s)) + # ora vanno controllati i limiti per ciascuna variabile: + # se fuori limiti viene fatta una scelta diversa. + CRR=xin[0] # serve per scalare i dati al CR effettivo (che varia a seconda di Small, Medium o Big) + if CRR==0: + ms.showerror(title='errore',message='CR=0 ! Dati inconsistenti.') + return None + z=CR/CRR # fattore di scala: con CR tra 200 e 600 puo' andare da 3 a 1/3 + if (z<0.2)or(z>5): + ms.showerror(title='errore',message='fattore di scala inconsistente.') + return None + Crr=xin[1]*z + Crrr=InRange(0,Crr,CR*0.98) # non vogliamo cerchi quasi uguali + Caa=xin[2]*z + Ca=InRange(Crrr-CR,Caa,CR-Crrr) + Cr=InRange(0,Crr,min(CR-Ca,CR+Ca)) + EntryCa.delete(0,END) + EntryCa.insert(0,'{:.5f}'.format(Ca)) + EntryCr.delete(0,END) + EntryCr.insert(0,'{:.5f}'.format(Cr)) + x0u=(xin[3])*z + y0u=(xin[4])*z +# controllare nan error ! + su=sqrt(x0u*x0u+y0u*y0u) + if (su>1200)or(su<300): + ms.showerror(title='errore',message='punto iniziale inconsistente.') + return None + if su>CR: + x0u=x0u*CR/su + y0u=y0u*CR/su + su=sqrt(x0u*x0u+(y0u-Ca)*(y0u-Ca)) + if su=2: + IsLoadedall=True + IsSetup=False + StartButton["text"]="Restart" + #vanno riscalati rr e ff ! + for i in range(len(ff)): + ff[i]=ff[i]*z + for i in range(len(rr)): + rr[i]=rr[i]*z + else: + IsLoaded=True + IsSetup=True + StartButton["text"]="Start" + RunMotion=False + rr=[] + ff=[] + rextern=rintern=angolo=angolov=0 + except: + ms.showerror(title='errore',message='non ho potuto caricare i dati') + # contyrollare di non aver sporcato dei dati ... + finally: + hnd.close() +# ...................................................... Read entries +def ReadData(*arg): + global GetData,IsSetup + if IsSetup: + GetData=True +#........................................................Grab center +def GrabSome(event): + global CenterGrabbed,RadiusGrabbed,PointGrabbed,VectorGrabbed,Ox,Oy,Ca,Cr,x0,y0,vx0,vy0,IsSetup,cp + if IsSetup: + CenterGrabbed=((Ox-event.x)**2+(Oy-Ca -event.y)**2)CR: + x0u=x0u*CR/su + y0u=y0u*CR/su + su=sqrt(x0u*x0u+(y0u-Ca)*(y0u-Ca)) + if su fw: + Cinterno=True + rintern=1 + rextern=0 + aavv=event.y-fw + aaff=event.x*2*pi/fw + aavv=(aavv-fw/2)*pi/fw + x0=Cr*sin(aaff) + y0=Ca+Cr*cos(aaff) + vx0=sin(aaff+aavv) + vy0=cos(aaff+aavv) + rintern=1 + rextern=0 + else: + Cinterno=False + rintern=0 + rextern=1 + aavv=event.y + aaff=event.x*2*pi/fw + aavv=(aavv-fw/2)*pi/fw + x0=CR*sin(aaff) + y0=CR*cos(aaff) + vx0=-sin(aaff+aavv) + vy0=-cos(aaff+aavv) + rr.append(Ox+x0) + rr.append(Oy-y0) + X0=x0 + Y0=y0 + VX0=vx0 + VY0=vy0 + IsSetup=False + RunMotion=True + StartButton["text"]="Stop" +#------------------------------------------------------ +def Mostra(event): + global fw,fh,IsSetup,Cinterno,RunMotion,CR,Ca,Cr,x1,y1,vx1,vy1,cp + if event.y > fw: + aavv=event.y-fw + cinterno=True + else: + aavv=event.y + cinterno=False + aaff=event.x*360/fw + aavv=(aavv-fw/2)*180/fw + Entryposang.delete(0,END) + Entryposang.insert(0,'{:.5f}'.format(aaff)) + Entryvelang.delete(0,END) + Entryvelang.insert(0,'{:.5f}'.format(aavv)) +# qui mostro il punto partenza e il vettore nel canvas dei cerchi +# ma solo nel SETUP: + if IsSetup: + if cinterno: + x1=Ox+Cr*sin(aaff*pi/180) + y1=Oy-Ca-Cr*cos(aaff*pi/180) + x2=Ox+(Cr+CR*0.1)*sin(aaff*pi/180) + y2=Oy-Ca-(Cr+CR*0.1)*cos(aaff*pi/180) + x3=Ox+Cr*sin(aaff*pi/180)+CR*0.1*sin(aaff*pi/180+aavv*pi/180) + y3=Oy-Ca-Cr*cos(aaff*pi/180)- CR*0.1*cos(aaff*pi/180+aavv*pi/180) + else: + x1=Ox+CR*sin(aaff*pi/180) + y1=Oy-CR*cos(aaff*pi/180) + x2=Ox+CR*sin(aaff*pi/180)*0.9 + y2=Oy-CR*cos(aaff*pi/180)*0.9 + x3=Ox+CR*sin(aaff*pi/180)-CR*0.1*sin(aaff*pi/180+aavv*pi/180) + y3=Oy-CR*cos(aaff*pi/180)+CR*0.1*cos(aaff*pi/180+aavv*pi/180) +# canvasc.create_oval(x1-cp,y1-cp,x1+cp,y1+cp,fill="green") evidenzia il punto del cerchio + canvasc.create_line(x1,y1,x2,y2,fill="red") # perpendicolare + canvasc.create_line(x1,y1,x3,y3,fill="green",arrow=LAST) +#....................................................... +def calcola(): + global x0,y0,vx0,vy0,CR,Cr,Ca,xx,yy,vxx,vyy,Cinterno,fw,angolo,angolov,rextern,rintern +# posizione iniziale x0,y0, velocita iniziale vx0 vy0 +# CR raggio esterno, Cr raggio interno, Ca posizione centro interno +# punto di rimbalzo xx,yy con velocita vxx,vyy +# Cinterno = True se rimbalza sul cerchio interno e non esterno +# Il calcolo del rimbalzo non usa la trigonometria, che serve solo a visualizzare le fasi +#print(x0,y0,vx0,vy0,CR,Cr,Ca) + vs=sqrt(vx0*vx0+vy0*vy0) + provv1=(x0*vx0+y0*vy0)/vs + delta1=provv1*provv1-x0*x0-y0*y0+CR*CR + t1= -provv1+sqrt(delta1) + t2= -provv1-sqrt(delta1) + tm12=max(t1,t2) + tm=tm12 +# istante contatto circonferenza esterna se non esistesse interna + alfa=0 + Cinterno=False +# + provv2=provv1-Ca*vy0/vs + delta2=provv2*provv2-x0*x0-y0*y0-Ca*Ca+2*y0*Ca+Cr*Cr + if delta2 > 0 : # la retta interseca la circonferenza interna + t3=-provv2+sqrt(delta2) + t4=-provv2-sqrt(delta2) + if ((t3<0) or (t4<0)) : # ma a tempi negativi - rimbalzo su circonferenza esterna + alfa=0 + tm=tm12 + else: + tm34=min(t3,t4) + if (tm34<0): # accade solo se sto partendo dalla circonferenza interna + alfa=0 + tm=tm12 + else: + alfa=Ca + Cinterno=True + tm=tm34 + if delta2==0 : + alfa=0 + tm=tm12 + xx=x0+vx0*tm/vs + yy=y0+vy0*tm/vs + yya=yy-alfa + yyas=yya*yya + xxs=xx*xx + denom=yyas+xxs + vyy=(vy0*(xxs-yyas)-2*vx0*xx*yya)/denom/vs + vxx=(vx0*(yyas-xxs)-2*vy0*xx*yya)/denom/vs + denom=sqrt(vxx*vxx+vyy*vyy) + vxx=vxx/denom + vyy=vyy/denom +# calcolo fasi : in alto cerchio esterno, in basso cerchio interno + if Cinterno: + angolo=arctan2(xx,yy-Ca) + else: + angolo=arctan2(xx,yy) + if angolo <0: + angolo=angolo+2*pi + # ora angolo sta tra 0 e 2*pi e rappresenta il punto di rimbalzo. + angolov=arctan2(vxx,vyy)-angolo + angolov=arcsin(sin(angolov)) + # ora angolov sta tra -pi/2 e +pi/2 + # va cambiato segno di angolov esterno (perche esterno punta dentro) + if Cinterno==False: + angolov=-angolov + if Cinterno: + angolov=(angolov+pi/2)*fw/pi + fw + else: + angolov=(angolov+pi/2)*fw/pi + angolo=angolo*fw/(2*pi) +# angolov ora sta tra 0 e fw per cerchio esterno, tra fw e 2*fw per cerchio interno +# angolo sta tra 0 e fw +# aggiorno il numero dei rimbalzi fatti + if Cinterno: + rintern=rintern+1 + else: + rextern=rextern+1 +########################################################################### +# +# ................................................ Create root window +root=Tk() +root.title("rimbalzi") +root.resizable(width=False,height=False) +root.bind('',ReadData) #occorre dare un ENTER per fare leggere i dati +# ......................................... Add canvas to root window +# ..................canvasc per i cerchi e canvasf per le fasi +canvasc=Canvas(root, width=cl, height=cl, background='white') +canvasc.grid(row=0,column=0) +# ..................................................... mouse buttons +canvasc.bind("",GrabSome) +canvasc.bind("",DragSome) +canvasc.bind("",ReleaseSome) +# +canvasf=Canvas(root, width=fw, height=fh, background='white') +canvasf.grid(row=0,column=1) +# +canvasf.bind("",Clicca) +canvasf.bind("",Mostra) +# +toolbar=Frame(root) +toolbar.grid(row=0,column=2,sticky=N) +# ................................................... Toolbar buttons +SetupButton=Button(toolbar,text="Setup",command=Setup,width=7) +SetupButton.grid(row=0,column=0) +StartButton=Button(toolbar,text="Start",command=StartStop,width=7) +StartButton.grid(row=0,column=1) +SaveButton=Button(toolbar, text="Save", command=Save,width=7) +SaveButton.grid(row=1,column=0) +LoadButton=Button(toolbar, text="Load", command=Load,width=7) +LoadButton.grid(row=1,column=1) +# nella versione small non c'e' spazio per i distanziatori +if small==False: + Labspazio1=Label(toolbar,text=" ") + Labspazio1.grid(row=2,column=0) +# +# ........................................ Toolbar labels and entries +LabCr=Label(toolbar,text="Cr/CR") +LabCr.grid(row=3,column=0) +EntryCr=Entry(toolbar,bd=5,width=10) +EntryCr.grid(row=3,column=1) +# +LabCa=Label(toolbar,text="Ca/CR") +LabCa.grid(row=4,column=0) +EntryCa=Entry(toolbar,bd=5,width=10) +EntryCa.grid(row=4,column=1) +# +Labx0=Label(toolbar,text="X0/CR") +Labx0.grid(row=5,column=0) +Entryx0=Entry(toolbar,bd=5,width=10) +Entryx0.grid(row=5,column=1) +# +Laby0=Label(toolbar,text="Y0/CR") +Laby0.grid(row=6,column=0) +Entryy0=Entry(toolbar,bd=5,width=10) +Entryy0.grid(row=6,column=1) +# +Labvx0=Label(toolbar,text="VX0") +Labvx0.grid(row=7,column=0) +Entryvx0=Entry(toolbar,bd=5,width=10) +Entryvx0.grid(row=7,column=1) +# +Labvy0=Label(toolbar,text="VY0") +Labvy0.grid(row=8,column=0) +Entryvy0=Entry(toolbar,bd=5,width=10) +Entryvy0.grid(row=8,column=1) +# nella versione small non c'e' spazio per i distanziatori +if small==False: + Labspazio2=Label(toolbar,text=" ") + Labspazio2.grid(row=9,column=0) +# +CloseButton=Button(toolbar, text="Quit", command=StopAll,width=7) +CloseButton.grid(row=10,column=0) +HelpButton=Button(toolbar, text="Help", command=Help,width=7) +HelpButton.grid(row=10,column=1) +# nella versione small non c'e' spazio per i distanziatori +if small==False: + Labspazio3=Label(toolbar,text=" ") + Labspazio3.grid(row=11,column=0) +# +Labrext=Label(toolbar,text="rimb. ext") +Labrext.grid(row=12,column=0) +Entryrext=Entry(toolbar,bd=5,width=10) +Entryrext.grid(row=12,column=1) +Labrint=Label(toolbar,text="rimb. int") +Labrint.grid(row=13,column=0) +Entryrint=Entry(toolbar,bd=5,width=10) +Entryrint.grid(row=13,column=1) +# +Labrtot=Label(toolbar,text="rimb. tot") +Labrtot.grid(row=14,column=0) +Entryrtot=Entry(toolbar,bd=5,width=10) +Entryrtot.grid(row=14,column=1) +Labrrapp=Label(toolbar,text="rimb. int %") +Labrrapp.grid(row=15,column=0) +Entryrrapp=Entry(toolbar,bd=5,width=10) +Entryrrapp.grid(row=15,column=1) +# nella versione small non c'e' spazio per i distanziatori +if small==False: + Labspazio4=Label(toolbar,text=" ") + Labspazio4.grid(row=16,column=0) +# +Labposang=Label(toolbar,text="posiz. angolare") +Labposang.grid(row=17,column=0) +Entryposang=Entry(toolbar,bd=5,width=6) +Entryposang.grid(row=17,column=1) +Labvelang=Label(toolbar,text="angolo rimbalzo") +Labvelang.grid(row=18,column=0) +Entryvelang=Entry(toolbar,bd=5,width=6) +Entryvelang.grid(row=18,column=1) +# +# nella versione small non c'e' spazio per questi bottoni +if small==False: + Labspazio5=Label(toolbar,text=" ") + Labspazio5.grid(row=19,column=0) +# +SaveAllButton=Button(toolbar, text="SaveAll", command=SaveAll,width=7) +SaveAllButton.grid(row=20,column=0) +LoadAllButton=Button(toolbar, text="LoadAll", command=LoadAll,width=7) +LoadAllButton.grid(row=20,column=1) +# +# scrittura valori iniziali +EntryCa.insert(0,'{:.5f}'.format(Ca/CR)) +EntryCr.insert(0,'{:.5f}'.format(Cr/CR)) +Entryx0.insert(0,'{:.5f}'.format(X0/CR)) +Entryy0.insert(0,'{:.5f}'.format(Y0/CR)) +Entryvx0.insert(0,'{:.5f}'.format(VX0)) +Entryvy0.insert(0,'{:.5f}'.format(VY0)) +#......................................................... Variables +delay=20 #milliseconds +if Slow: + delay=200 +if Fast: + delay=5 +while RunAll: +# .............................................. Draw on canvas ---- Main Loop +# +# codiche che abilita o disabilita i bottoni a secondo delle variabili + if RunMotion: + # mentre gira non voglio poter entrare in setup, save, saveall, load, loadall : restano lo stop, lo help e il quit + SetupButton['state']=DISABLED + SaveButton['state']=DISABLED + SaveAllButton['state']=DISABLED + LoadButton['state']=DISABLED + LoadAllButton['state']=DISABLED + else: + SetupButton['state']=NORMAL + SaveButton['state']=NORMAL + SaveAllButton['state']=NORMAL + LoadButton['state']=NORMAL + LoadAllButton['state']=NORMAL + + if IsLoadedall or IsLoaded: + canvasf.delete(ALL) + canvasc.delete(ALL) +# canvasc.create_oval(Ox-cp,Oy-Ca-cp,Ox+cp,Oy-Ca+cp,fill="black") # centro cerchio interno, mobile +# canvasc.create_oval(Ox-cp+Cr/sqrt(2),Oy-Ca-cp+Cr/sqrt(2),Ox+cp+Cr/sqrt(2),Oy-Ca+cp+Cr/sqrt(2),fill="black") # maniglia per cambiare raggio +# canvasc.create_oval(Ox+x0-cp,Oy-y0-cp,Ox+x0+cp,Oy-y0+cp,fill="black") # maniglia per spostare il punto di partenza +# canvasc.create_oval(Ox+x0-cp+vx0*c1,Oy-y0-cp-vy0*c1,Ox+x0+cp+vx0*c1,Oy-y0+cp-vy0*c1,fill="black") # maniglia per spostare il vettore di partenza + if IsLoaded: + canvasc.create_line(Ox+x0,Oy-y0,Ox+x0+vx0*c1,Oy-y0-vy0*c1,arrow=LAST) # freccia del vettore iniziale + canvasc.config(cursor="target blue") #cursore tondo blu sul canvas dei cerchi + canvasf.config(cursor="target red") #cursore tondo rosso sul canvas delle fasi + + if IsSetup: + canvasf.delete(ALL) + canvasc.delete(ALL) + canvasc.create_oval(Ox-cp,Oy-Ca-cp,Ox+cp,Oy-Ca+cp,fill="black") # centro cerchio interno, mobile + canvasc.create_oval(Ox-cp+Cr/sqrt(2),Oy-Ca-cp+Cr/sqrt(2),Ox+cp+Cr/sqrt(2),Oy-Ca+cp+Cr/sqrt(2),fill="black") # maniglia per cambiare raggio + canvasc.create_oval(Ox+x0-cp,Oy-y0-cp,Ox+x0+cp,Oy-y0+cp,fill="black") # maniglia per spostare il punto di partenza + canvasc.create_oval(Ox+x0-cp+vx0*c1,Oy-y0-cp-vy0*c1,Ox+x0+cp+vx0*c1,Oy-y0+cp-vy0*c1,fill="black") # maniglia per spostare il vettore di partenza + canvasc.create_line(Ox+x0,Oy-y0,Ox+x0+vx0*c1,Oy-y0-vy0*c1,arrow=LAST) # freccia del vettore iniziale + canvasc.config(cursor="target blue") #cursore tondo blu sul canvas dei cerchi + canvasf.config(cursor="target red") #cursore tondo rosso sul canvas delle fasi + if GetData: #input dei dati permesso solo nella fase di SETUP +# va controllato che i dati siano consistenti + try: + eCa=float(EntryCa.get()) + except ValueError: + pass + try: + eCr=float(EntryCr.get()) + except ValueError: + pass + try: + ex0=float(Entryx0.get()) + except ValueError: + pass + try: + ey0=float(Entryy0.get()) + except ValueError: + pass + try: + evx0=float(Entryvx0.get()) + except ValueError: + pass + try: + evy0=float(Entryvy0.get()) + except ValueError: + pass + Ca=InRange(Cr-CR,eCa,CR-Cr) + Cr=InRange(0,eCr,min(CR-Ca,CR+Ca)) + su=sqrt(ex0*ex0+ey0*ey0) + if su>CR: + ex0=ex0*CR/su + ey0=ey0*CR/su + su=sqrt(ex0*ex0+(ey0-Ca)*(ey0-Ca)) + if su=xmax: + return xmax + if x<=xmin: + return xmin + return x +# ................................................. Start/Stop motion +def StartStop(): + global RunMotion,IsSetup,IsLoadedall,IsLoaded + RunMotion=not RunMotion + if RunMotion: + StartButton["text"]="Stop" + else: + if IsSetup: + StartButton["text"]="Start" + else: + StartButton["text"]="Restart" + +# ...................................................... Exit program +def StopAll(): + global RunAll + RunAll=False +#........................................................ +def Setup(): + global IsSetup,rr,ff,RunMotion,x0,y0,xx,yy,vx0,vy0,rr,ff,rextern,rintern,cl,X0,Y0,VX0,VY0,IsLoadedall,IsLoaded + IsLoaded=False + IsLoadedall=False + if RunMotion==False: + IsSetup=True + xx=0 + yy=0 + x0=X0 #riinizializzazione valori operativi + y0=Y0 + vx0=VX0 + vy0=VY0 + rr=[] + ff=[] + rextern=0 + rintern=0 +# + Entryrext.delete(0,END) + Entryrint.delete(0,END) + Entryrtot.delete(0,END) + Entryrrapp.delete(0,END) +# + StartButton["text"]="Start" +#....................................................... +def Help(): + newWindow=Toplevel(root) + newWindow.title("Help") + newWindow.geometry("600x600") + Label(newWindow,text="Rimbalzi in una corona circolare asimmetrica. v.1.1\n\ +\n\ +Nella fase di SETUP, usando il mouse (cursore blu) sui punti neri, si puo' spostare\n\ +il centro del cerchio interno e cambiarne il raggio e posizionare\n\ +il vettore iniziale su cui iniziera' a muoversi un punto.\n\ +In alternativa, invece di fissare punto e vettore iniziale, si puo' scegliere\n\ +una 'fase' di partenza (cursore rosso) e in tal caso appena si clicca il\n\ +programma effettua uno START partendo dal punto della circonferenza scelto e con\n\ +l'angolo scelto con la normale al cerchio.(preview in verde mentre si muove il cursore)\n\ +All'apertura il programma e' nel modo di SETUP\n\ +\n\ +Allo START il punto inizia a rimbalzare elasticamente sulle due circonferenze.\n\ +Si puo' fermare con STOP e rilanciare con RESTART, ma se si chiama il SETUP\n\ +i dati dei rimbalzi vengono cancellati e riinizializzati.\n\ +\n\ +SAVE salva i dati di partenza (centro e raggio del cerchio interno Ca e Cr, \n\ +e posizione e velocita' iniziale del punto, X0,Y0,VX0,VY0) nel file \n\ +rimbalzi-data.txt in formato binario, e LOAD li carica da detto file.\n\ +\n\ +E' possibile durante il SETUP immettere direttamente questi dati da tastiera,\n\ +ma occorre dare un ENTER per farli accettare dal programma\n\ +\n\ +SAVEALL salva tutto nel file rimbalzi-alldata.txt in formato binario,\n\ +e LOADALL li carica da detto file. (tasti non disponibili nel formato small (-s))\n\ +\n\ +Nella parte di sinistra si vedono i cerchi e le traiettorie del punto\n\ +in movimento. Nella parte di destra sia per il cerchio EXTerno che per\n\ +quello INTerno sono segnati i punti di contatto sul cerchio (tra 0 e 360 gradi)\n\ +e l'angolo di rimbalzo rispetto la normale (tra -90 e +90 gradi).\n\ +\n\ +Questo programma e' il port in python3 con tkinter dell'analogo programma\n\ +scritto per il macintosh nel 1993 in Tkink-C.\n\ +\n\ +Sergio Steffe' Pisa 16/6/2022 ").pack() +#......................................................Save CR,Cr,Ca,X0,Y0,VX0,VY0 +def Save(): + global CR,Cr,Ca,X0,Y0,VX0,VY0 + try: + hnd=fd.asksaveasfile(mode="wb") + s=pack("7d",CR,Cr,Ca,X0,Y0,VX0,VY0) + hnd.write(s) + except : + ms.showerror(title='errore',message='non ho potuto salvare i dati') + # uuu=sys.exc_info()[0] + # ms.showerror(title='errore',message=uuu) + finally: + hnd.close() +#.......................................................Load CR,Cr,Ca,X0,Y0,VX0,VY0 +def Load(): + global CR,Cr,Ca,x0,y0,vx0,vy0,CR,X0,Y0,VX0,VY0,IsLoaded,rr,ff,rextern,rintern,RunMotion,IsLoaded,IsSetup,IsLoadedall + filename=fd.askopenfilename() + if len(filename)==0: + return None + try: + hnd=open(filename,"rb") + s=hnd.read(7*8) # 8 bytes ogni numero, 7 numeri + xin=array(unpack('d'*7, s)) + # ora vanno controllati i limiti per ciascuna variabile: + # se fuori limiti viene fatta una scelta diversa. + CRR=xin[0] # serve per scalare i dati al CR effettivo (che varia a seconda di Small, Medium o Big) + if CRR==0: + ms.showerror(title='errore',message='CR=0 ! Dati inconsistenti.') + return None + z=CR/CRR # fattore di scala: con CR tra 200 e 600 puo' andare da 3 a 1/3 + if (z<0.2)or(z>5): + ms.showerror(title='errore',message='fattore di scala inconsistente.') + return None + Crr=xin[1]*z + Crrr=InRange(0,Crr,CR*0.98) # non vogliamo cerchi quasi uguali + Caa=xin[2]*z + Ca=InRange(Crrr-CR,Caa,CR-Crrr) + Cr=InRange(0,Crr,min(CR-Ca,CR+Ca)) + EntryCa.delete(0,END) + EntryCa.insert(0,'{:.5f}'.format(Ca)) + EntryCr.delete(0,END) + EntryCr.insert(0,'{:.5f}'.format(Cr)) + x0u=(xin[3])*z + y0u=(xin[4])*z +# controllare nan error ! + su=sqrt(x0u*x0u+y0u*y0u) + if (su>1200)or(su<300): + ms.showerror(title='errore',message='punto iniziale inconsistente.') + return None + if su>CR: + x0u=x0u*CR/su + y0u=y0u*CR/su + su=sqrt(x0u*x0u+(y0u-Ca)*(y0u-Ca)) + if su=2: + IsLoadedall=True + IsSetup=False + StartButton["text"]="Restart" + #vanno riscalati rr e ff ! + for i in range(len(ff)): + ff[i]=ff[i]*z + for i in range(len(rr)): + rr[i]=rr[i]*z + else: + IsLoaded=True + IsSetup=True + StartButton["text"]="Start" + RunMotion=False + rr=[] + ff=[] + rextern=rintern=angolo=angolov=0 + except: + ms.showerror(title='errore',message='non ho potuto caricare i dati') + # contyrollare di non aver sporcato dei dati ... + finally: + hnd.close() +# ...................................................... Read entries +def ReadData(*arg): + global GetData,IsSetup + if IsSetup: + GetData=True +#........................................................Grab center +def GrabSome(event): + global CenterGrabbed,RadiusGrabbed,PointGrabbed,VectorGrabbed,Ox,Oy,Ca,Cr,x0,y0,vx0,vy0,IsSetup,cp,ttt + if IsSetup: + CenterGrabbed=((Ox-event.x)**2+(Oy-Ca -event.y)**2)CR: + x0u=x0u*CR/su + y0u=y0u*CR/su + su=sqrt(x0u*x0u+(y0u-Ca)*(y0u-Ca)) + if su fw: + Cinterno=True + rintern=1 + rextern=0 + aavv=event.y-fw + aaff=event.x*2*pi/fw + aavv=(aavv-fw/2)*pi/fw + x0=Cr*sin(aaff) + y0=Ca+Cr*cos(aaff) + vx0=sin(aaff+aavv) + vy0=cos(aaff+aavv) + rintern=1 + rextern=0 + else: + Cinterno=False + rintern=0 + rextern=1 + aavv=event.y + aaff=event.x*2*pi/fw + aavv=(aavv-fw/2)*pi/fw + x0=CR*sin(aaff) + y0=CR*cos(aaff) + vx0=-sin(aaff+aavv) + vy0=-cos(aaff+aavv) + rr.append(Ox+x0) + rr.append(Oy-y0) + X0=x0 + Y0=y0 + VX0=vx0 + VY0=vy0 + IsSetup=False + RunMotion=True + StartButton["text"]="Stop" +#------------------------------------------------------ +def Mostra(event): + global fw,fh,IsSetup,Cinterno,RunMotion,CR,Ca,Cr,x1,y1,vx1,vy1,cp + if event.y > fw: + aavv=event.y-fw + cinterno=True + else: + aavv=event.y + cinterno=False + aaff=event.x*360/fw + aavv=(aavv-fw/2)*180/fw + Entryposang.delete(0,END) + Entryposang.insert(0,'{:.5f}'.format(aaff)) + Entryvelang.delete(0,END) + Entryvelang.insert(0,'{:.5f}'.format(aavv)) +# qui mostro il punto partenza e il vettore nel canvas dei cerchi +# ma solo nel SETUP: + if IsSetup: + if cinterno: + x1=Ox+Cr*sin(aaff*pi/180) + y1=Oy-Ca-Cr*cos(aaff*pi/180) + x2=Ox+(Cr+CR*0.1)*sin(aaff*pi/180) + y2=Oy-Ca-(Cr+CR*0.1)*cos(aaff*pi/180) + x3=Ox+Cr*sin(aaff*pi/180)+CR*0.1*sin(aaff*pi/180+aavv*pi/180) + y3=Oy-Ca-Cr*cos(aaff*pi/180)- CR*0.1*cos(aaff*pi/180+aavv*pi/180) + else: + x1=Ox+CR*sin(aaff*pi/180) + y1=Oy-CR*cos(aaff*pi/180) + x2=Ox+CR*sin(aaff*pi/180)*0.9 + y2=Oy-CR*cos(aaff*pi/180)*0.9 + x3=Ox+CR*sin(aaff*pi/180)-CR*0.1*sin(aaff*pi/180+aavv*pi/180) + y3=Oy-CR*cos(aaff*pi/180)+CR*0.1*cos(aaff*pi/180+aavv*pi/180) +# canvasc.create_oval(x1-cp,y1-cp,x1+cp,y1+cp,fill="green") evidenzia il punto del cerchio + canvasc.create_line(x1,y1,x2,y2,fill="red") # perpendicolare + canvasc.create_line(x1,y1,x3,y3,fill="green",arrow=LAST) +#....................................................... +def calcola(): + global x0,y0,vx0,vy0,CR,Cr,Ca,xx,yy,vxx,vyy,Cinterno,fw,angolo,angolov,rextern,rintern +# posizione iniziale x0,y0, velocita iniziale vx0 vy0 +# CR raggio esterno, Cr raggio interno, Ca posizione centro interno +# punto di rimbalzo xx,yy con velocita vxx,vyy +# Cinterno = True se rimbalza sul cerchio interno e non esterno +# Il calcolo del rimbalzo non usa la trigonometria, che serve solo a visualizzare le fasi +#print(x0,y0,vx0,vy0,CR,Cr,Ca) + vs=sqrt(vx0*vx0+vy0*vy0) + provv1=(x0*vx0+y0*vy0)/vs + delta1=provv1*provv1-x0*x0-y0*y0+CR*CR + t1= -provv1+sqrt(delta1) + t2= -provv1-sqrt(delta1) + tm12=max(t1,t2) + tm=tm12 +# istante contatto circonferenza esterna se non esistesse interna + alfa=0 + Cinterno=False +# + provv2=provv1-Ca*vy0/vs + delta2=provv2*provv2-x0*x0-y0*y0-Ca*Ca+2*y0*Ca+Cr*Cr + if delta2 > 0 : # la retta interseca la circonferenza interna + t3=-provv2+sqrt(delta2) + t4=-provv2-sqrt(delta2) + if ((t3<0) or (t4<0)) : # ma a tempi negativi - rimbalzo su circonferenza esterna + alfa=0 + tm=tm12 + else: + tm34=min(t3,t4) + if (tm34<0): # accade solo se sto partendo dalla circonferenza interna + alfa=0 + tm=tm12 + else: + alfa=Ca + Cinterno=True + tm=tm34 + if delta2==0 : + alfa=0 + tm=tm12 + xx=x0+vx0*tm/vs + yy=y0+vy0*tm/vs + yya=yy-alfa + yyas=yya*yya + xxs=xx*xx + denom=yyas+xxs + vyy=(vy0*(xxs-yyas)-2*vx0*xx*yya)/denom/vs + vxx=(vx0*(yyas-xxs)-2*vy0*xx*yya)/denom/vs + denom=sqrt(vxx*vxx+vyy*vyy) + vxx=vxx/denom + vyy=vyy/denom +# calcolo fasi : in alto cerchio esterno, in basso cerchio interno + if Cinterno: + angolo=arctan2(xx,yy-Ca) + else: + angolo=arctan2(xx,yy) + if angolo <0: + angolo=angolo+2*pi + # ora angolo sta tra 0 e 2*pi e rappresenta il punto di rimbalzo. + angolov=arctan2(vxx,vyy)-angolo + angolov=arcsin(sin(angolov)) + # ora angolov sta tra -pi/2 e +pi/2 + # va cambiato segno di angolov esterno (perche esterno punta dentro) + if Cinterno==False: + angolov=-angolov + if Cinterno: + angolov=(angolov+pi/2)*fw/pi + fw + else: + angolov=(angolov+pi/2)*fw/pi + angolo=angolo*fw/(2*pi) +# angolov ora sta tra 0 e fw per cerchio esterno, tra fw e 2*fw per cerchio interno +# angolo sta tra 0 e fw +# aggiorno il numero dei rimbalzi fatti + if Cinterno: + rintern=rintern+1 + else: + rextern=rextern+1 +########################################################################### +# +# ................................................ Create root window +root=Tk() +root.title("rimbalzi") +root.resizable(width=False,height=False) +root.bind('',ReadData) #occorre dare un ENTER per fare leggere i dati +# ......................................... Add canvas to root window +# ..................canvasc per i cerchi e canvasf per le fasi +canvasc=Canvas(root, width=cl, height=cl, background='white') +canvasc.grid(row=0,column=0) +# ..................................................... mouse buttons +canvasc.bind("",GrabSome) +canvasc.bind("",DragSome) +canvasc.bind("",ReleaseSome) +# +canvasf=Canvas(root, width=fw, height=fh, background='white') +canvasf.grid(row=0,column=1) +# +canvasf.bind("",Clicca) +canvasf.bind("",Mostra) +# +toolbar=Frame(root) +toolbar.grid(row=0,column=2,sticky=N) +# ................................................... Toolbar buttons +SetupButton=Button(toolbar,text="Setup",command=Setup,width=7) +SetupButton.grid(row=0,column=0) +StartButton=Button(toolbar,text="Start",command=StartStop,width=7) +StartButton.grid(row=0,column=1) +SaveButton=Button(toolbar, text="Save", command=Save,width=7) +SaveButton.grid(row=1,column=0) +LoadButton=Button(toolbar, text="Load", command=Load,width=7) +LoadButton.grid(row=1,column=1) +# nella versione small non c'e' spazio per i distanziatori +if small==False: + Labspazio1=Label(toolbar,text=" ") + Labspazio1.grid(row=2,column=0) +# +# ........................................ Toolbar labels and entries +LabCr=Label(toolbar,text="Cr/CR") +LabCr.grid(row=3,column=0) +EntryCr=Entry(toolbar,bd=5,width=10) +EntryCr.grid(row=3,column=1) +# +LabCa=Label(toolbar,text="Ca/CR") +LabCa.grid(row=4,column=0) +EntryCa=Entry(toolbar,bd=5,width=10) +EntryCa.grid(row=4,column=1) +# +Labx0=Label(toolbar,text="X0/CR") +Labx0.grid(row=5,column=0) +Entryx0=Entry(toolbar,bd=5,width=10) +Entryx0.grid(row=5,column=1) +# +Laby0=Label(toolbar,text="Y0/CR") +Laby0.grid(row=6,column=0) +Entryy0=Entry(toolbar,bd=5,width=10) +Entryy0.grid(row=6,column=1) +# +Labvx0=Label(toolbar,text="VX0") +Labvx0.grid(row=7,column=0) +Entryvx0=Entry(toolbar,bd=5,width=10) +Entryvx0.grid(row=7,column=1) +# +Labvy0=Label(toolbar,text="VY0") +Labvy0.grid(row=8,column=0) +Entryvy0=Entry(toolbar,bd=5,width=10) +Entryvy0.grid(row=8,column=1) +# nella versione small non c'e' spazio per i distanziatori +if small==False: + Labspazio2=Label(toolbar,text=" ") + Labspazio2.grid(row=9,column=0) +# +CloseButton=Button(toolbar, text="Quit", command=StopAll,width=7) +CloseButton.grid(row=10,column=0) +HelpButton=Button(toolbar, text="Help", command=Help,width=7) +HelpButton.grid(row=10,column=1) +# nella versione small non c'e' spazio per i distanziatori +if small==False: + Labspazio3=Label(toolbar,text=" ") + Labspazio3.grid(row=11,column=0) +# +Labrext=Label(toolbar,text="rimb. ext") +Labrext.grid(row=12,column=0) +Entryrext=Entry(toolbar,bd=5,width=10) +Entryrext.grid(row=12,column=1) +Labrint=Label(toolbar,text="rimb. int") +Labrint.grid(row=13,column=0) +Entryrint=Entry(toolbar,bd=5,width=10) +Entryrint.grid(row=13,column=1) +# +Labrtot=Label(toolbar,text="rimb. tot") +Labrtot.grid(row=14,column=0) +Entryrtot=Entry(toolbar,bd=5,width=10) +Entryrtot.grid(row=14,column=1) +Labrrapp=Label(toolbar,text="rimb. int %") +Labrrapp.grid(row=15,column=0) +Entryrrapp=Entry(toolbar,bd=5,width=10) +Entryrrapp.grid(row=15,column=1) +# nella versione small non c'e' spazio per i distanziatori +if small==False: + Labspazio4=Label(toolbar,text=" ") + Labspazio4.grid(row=16,column=0) +# +Labposang=Label(toolbar,text="posiz. angolare") +Labposang.grid(row=17,column=0) +Entryposang=Entry(toolbar,bd=5,width=6) +Entryposang.grid(row=17,column=1) +Labvelang=Label(toolbar,text="angolo rimbalzo") +Labvelang.grid(row=18,column=0) +Entryvelang=Entry(toolbar,bd=5,width=6) +Entryvelang.grid(row=18,column=1) +# +# nella versione small non c'e' spazio per questi bottoni +if small==False: + Labspazio5=Label(toolbar,text=" ") + Labspazio5.grid(row=19,column=0) +# +SaveAllButton=Button(toolbar, text="SaveAll", command=SaveAll,width=7) +SaveAllButton.grid(row=20,column=0) +LoadAllButton=Button(toolbar, text="LoadAll", command=LoadAll,width=7) +LoadAllButton.grid(row=20,column=1) +# +# scrittura valori iniziali +EntryCa.insert(0,'{:.5f}'.format(Ca/CR)) +EntryCr.insert(0,'{:.5f}'.format(Cr/CR)) +Entryx0.insert(0,'{:.5f}'.format(X0/CR)) +Entryy0.insert(0,'{:.5f}'.format(Y0/CR)) +Entryvx0.insert(0,'{:.5f}'.format(VX0)) +Entryvy0.insert(0,'{:.5f}'.format(VY0)) +#......................................................... Variables +delay=20 #milliseconds +if Slow: + delay=200 +if Fast: + delay=5 +while RunAll: +# .............................................. Draw on canvas ---- Main Loop +# +# codiche che abilita o disabilita i bottoni a secondo delle variabili + if RunMotion: + # mentre gira non voglio poter entrare in setup, save, saveall, load, loadall : restano lo stop, lo help e il quit + SetupButton['state']=DISABLED + SaveButton['state']=DISABLED + SaveAllButton['state']=DISABLED + LoadButton['state']=DISABLED + LoadAllButton['state']=DISABLED + else: + SetupButton['state']=NORMAL + SaveButton['state']=NORMAL + SaveAllButton['state']=NORMAL + LoadButton['state']=NORMAL + LoadAllButton['state']=NORMAL + + if IsLoadedall or IsLoaded: + canvasf.delete(ALL) + canvasc.delete(ALL) +# canvasc.create_oval(Ox-cp,Oy-Ca-cp,Ox+cp,Oy-Ca+cp,fill="black") # centro cerchio interno, mobile +# canvasc.create_oval(Ox-cp+Cr/sqrt(2),Oy-Ca-cp+Cr/sqrt(2),Ox+cp+Cr/sqrt(2),Oy-Ca+cp+Cr/sqrt(2),fill="black") # maniglia per cambiare raggio +# canvasc.create_oval(Ox+x0-cp,Oy-y0-cp,Ox+x0+cp,Oy-y0+cp,fill="black") # maniglia per spostare il punto di partenza +# canvasc.create_oval(Ox+x0-cp+vx0*c1,Oy-y0-cp-vy0*c1,Ox+x0+cp+vx0*c1,Oy-y0+cp-vy0*c1,fill="black") # maniglia per spostare il vettore di partenza + if IsLoaded: + canvasc.create_line(Ox+x0,Oy-y0,Ox+x0+vx0*c1,Oy-y0-vy0*c1,arrow=LAST) # freccia del vettore iniziale + canvasc.config(cursor="target blue") #cursore tondo blu sul canvas dei cerchi + canvasf.config(cursor="target red") #cursore tondo rosso sul canvas delle fasi + + if IsSetup: + canvasf.delete(ALL) + canvasc.delete(ALL) + if CenterGrabbed: #effetto ottico quando si ottiene il grab + if ttt==1: + canvasc.create_oval(Ox-2*cp,Oy-Ca-2*cp,Ox+2*cp,Oy-Ca+2*cp,fill="blue") # centro cerchio interno, mobile blue + ttt=0 + if ttt==2: + canvasc.create_oval(Ox-4*cp,Oy-Ca-4*cp,Ox+4*cp,Oy-Ca+4*cp,fill="blue") # + ttt=1 + if ttt==3: + canvasc.create_oval(Ox-5*cp,Oy-Ca-5*cp,Ox+5*cp,Oy-Ca+5*cp,fill="blue") # + ttt=2 + canvasc.create_oval(Ox-cp,Oy-Ca-cp,Ox+cp,Oy-Ca+cp,fill="black") # centro cerchio interno, mobile nero + if RadiusGrabbed: #effetto ottico quando si ottiene il grab + if ttt==1: + canvasc.create_oval(Ox-2*cp+Cr/sqrt(2),Oy-Ca-2*cp+Cr/sqrt(2),Ox+2*cp+Cr/sqrt(2),Oy-Ca+2*cp+Cr/sqrt(2),fill="blue") # maniglia per cambiare raggio blue + ttt=0 + if ttt==2: + canvasc.create_oval(Ox-4*cp+Cr/sqrt(2),Oy-Ca-4*cp+Cr/sqrt(2),Ox+4*cp+Cr/sqrt(2),Oy-Ca+4*cp+Cr/sqrt(2),fill="blue") # + ttt=1 + if ttt==3: + canvasc.create_oval(Ox-5*cp+Cr/sqrt(2),Oy-Ca-5*cp+Cr/sqrt(2),Ox+5*cp+Cr/sqrt(2),Oy-Ca+5*cp+Cr/sqrt(2),fill="blue") # + ttt=2 + canvasc.create_oval(Ox-cp+Cr/sqrt(2),Oy-Ca-cp+Cr/sqrt(2),Ox+cp+Cr/sqrt(2),Oy-Ca+cp+Cr/sqrt(2),fill="black") # maniglia per cambiare raggio nero + if PointGrabbed: #effetto ottico quando si ottiene il grab + if ttt==1: + canvasc.create_oval(Ox+x0-2*cp,Oy-y0-2*cp,Ox+x0+2*cp,Oy-y0+2*cp,fill="blue") # maniglia per spostare il punto di partenza blu + ttt=0 + if ttt==2: + canvasc.create_oval(Ox+x0-4*cp,Oy-y0-4*cp,Ox+x0+4*cp,Oy-y0+4*cp,fill="blue") # + ttt=1 + if ttt==3: + canvasc.create_oval(Ox+x0-5*cp,Oy-y0-5*cp,Ox+x0+5*cp,Oy-y0+5*cp,fill="blue") # + ttt=2 + canvasc.create_oval(Ox+x0-cp,Oy-y0-cp,Ox+x0+cp,Oy-y0+cp,fill="black") # maniglia per spostare il punto di partenza nero + if VectorGrabbed: #effetto ottico quando si ottiene il grab + if ttt==1: + canvasc.create_oval(Ox+x0-2*cp+vx0*c1,Oy-y0-2*cp-vy0*c1,Ox+x0+2*cp+vx0*c1,Oy-y0+2*cp-vy0*c1,fill="blue") # maniglia per spostare il vettore di partenza blu + ttt=0 + if ttt==2: + canvasc.create_oval(Ox+x0-4*cp+vx0*c1,Oy-y0-4*cp-vy0*c1,Ox+x0+4*cp+vx0*c1,Oy-y0+4*cp-vy0*c1,fill="blue") # + ttt=1 + if ttt==3: + canvasc.create_oval(Ox+x0-5*cp+vx0*c1,Oy-y0-5*cp-vy0*c1,Ox+x0+5*cp+vx0*c1,Oy-y0+5*cp-vy0*c1,fill="blue") # + ttt=2 + + canvasc.create_oval(Ox+x0-cp+vx0*c1,Oy-y0-cp-vy0*c1,Ox+x0+cp+vx0*c1,Oy-y0+cp-vy0*c1,fill="black") # maniglia per spostare il vettore di partenza + + canvasc.create_line(Ox+x0,Oy-y0,Ox+x0+vx0*c1,Oy-y0-vy0*c1,arrow=LAST) # freccia del vettore iniziale + canvasc.config(cursor="target blue") #cursore tondo blu sul canvas dei cerchi + canvasf.config(cursor="target red") #cursore tondo rosso sul canvas delle fasi + if GetData: #input dei dati permesso solo nella fase di SETUP +# va controllato che i dati siano consistenti + try: + eCa=float(EntryCa.get()) + except ValueError: + pass + try: + eCr=float(EntryCr.get()) + except ValueError: + pass + try: + ex0=float(Entryx0.get()) + except ValueError: + pass + try: + ey0=float(Entryy0.get()) + except ValueError: + pass + try: + evx0=float(Entryvx0.get()) + except ValueError: + pass + try: + evy0=float(Entryvy0.get()) + except ValueError: + pass + Ca=InRange(Cr-CR,eCa,CR-Cr) + Cr=InRange(0,eCr,min(CR-Ca,CR+Ca)) + su=sqrt(ex0*ex0+ey0*ey0) + if su>CR: + ex0=ex0*CR/su + ey0=ey0*CR/su + su=sqrt(ex0*ex0+(ey0-Ca)*(ey0-Ca)) + if su