import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;
import java.text.*;
import java.io.*;

/**
 * Pannello per il calcolo del moto dei pianeti con l'algoritmo di
 * Verlet.  Visualizza l'orbita nel piano e permette di calcolare
 * l'area spazzata dal raggio vettore in intervalli temporali uguali.
 * Consente salvataggio su file della traiettoria e di energia in
 * funzione del tempo.  Permette di leggere come parametri per un
 * nuovo calcolo la posizione e la velocita' all'ultimo passo di un
 * calcolo precedente (la vecchia traiettoria rimane indicata con un
 * nuovo colore).  Animazione del pianeta.
 */
public class Keplero extends JPanel implements ActionListener,
					       ChangeListener,
					       Runnable
{

    /** Versione */
    static String VERSIONE="1.11";

    // Parametri predefiniti per il calcolo (unita' SI)
    /** Numero di iterazioni */
    static int    PREDEF_NITER  = 52;
    /** Intervallo temporale per la dinamica */
    static double PREDEF_DELTAT = 365.25*24*3600/PREDEF_NITER;
    /** Massa del Sole */
    static double PREDEF_MASSA  = 1.989e30;
    /** Posizione del pianeta (x) */
    static double PREDEF_POSX   = 1.521e11;
    /** Posizione del pianeta (y) */
    static double PREDEF_POSY   = 0;
    /** Velocita' del pianeta (x) */
    static double PREDEF_VELX   = 0;
    /** Velocita' del pianeta (y) */
    static double PREDEF_VELY   = 29290.;
    

    // Parametri di visualizzazione
    static int dimArea;          // Semiampiezza dell'area di disegno
    static int DIMAREA_EXEC=350; // Default per stand-alone exec
    static int DIMAREA_APPL=290; // Default per applet

    // I file in cui salvare la traiettoria
    static String FILE_TRAIETTORIA =new String("traiettoria.txt");
    static String FILE_INFORMAZIONI=new String("traiettinfo.txt");
    private boolean abilitaScrittura;


    // Notazione scientifica con diversi decimali
    static DecimalFormat notazScient6
	= new DecimalFormat( "0.000000E00;-0.000000E00",
			     new DecimalFormatSymbols(Locale.US) );
    // Numeri interi
    static DecimalFormat notazInteri
	= new DecimalFormat( "#;-#");


    // Gli oggetti che contengono la traiettoria. Vedi file "MotoPianeta.java"
    MotoPianeta motoPianeta;
    MotoPianeta vecchioMoto;


    // L'area in cui tracciare la traiettoria
    AreaDisegno areaDisegno;
    // Il pannello comandi/parametri
    JPanel pannelloLaterale;
    // Il pop-up per il calcolo delle aree
    PannelloAree pannelloAree;

    // Pulsanti di controllo
    JButton pulsPlayStop, pulsFwd, pulsRew,
	pulsCalcola, pulsAree, pulsDefault, pulsScrivi, pulsTacche, pulsPulisci;

    // Campi di input
    JFormattedTextField inp_niter, inp_massa, inp_dt,
	inp_pos0x, inp_pos0y, inp_vel0x, inp_vel0y;

    // Selettori per lo zoom e la velocita' di animazione
    JSlider selettZoom, selettVelocita;

    // Oggetti per l'animazione
    Thread animThread;
    boolean animazioneInCorso=false;
    int dt_anim=0;  // timestep per l'animazione (ms)
    int iterazOra;

    // Variabili di visualizzazione
    boolean disegnaTacche=true;


    /**
     * Costruttore del pannello per il calcolo del moto dei pianeti
     */
    public Keplero(boolean _abilitaScrittura, int _dimArea) {
	abilitaScrittura=_abilitaScrittura;
	dimArea=_dimArea;
	
	// Crea l'area del disegno
	areaDisegno=new AreaDisegno();
	areaDisegno.setLocked(false);
	
	// Crea il sotto-pannello controllo
 	pulsCalcola =new JButton("Calcola con questi parametri");     pulsCalcola.addActionListener(this);
 	pulsDefault=new JButton("Parametri originali");               pulsDefault.addActionListener(this);
	if (abilitaScrittura) {
	    pulsScrivi=new JButton("Scrivi traiettoria su file");     pulsScrivi.addActionListener(this);
	}
	pulsAree    =new JButton("Calcola le aree");                  pulsAree.addActionListener(this);
	pulsRew     =new JButton("<<");                               pulsRew.addActionListener(this);
	pulsPlayStop=new JButton("Play / Stop");                      pulsPlayStop.addActionListener(this);
	pulsFwd     =new JButton(">>");                               pulsFwd.addActionListener(this);
	pulsTacche  =new JButton("Mostra/nascondi discretizzazione"); pulsTacche.addActionListener(this);
	pulsPulisci =new JButton("Pulisci la vecchia traiettoria");   pulsPulisci.addActionListener(this);
	dt_anim=(int) (1000* (1.-Math.sqrt(0.5) ));
	selettVelocita=new JSlider(JSlider.HORIZONTAL,0,1000,dt_anim);
	selettVelocita.setPaintTicks(true);
	selettVelocita.setMajorTickSpacing(500);
	selettVelocita.setMinorTickSpacing(100);
	selettVelocita.addChangeListener(this);
	JPanel pannAnimaz=new JPanel();
	pannAnimaz.setLayout(new BorderLayout(2,0));
	pannAnimaz.add(pulsRew,BorderLayout.WEST);
	pannAnimaz.add(pulsPlayStop,BorderLayout.CENTER);
	pannAnimaz.add(pulsFwd,BorderLayout.EAST);
	JPanel pannVelocita=new JPanel();
	pannVelocita.setLayout(new BorderLayout(0,0));
	pannVelocita.add(new JLabel("<html>Velocit&agrave;</html>"),BorderLayout.WEST);
	pannVelocita.add(selettVelocita,BorderLayout.CENTER);

	// Crea il sotto-pannello zoom
	selettZoom=new JSlider(JSlider.HORIZONTAL,-100,100,0);
	selettZoom.setPaintTicks(true);
	selettZoom.setMajorTickSpacing(100);
	selettZoom.setMinorTickSpacing(20);
	selettZoom.addChangeListener(this);
	areaDisegno.zoom=Math.pow(10,0.01*selettZoom.getValue());

	JPanel pannZoom=new JPanel();
	pannZoom.setLayout(new BorderLayout());
	pannZoom.add(new JLabel("Zoom:"),BorderLayout.WEST);
	pannZoom.add(selettZoom,BorderLayout.CENTER);
	JPanel pannControllo=new JPanel();
	pannControllo.setLayout(new GridLayout( abilitaScrittura?9:8, 1 ,2 ,10 ));
	pannControllo.add(pulsCalcola);
 	pannControllo.add(pulsDefault);
	if (abilitaScrittura) pannControllo.add(pulsScrivi);
	pannControllo.add(pulsAree);
	pannControllo.add(pannAnimaz);
	pannControllo.add(pannVelocita);
	pannControllo.add(pulsTacche);
	pannControllo.add(pulsPulisci);
	pannControllo.add(pannZoom);

	// Crea il sottopannello parametri
	inp_niter=new JFormattedTextField(notazInteri);  inp_niter.setValue(PREDEF_NITER);
	inp_dt   =new JFormattedTextField(notazScient6); inp_dt.setValue(PREDEF_DELTAT);
	inp_massa=new JFormattedTextField(notazScient6); inp_massa.setValue(PREDEF_MASSA);
	inp_pos0x=new JFormattedTextField(notazScient6); inp_pos0x.setValue(PREDEF_POSX);
	inp_pos0y=new JFormattedTextField(notazScient6); inp_pos0y.setValue(PREDEF_POSY);
	inp_vel0x=new JFormattedTextField(notazScient6); inp_vel0x.setValue(PREDEF_VELX);
	inp_vel0y=new JFormattedTextField(notazScient6); inp_vel0y.setValue(PREDEF_VELY);
	JPanel pannParametri=new JPanel();
	pannParametri.setLayout(new GridLayout(7,2));
	pannParametri.add(new JLabel("Numero iterazioni")  ); pannParametri.add(inp_niter);
	pannParametri.add(new JLabel("Delta t (s)")        ); pannParametri.add(inp_dt);
	pannParametri.add(new JLabel("Massa del Sole (Kg)")); pannParametri.add(inp_massa);
	pannParametri.add(new JLabel("Posizione x (m)")    ); pannParametri.add(inp_pos0x);
	pannParametri.add(new JLabel("Posizione y (m)")    ); pannParametri.add(inp_pos0y);
	pannParametri.add(new JLabel("<html>Velocit&agrave; x (m/s)</html>")  ); pannParametri.add(inp_vel0x);
	pannParametri.add(new JLabel("<html>Velocit&agrave; y (m/s)</html>")  ); pannParametri.add(inp_vel0y);
	// Inizializza il moto pianeta con i parametri predefiniti
	nuovoCalcolo();


	// Componi il pannello laterale
	pannelloLaterale=new JPanel();
	pannelloLaterale.setLayout(new BorderLayout(0,20));
	pannelloLaterale.add(pannControllo,BorderLayout.CENTER);
	pannelloLaterale.add(pannParametri,BorderLayout.NORTH);
	//pannelloLaterale.add(pannZoom,BorderLayout.SOUTH);
	JPanel pannLat1=new JPanel();
	pannLat1.add(pannelloLaterale);

	// Componi il pannello complessivo
	this.setLayout(new BorderLayout(2,2));
	this.add(areaDisegno,BorderLayout.CENTER);
	this.add(pannLat1,BorderLayout.EAST);
    }


    /**
     * Leggi i parametri di input e effettua il calcolo dell'orbita
     */
    public void nuovoCalcolo() {
	vecchioMoto=motoPianeta;
	try {
	    motoPianeta=new MotoPianeta
		(notazInteri.parse( inp_niter.getText()).intValue(),
		 notazScient6.parse(inp_massa.getText()).doubleValue(),
		 notazScient6.parse(   inp_dt.getText()).doubleValue(),
		 notazScient6.parse(inp_pos0x.getText()).doubleValue(),
		 notazScient6.parse(inp_pos0y.getText()).doubleValue(),
		 notazScient6.parse(inp_vel0x.getText()).doubleValue(),
		 notazScient6.parse(inp_vel0y.getText()).doubleValue() );
	    if (pannelloAree!=null) pannelloAree.reset();
	    animazioneInCorso=false;
	    iterazOra=0;
	}
	catch(ParseException nfe) {
	    motoPianeta=vecchioMoto;
	    JOptionPane.showMessageDialog
		(this, "Controlla i valori inseriti!",
		 "Keplero - Errore", JOptionPane.ERROR_MESSAGE);
	}
    }


    /**
     * Funzione eseguita ogni volta che si clicca su un pulsante
     */
    public void actionPerformed(ActionEvent e) {
	if (e.getSource()== pulsCalcola) {
	    areaDisegno.setLocked(true);
	    nuovoCalcolo();
	    areaDisegno.setLocked(false);

	}
	else if (e.getSource()== pulsPlayStop) {
	    stopIfRunning(animazioneInCorso);
	}
	else if (e.getSource()== pulsFwd) {
	    stopIfRunning(true);
	    iterazOra=(iterazOra<motoPianeta.niter-1)?iterazOra+1:0;

	}
	else if (e.getSource()== pulsRew) {
	    stopIfRunning(true);
	    iterazOra=(iterazOra>0)?iterazOra-1:motoPianeta.niter-1;

	}
	else if (e.getSource()== pulsTacche) {
	    disegnaTacche=!disegnaTacche;

	}
	else if (e.getSource()== pulsPulisci) {
	    vecchioMoto=null;

	}
	else if (e.getSource()== pulsDefault) {
            inp_niter.setValue(PREDEF_NITER);
            inp_dt.setValue(PREDEF_DELTAT);
            inp_massa.setValue(PREDEF_MASSA);
            inp_pos0x.setValue(PREDEF_POSX);
            inp_pos0y.setValue(PREDEF_POSY);
            inp_vel0x.setValue(PREDEF_VELX);
            inp_vel0y.setValue(PREDEF_VELY);
	}
	else if (e.getSource()== pulsScrivi && abilitaScrittura) {
		try {
		    motoPianeta.scriviTraiettoria
			  (notazScient6, FILE_TRAIETTORIA, FILE_INFORMAZIONI);
		    JOptionPane.showMessageDialog
			(this,"Scritti file: "+FILE_TRAIETTORIA+" e "+FILE_INFORMAZIONI+".",
			 "Keplero - Informazione", JOptionPane.INFORMATION_MESSAGE);
		}
		catch (java.io.IOException ex) {
		    JOptionPane.showMessageDialog
			(this,"Errore nella scrittura dei file con la traiettoria.",
			 "Keplero - Errore", JOptionPane.ERROR_MESSAGE);
		}
		catch (java.security.AccessControlException ex) {
		    JOptionPane.showMessageDialog
			(this,"Errore nella scrittura dei file con la traiettoria:\npermesso negato.",
			 "Keplero - Errore", JOptionPane.ERROR_MESSAGE);
		}
	}
	else if (e.getSource()== pulsAree) {
	    class FinestrellaAree extends JFrame {
		String title;
		FinestrellaAree (String title) {
		    super(title);
		    pannelloAree=new PannelloAree();
		    this.getContentPane().add(pannelloAree);
		    this.pack();
		    this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		    this.setDefaultLookAndFeelDecorated(false);
		    this.setResizable(false);
		    this.setVisible(true);
		}
		public void dispose () {
		    pannelloAree=null;
		    super.dispose();
		}
	    }
	    if (pannelloAree==null) {
		FinestrellaAree finestraAree=new FinestrellaAree ("Calcola aree");

	    }
	}
    }


    /**
     * Funzione eseguita ogni volta che si trascina una barra di selezione
     */
    public void stateChanged(ChangeEvent e) {
	if (e.getSource()== selettZoom) {
	    areaDisegno.zoom=Math.pow(10,0.01*selettZoom.getValue());
	    //areaDisegno.paintComponent(areaDisegno.getGraphics());
	}
	else if (e.getSource()== selettVelocita) {
	    // La relazione qui sotto e' solo per dare piu' spazio ai valori piccoli
	    dt_anim=(int) (1000* (1.-Math.sqrt(0.001*selettVelocita.getValue())) );
	}
    }


    /**
     * L'animazione: ogni DT_ANIM millisecondi muovi il pianeta
     */
    public void run() {
	Thread me = Thread.currentThread();
        while(animThread==me) {
	    try { Thread.sleep(dt_anim); } catch (InterruptedException e) {};
	    if (iterazOra<motoPianeta.niter-1) {
		iterazOra=iterazOra+1;
	    } else {
		iterazOra=motoPianeta.niter-1;
		stopIfRunning(true);
	    }
	}
    }


    /**
     * Arresta l'animazione se e' in corso, o falla partire se e' ferma
     */
    public void stopIfRunning(boolean running) {
	if (running) {
	    if (animazioneInCorso) animThread=null;
	} else {
	    if (iterazOra>=motoPianeta.niter-1) iterazOra=0;
	    animThread=new Thread(this);
	    animThread.start();
	}
	animazioneInCorso=!running;
    }
    

    /**
     * Crea un pannello "keplero" e apri una finestra per visualizzarlo
     */
    public static void main(String[] args) {
        JFrame f=new JFrame("Keplero: laboratorio numerico - versione "+VERSIONE);
        Keplero kep=new Keplero(true, DIMAREA_EXEC);
        f.getContentPane().add(kep);
        f.pack();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setDefaultLookAndFeelDecorated(false);
	    f.setResizable(false);
        f.setVisible(true);
    }


    /////////////////////////////////////////////////////////////////////
    //
    //                          CLASSI INTERNE
    //
    /////////////////////////////////////////////////////////////////////


    /********************************************************************
     * L'area in cui tracciare il moto del pianeta.
     */
    class AreaDisegno extends JPanel implements Runnable {
	int dt_ridisegna=50; // 20 volte al secondo
        Color col_SFONDO=Color.BLACK;
        Color col_SOLE=Color.ORANGE;
        Color col_PIANETA=Color.GREEN;
        Color col_TRAIETTORIA=new Color(190,190,255);
        Color col_VECCHIA_TRAIETTORIA=Color.BLUE;
        Color col_AREA1=Color.GREEN;
        Color col_AREA2=Color.YELLOW;
        Color col_TESTO=Color.WHITE;
	double zoom;
	Image offScreen;
	Graphics goff;
	Thread disegnaThread;
	boolean locked=true;  // di default l'aggiornamento del disegno e' bloccato
	//
	public AreaDisegno () {
	    this.setPreferredSize(new Dimension(2*dimArea+1,2*dimArea+1));
	    this.setBackground(col_SFONDO);
	}
	//
	public void paintComponent(Graphics g) {
	    if (offScreen==null) offScreen=createImage(2*dimArea+1,2*dimArea+1);
	    goff=offScreen.getGraphics();
	    paintOnGraphics(goff);
	    g.drawImage(offScreen,0,0,this);
	    // Dopo che l'hai disegnato la prima volta, avvia un thread che
	    // continuera' a ridisegnarlo.
	    if (disegnaThread==null) {
		disegnaThread=new Thread(this);
		disegnaThread.start();
	    }
	}
	//
	public void paintOnGraphics(Graphics g) {
	    //
	    // Usa l'iterazione a cui e' arrivato in questo momento
	    int iterazOra_ = iterazOra;
	    //
	    // Sfondo
	    super.paintComponent(g);
	    //
	    // Le aree, se richiesto
	    if (pannelloAree!=null) {
		int x[]=new int[motoPianeta.niter];
		int y[]=new int[motoPianeta.niter];
		for (int iii=0;iii<motoPianeta.niter;iii++) {
		    x[iii]=x2schermo(motoPianeta.pos_x[iii]);
		    y[iii]=y2schermo(motoPianeta.pos_y[iii]);
		}
		int x1[]=new int[motoPianeta.niter+1];
		int y1[]=new int[motoPianeta.niter+1];
		int x2[]=new int[motoPianeta.niter+1];
		int y2[]=new int[motoPianeta.niter+1];
		x1[0]=x2schermo(0);
		y1[0]=y2schermo(0);
		x2[0]=x2schermo(0);
		y2[0]=y2schermo(0);
		for (int iii=0;iii<pannelloAree.tempo+1;iii++) {
		    x1[iii+1]=x[iii+pannelloAree.punto1];
		    y1[iii+1]=y[iii+pannelloAree.punto1];
		    x2[iii+1]=x[iii+pannelloAree.punto2];
		    y2[iii+1]=y[iii+pannelloAree.punto2];
		}
		g.setColor(col_AREA1);
		g.fillPolygon(x1,y1,pannelloAree.tempo+2);
		g.setColor(col_AREA2);
		g.fillPolygon(x2,y2,pannelloAree.tempo+2);
		g.drawLine(x2[0],y2[0],
			   x2[pannelloAree.tempo+1],y2[pannelloAree.tempo+1]);
		g.drawLine(x2[0],y2[0],x2[1],y2[1]);
		g.setColor(col_AREA1);
		g.drawLine(x1[0],y1[0],
			   x1[pannelloAree.tempo+1],y1[pannelloAree.tempo+1]);
		g.drawLine(x1[0],y1[0],x1[1],y1[1]);
	    }
	    //
	    // Il sole
	    g.setColor(col_SOLE);
	    g.fillOval(x2schermo(0)-7,y2schermo(0)-7,15,15);
	    //
	    // La vecchia traiettoria, se esiste
	    if (vecchioMoto!=null) {
		g.setColor(col_VECCHIA_TRAIETTORIA);
		for (int iii=0;iii<vecchioMoto.niter-1;iii++)
		    g.drawLine( x2schermo(vecchioMoto.pos_x[iii  ]),
				y2schermo(vecchioMoto.pos_y[iii  ]),
				x2schermo(vecchioMoto.pos_x[iii+1]),
				y2schermo(vecchioMoto.pos_y[iii+1])  );
	    }
	    //
	    // La nuova traiettoria
	    g.setColor(col_TRAIETTORIA);
	    for (int iii=0;iii<motoPianeta.niter-1;iii++)
		g.drawLine( x2schermo(motoPianeta.pos_x[iii  ]),
			    y2schermo(motoPianeta.pos_y[iii  ]),
			    x2schermo(motoPianeta.pos_x[iii+1]),
			    y2schermo(motoPianeta.pos_y[iii+1])  );
	    if (disegnaTacche) for (int iii=0;iii<motoPianeta.niter  ;iii++)
		g.fillOval( x2schermo(motoPianeta.pos_x[iii])-1,
			    y2schermo(motoPianeta.pos_y[iii])-1, 3,3);
	    //
	    // La posizione corrente del pianeta
	    g.setColor(col_PIANETA);
	    g.fillOval( x2schermo(motoPianeta.pos_x[iterazOra_])-3,
			y2schermo(motoPianeta.pos_y[iterazOra_])-3, 7,7);
	    g.setColor(col_SFONDO);
	    g.fillOval( x2schermo(motoPianeta.pos_x[iterazOra_])-1,
			y2schermo(motoPianeta.pos_y[iterazOra_])-1, 3,3);
	    //
	    // Valori correnti dell'energia
	    g.setColor(col_TESTO);
	    g.drawString("Tempo trascorso: "+
			 notazScient6.format(motoPianeta.dt*iterazOra_)+"  s", 12,20);
	    g.drawString("Energia cinetica/massa:       "+
			 notazScient6.format(motoPianeta.enCin[iterazOra_])+"  J/Kg", 12,40);
	    g.drawString("Energia potenziale/massa: "+
			 notazScient6.format(motoPianeta.enPot[iterazOra_])+"  J/Kg", 12,60);
	    g.drawString("Energia totale/massa:        "+
			 notazScient6.format(motoPianeta.enCin[iterazOra_]+
					     motoPianeta.enPot[iterazOra_])+"  J/Kg", 12,80);
	    //
	}
	//
	/**
	 * L'animazione: ogni DT millisecondi ridisegna il pannello
	 */
	public void run() {
	    Thread me = Thread.currentThread();
	    while(disegnaThread==me) {
		try { Thread.sleep(dt_ridisegna); } catch (InterruptedException e) {};
		if (!isLocked()) this.paintComponent(this.getGraphics());
	    }
	}
	//
	/** L'animazione ridisegna pannello solo se non e' bloccato */
	public boolean isLocked() {return locked;}
	public void setLocked(boolean _locked) {locked=_locked;}
	//
	// Trasforma le posizioni lungo x e y in pixel sul grafico
	// Nota: L'asse y e' per convenzione diretto verso il basso
	int x2schermo(double x) { return (int) (+x/getScala()*zoom+dimArea+1); }
	int y2schermo(double y) { return (int) (-y/getScala()*zoom+dimArea+1); }
	double getScala() {
	    return Math.sqrt( motoPianeta.pos_x[0]*motoPianeta.pos_x[0] +
			      motoPianeta.pos_y[0]*motoPianeta.pos_y[0] )
		/ (dimArea *0.7);
	}
    }


    /********************************************************************
     * L'area per il pop-up con i parametri per il calcolo delle aree.
     */
    class PannelloAree extends JPanel implements ChangeListener {
	JSlider selettPunto1, selettPunto2, selettTempo;
	JLabel txtPunto1, txtPunto2, txtTempo, txtArea1, txtArea2;
	int punto1, punto2, tempo;
	double area1, area2;

	public PannelloAree () {
	    selettPunto1=new JSlider(JSlider.HORIZONTAL,
				     0,motoPianeta.niter-1,0);
	    selettPunto2=new JSlider(JSlider.HORIZONTAL,
				     0,motoPianeta.niter-1,0);
	    selettTempo =new JSlider(JSlider.HORIZONTAL,
				     0,motoPianeta.niter-1,0);
	    selettPunto1.addChangeListener(this);
	    selettPunto2.addChangeListener(this);
	    selettTempo.addChangeListener(this);
	    txtPunto1=new JLabel();
	    txtPunto2=new JLabel();
	    txtTempo=new JLabel();
	    txtArea1=new JLabel();
	    txtArea2=new JLabel();
	    aggiornaValori();
	    //
	    this.setLayout(new GridLayout(12,1));
	    //
	    this.add(selettPunto1);
	    this.add(txtPunto1);
	    this.add(new JLabel(""));
	    //
	    this.add(selettPunto2);
	    this.add(txtPunto2);
	    this.add(new JLabel(""));
	    //
	    this.add(selettTempo);
	    this.add(txtTempo);
	    this.add(new JLabel(""));
	    //
	    this.add(txtArea1);
	    this.add(new JLabel(""));
	    this.add(txtArea2);
	}

	public void reset () {
	    punto1=0; selettPunto1.setValue(punto1);
	    punto2=0; selettPunto2.setValue(punto2);
	    tempo =0; selettTempo.setValue(tempo);
	    aggiornaValori();
	}

	void aggiornaValori () {
	    area1=calcolaArea(punto1,punto1+tempo);
	    area2=calcolaArea(punto2,punto2+tempo);
	    txtPunto1.setText("Tempo di inizio area verde: "+
			      notazScient6.format(punto1*motoPianeta.dt));
	    txtPunto2.setText("Tempo di inizio area gialla: "+
			      notazScient6.format(punto2*motoPianeta.dt));
	    txtTempo.setText("Tempo di misura: "+
			     notazScient6.format(tempo*motoPianeta.dt)+"  s");
	    txtArea1.setText("<html>Area verde: "+notazScient6.format(area1)+"  m<sup>2</sup></html>q");
	    txtArea2.setText("<html>Area gialla: "+notazScient6.format(area2)+"  m<sup>2</sup></html>");
	}

	double calcolaArea(int inizio, int fine) {
	    double area=0;
	    for (int i=inizio;i<fine;i++) area=area+motoPianeta.dArea[i];
	    return area;
	}

	public void stateChanged(ChangeEvent e) {
	    punto1=selettPunto1.getValue();
	    punto2=selettPunto2.getValue();
	    int maxPunto=(punto1>punto2)?punto1:punto2;
	    selettTempo.setMaximum(motoPianeta.niter-1 - maxPunto);
	    tempo=selettTempo.getValue();
	    aggiornaValori();
	}
    }


}////////////////////////////   FINE FILE   ///////////////////////////////
