#!/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