// ................................................................ xpendolo.cc
#include <curses.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <corso.h>

extern XVideoData xvd;

void func(double *t,double *y,double *dydt);

main()
{
	int DeltaSave,i,ii,ix,ix0,iy,iy0,iyf,iyf0,mx,my,nComm,nPar;
	double alpha,dt,step,tMax,tMin,yScale,yScale2;
	double *tt,*y;
	char answ[122],buff[40];
	char **comandi,**ParName,**ParVal;
	clock_t musec1,musec2;
	timespec ts1,ts2;
	FILE *hnd;
	// ............................................................. modo grafico
	StartXWindow(800,600,0,0,"Pendolo",1);
	XSelectInput(xvd.display,xvd.win[0],ButtonPressMask|ButtonReleaseMask|
			PointerMotionMask|KeyPressMask|KeyReleaseMask|ExposureMask|
					StructureNotifyMask);
	// ...................................................... allocazione memoria
	nPar=2;
	ParName=new char * [nPar];
	ParVal=new char * [nPar];
	for (i=0;i<nPar;i++) ParVal[i]=new char [24];
	ParName[0]="g/l";
	ParName[1]="smorzamento";
	// .................................................................. comandi
	nComm=4;
	comandi=new char * [nComm];
	comandi[0]="caduta";
	comandi[1]="calcione";
	comandi[2]="ferma";
	comandi[3]="fine";
	// .......................................................... allocate arrays
	tt=new double [4];
	y=new double [2];
	// ................................................................. costanti
	tt[1]=10.0; //      g/l
	tt[2]=0.05; //        smorzamento
	sprintf(ParVal[0],"%.4lf",tt[1]);
	sprintf(ParVal[1],"%.4lf",tt[2]);
	// ...................................................... condizioni iniziali
	y[0]=90.0; //         angolo iniziale
	y[1]=0.0; //         velocita' iniziale
	// ...................................................... intervallo di tempo
	step=0.02;
	// ............................................................ campionamento
	DeltaSave=1;
	// ........................................................... punti iniziali
	ix0=400;
	iy0=20;
	// .......................................................... disegna il menu
	XPermMenu(1,"pendolo",ParName,ParVal,nPar,16,comandi,nComm,20,400,&mx,&my,0,0);
	// ............................................... primo passo di Runge-Kutta
	tt[0]=0;
	RungeStep(tt,y,2,step,0,func);
	XSync(xvd.display,TRUE);
	// ..........................................................................
	ts1.tv_sec=0;
	// ..................................................... ciclo di Runge Kutta
	for (;;)
	{
		musec1=clock();
		RungeStep(tt,y,2,step,1,func);
		if (i%DeltaSave) continue;
		// ................................ seleziona e pulisci il contesto grafico
		XSetForeground(xvd.display,xvd.gc,xvd.white);
		XFillRectangle(xvd.display,xvd.backpix[0],xvd.gc,0,0,800,400);
		// ..................................................... disegna il pendolo
		XSetForeground(xvd.display,xvd.gc,xvd.black);
		XFillArc(xvd.display,xvd.backpix[0],xvd.gc,ix0-2,iy0-2,4,4,0,23040);
		alpha=M_PI*y[0]/180.0;
		iy=iy0+int(350.0*cos(alpha)+0.5);
		ix=ix0+int(350.0*sin(alpha)+0.5);
		XDrawLine(xvd.display,xvd.backpix[0],xvd.gc,ix0,iy0,ix,iy);
		XSetForeground(xvd.display,xvd.gc,xvd.red[1]);
		ix-=10;
		iy-=10;
		XFillArc(xvd.display,xvd.backpix[0],xvd.gc,ix,iy,20,20,0,23040);
		XCopyArea(xvd.display,xvd.backpix[0],xvd.win[0],xvd.gc,0,0,800,400,0,0);
		XSync(xvd.display,FALSE);
		// .......................................................... leggi il menu
		ii=XPermMenu(1,"pendolo",ParName,ParVal,nPar,16,comandi,nComm,20,
								 400,&mx,&my,1,0);
		if (ii==0)
		{ // ............................................................... caduta
			tt[0]=0;
			y[0]=90.0;
			y[1]=0.0;
		}
		else if (ii==1)
		{ // ............................................................. calcione
			tt[0]=0;
			y[0]=0.0;
			y[1]=sqrt(2.0*tt[1]*180.0/M_PI);
		}
		else if (ii==2)
		{ // ..................................................... ferma il pendolo
			tt[0]=0;
			y[0]=0.0;
			y[1]=0.0;
		}
		else if (ii==3) break;
		else if (ii==nComm)
		{ // ........................................ riparti con i nuovi parametri
			tt[1]=atof(ParVal[0]);
			tt[2]=atof(ParVal[1]);
		}
		XSync(xvd.display,TRUE);
		musec2=clock();
		ts1.tv_nsec=10000000-(musec2-musec1)*1000;
		if (ts1.tv_nsec>0) nanosleep(&ts1,&ts2);
	}
	// .................................................... last Runge-Kutta step
	RungeStep(tt,y,2,step,2,func);
	// ............................................................... erase menu
	ii=XPermMenu(1,"pendolo",ParName,ParVal,nPar,16,comandi,nComm,20,
							 400,&mx,&my,2,0);
	// ..........................................................................
	delete [] y;
	delete [] tt;
	CloseXWindow();
}

// ----------------------------------------------------------------------------

void func(double *t,double *y,double *dydt)
{
	double a,gl,k;
	
	gl=t[1];
	k=t[2];
	// ................................................................ velocita'
	dydt[0]=y[1];
	// ............................................................ accelerazione
	dydt[1]=-gl*sin(M_PI*y[0]/180.0)-k*y[1];
}


