/*
Pendule - algorithme de simulation pour SimuLab

Copyright (C) 2002 Observatoire de Paris-Meudon

Ce programme est un logiciel libre ; vous pouvez le redistribuer et/ou le modifier conformément aux dispositions de la Licence Publique Générale GNU, telle que publiée par la Free Software Foundation ; version 2 de la licence, ou encore (à votre choix) toute version ultérieure.

Ce programme est distribué dans l'espoir qu'il sera utile, mais SANS AUCUNE GARANTIE ; sans même la garantie implicite de COMMERCIALISATION ou D'ADAPTATION A UN OBJET PARTICULIER. Pour plus de détail, voir la Licence Publique Générale GNU .

Vous devez avoir reçu un exemplaire de la Licence Publique Générale GNU en même temps que ce programme ; si ce n'est pas le cas, écrivez à la Free Software Foundation Inc., 675 Mass Ave, Cambridge, MA 02139, Etats-Unis.
*/

import simu.*;

/**
 * Algorithme de simulation pour SimuLab.
 * Pendule de Foucault
 * compilation: javac -source 1.2 -target 1.1 -encoding ISO-8859-1 -classpath SimuLab.jar Pendule.java
 */
public class Pendule extends SimuApplet {

    static final double g = 9.81;
    static final double omterre = 2*Math.PI/(24*3600); // rotation de la terre en radian par seconde
    double pulsation;
    double omega;
    double x0,v0;
    double x,y;
    double t;
    double dt = 0.01; // intervalle de temps entre deux points, en s
    double duree;
    
    // constructeur de la classe, avec la définition des paramètres de simulation
    // et des options d'affichage.
    public Pendule() {
        appletDoc("pendule_doc.xml");
        //setTitreEnsembles("ensembles de valeurs");
    }
    
    // calcul live (utilisé avec affichage "plotlive")
    // initialisation
    public void initCalculLive(ListeValeurs in) throws SimuException {
        x = x0;
        y = 0;
        t = 0;
        double latitude = in.lireDouble("latitude");
        double L = in.lireDouble("longueur");
        double vitrot = in.lireDouble("vitrot");
        String ajuster = in.lireString("ajuster");
        getAffichage("afflive").ajuster = "on".equals(ajuster);
        x0 = in.lireDouble("x0");
        v0 = in.lireDouble("v0");
        duree = in.lireDouble("duree");
        dt = in.lireDouble("intervalle");
        pulsation = Math.sqrt(g/L);
        omega = omterre * Math.sin(latitude/180.0*Math.PI) * vitrot;
    }
    
    // Calcul du temps t au temps t+1.
    public ListeValeurs calculLive() throws SimuException {
        ListeValeurs out = new ListeValeurs();
        t += dt;
        xy();
        out.ajouterDouble("x", x);
        out.ajouterDouble("y", y);
        dormir(Math.round(dt*1000)); // pour bloquer le programme pendant dt secondes
        return out;
    }
    
    public ListeValeurs calcul(ListeValeurs in) throws SimuException {
        ListeValeurs out = new ListeValeurs();
        initCalculLive(in);
        while (t < duree) {
            t += dt;
            xy();
            out.ajouterDouble("x", x);
            out.ajouterDouble("y", y);
        }
        return out;
    }
    
    public void xy() {
        
        /*
        // calcul oversimplifié (vu sur le web) avec v0=0 en supposant omega << pulsation
        double temp = Math.cos(Math.sqrt(pulsation*pulsation + omega*omega)*t);
        x = x0 * Math.cos(omega*t) * temp;
        y = -x0 * Math.sin(omega*t) * temp;
        */
        /*
        // avec v0=0 en supposant omega << pulsation (mais moins de simplifications)
        x = x0 * (Math.cos(omega*t) * Math.cos(pulsation*t) +
            omega/pulsation*Math.sin(omega*t)*Math.sin(pulsation*t));
        y = - x0 * (Math.sin(omega*t) * Math.cos(pulsation*t) -
            omega/pulsation*Math.cos(omega*t)*Math.sin(pulsation*t));
        */
        
        // mon calcul à moi, calcul de x,y avec v0=0
        double delta = Math.sqrt(pulsation*pulsation + omega*omega);
        double temp1 = omega + delta;
        double temp2 = omega - delta;
        double x1 = x0*temp1/(2*delta)*Math.cos(temp2*t) - x0*temp2/(2*delta)*Math.cos(temp1*t);
        double y1 = -x0*temp1/(2*delta)*Math.sin(temp2*t) + x0*temp2/(2*delta)*Math.sin(temp1*t);
        
        // mon calcul avec x0=0
        //double delta = Math.sqrt(pulsation*pulsation + omega*omega);
        double x2 = v0/delta*Math.sin(delta*t)*Math.cos(omega*t);
        double y2 = -v0/delta*Math.sin(omega*t)*Math.sin(delta*t);
        
        // cas général
        x = x1 + x2;
        y = y1 + y2;
    }
}
