 /***************************************************************************
 * 
 *                  NE PAS MODIFIER CETTE SECTION 
 *                  
 **************************************************************************/
import java.awt.*;
import Listes.*;

public class Rebonds extends FenetreTortue
{ 
     
/***************************************************************************
 * 
 *                      SECTION MODIFIABLE 
 *                  
 **************************************************************************/
 
 
 
/********************** Parametres de l'interface ************************/

    public static int baseFenetre = 600; // Largeur de la fenetre
    public static int hauteurFenetre = 700; // Hauteur de la fenetre
    public static String titreFenetre = "Rebonds"; // Titre de la fenetre
    // Le texte
    public static boolean zoneTexte = false; // Indique si on désire ou non une zone de texte
    // Les boutons
    public static String[] nomsBoutonsLigne1 = {"Ajouter","Simuler", "Situation","Paramtres","Quitter"}; // Noms des boutons de la ligne 1
    public static String[] nomsBoutonsLigne2 = {}; // Noms des boutons de la ligne 2
    // Les menus
    public static String[] nomsMenus1 = {}; // Exemple: private static String[] nomsMenus1 = {"nomMenu", "nomItem_1", ...};
    public static String[] nomsMenus2 = {}; // Laissez vide si vous ne désirez pas de menu
    public static String[] nomsMenus3 = {};
    public static String[] nomsMenus4 = {};
    public static String[] nomsMenus5 = {};
    public static String[] nomsMenus6 = {};
    public static String[] nomsMenus7 = {};
    public static String[] nomsMenus8 = {};
    
    public static void ajoutDeGlissieres(){
    // Exemple: ajouterGlissiereLigne1(legende, min, max, posDebut, nbDecimales)
    } 

/****************** Initialisation *********************************/
   
    int nbBandes=0, nbMaxBandes=20, dimPoints=2+2*nbMaxBandes, noPoint=-1;
    double[] Px=new double[dimPoints], Py=new double[dimPoints];
    
    boolean modeSimulation=false;
    double longueur, echelle=1, vitesse=1; 
    int noRebond;
    
    int debutTrace=0, finTrace=0, nbTraces=0, nbMaxTraces=1000; boolean modeTrace=false;
    double[] traceX=new double[nbMaxTraces+1], traceY=new double[nbMaxTraces+1];
    
    void initialisation() {
        Px[1]=0; Py[1]=0; Px[0]=Px[1]; Py[0]=Py[1]; nbBandes=0;
        initTrace(); dessinerSituation();
    }
    
/****************** Placer vos procedures ici ****************************/

void dessinerSituation() { 
        centreTortue(); effaceGraphique(); 
        couleurCrayon(bleu); 
        if (! modeSimulation) {segment(Px[1],Py[1],Px[0],Py[0]);}
        cercle(Px[1],Py[1],3);
        couleurCrayon(rouge);
        for (int k=1; k<=nbBandes; k=k+1) {
            segment(Px[2*k],Py[2*k],Px[2*k+1],Py[2*k+1]);
        }
        if (modeTrace) {
            couleurCrayon(noir);
            for (int i=0; i<nbTraces; i++) {
                segment(traceX[(debutTrace+i) % (nbTraces+1)], traceY[(debutTrace+i) % (nbTraces+1)], 
                        traceX[(debutTrace+i+1) % (nbTraces+1)], traceY[(debutTrace+i+1) % (nbTraces+1)]);}
        }
        couleurCrayon(bleu); cercle(Px[1],Py[1],3);
}

void faireSimulation() {
        double Px0=Px[0], Py0=Py[0], Px1=Px[1], Py1=Py[1], Px2=Px[2], Py2=Py[2], Px3=Px[3], Py3=Py[3];  // temporaire
        modeSimulation=true;
        initTrace();
        Px[0]= echelle*(Px[0]-Px[1]); Py[0]= echelle*(Py[0]-Py[1]);
        longueur = norme(Px[0], Py[0]);
        while ((0 < longueur) && (abs(Px[1])<=largeurZoneGraphique()/2) && (abs(Py[1])<=hauteurZoneGraphique()/2)) 
            {simulerSegment(); if (interruption()) {break;}}
        Px[0]=Px[1]; Py[0]=Py[1];
        modeSimulation=false;
        // dessinerSituation();
}

void simulerSegment() {
        int noBande=0;
        double coeff, coeffMin=1;
        double epsilon = 0.0000000001; // CORRIGE BUG SUBTIL : aprs une collision, la redŽtecte sans se rendre compte qu'il est dŽjˆ sur le segment
        for (int k=1; k<=nbBandes; k=k+1) {
            coeff=calculIntersection(k);
            if (epsilon<coeff && coeff<coeffMin) {noBande=k; coeffMin=coeff;}
        }
        trajet(Px[1],Py[1],coeffMin*Px[0], coeffMin*Py[0]);
        Px[0]=(1-coeffMin)*Px[0]; Py[0]=(1-coeffMin)*Py[0]; longueur=(1-coeffMin)*longueur;
        if (0<longueur) {calculerReflexion(noBande);} 
}
    
 double calculIntersection(int n) {
        double x=Px[1]+Px[0], y=Py[1]+Py[0];
        double coeff1 = coeffIntersection(Px[1], Py[1], x, y, Px[2*n], Py[2*n], Px[2*n+1], Py[2*n+1]);
        if (!(0<coeff1 && coeff1<1)) {coeff1=INFINI;}
        double coeff2 = coeffIntersection(Px[2*n], Py[2*n], Px[2*n+1], Py[2*n+1], Px[1], Py[1], x, y);
        if (!(0<coeff2 && coeff2<1)) {coeff1=INFINI;}
        return coeff1;
 }
    
 double coeffIntersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) {
        double u1=x2-x1, v1=y2-y1, u3=x4-x3, v3=y4-y3;
        if (u1*v3==u3*v1) {return INFINI;}
        return (v3*(x3-x1)-u3*(y3-y1))/(u1*v3-u3*v1);
 }

void calculerReflexion(int noBande) {
    double wx=Px[2*noBande+1]-Px[2*noBande], wy=Py[2*noBande+1]-Py[2*noBande];
    double gamma= 2*(Px[0]*wx+Py[0]*wy)/(wx*wx+wy*wy); 
    Px[0] = gamma*wx-Px[0]; Py[0] = gamma*wy-Py[0];
}

double norme(double a, double b) {return racine(a*a+b*b);}

void trajet(double a, double b, double da, double db) {
    int nbEtapes = max(1,arrondis(norme(da, db) / vitesse));
    if (modeTrace) {debutTrace = (debutTrace +1) % (nbTraces+1); finTrace = (finTrace+1) % (nbTraces+1); 
                    traceX[finTrace]=Px[1]; traceY[finTrace]=Py[1]; }
    for (int k=0; k<=nbEtapes; k++) {
        Px[1] = a+da*k/nbEtapes; Py[1]=b+db*k/nbEtapes;
        traceX[finTrace]=Px[1]; traceY[finTrace]=Py[1];
        dessinerSituation(); miseAJourGraphique();
        if ((abs(Px[1])>largeurZoneGraphique()/2) || (abs(Py[1])>hauteurZoneGraphique()/2)) {return;}
    }
    // Px[1]=a+da; Py[1]=b+db;
}

void initTrace() {
    if (modeTrace) {
            debutTrace=0; finTrace=nbTraces; 
            for (int k=debutTrace; k<=finTrace; k++) {traceX[k]=Px[1]; traceY[k]=Py[1];}
        }
}


/**************  Les actions des boutons  ************************************/

public void actionBouton1(){    //Ajouter une bande
       nbBandes=nbBandes+1;
       Px[2*nbBandes]=largeurZoneGraphique()*(hasard()-0.5);
       Py[2*nbBandes+1]=hauteurZoneGraphique()*(hasard()-0.5);
       dessinerSituation();
} 

public void actionBouton2(){    //Simuler
    faireSimulation();
} 

public void actionBouton3(){    //Recommencer
    int boutonChoisi = choixMultiple("Situation", "Situation dŽsirŽe ?", "Statut quo", "Recommencer", "Polygone rŽgulier");
    if (boutonChoisi == 2) {initialisation();}
    if (boutonChoisi == 3) {
        int n = demanderEntier("n-gone rŽgulier", "Nombre de c™tŽs ?", 3);
        n = max(3,min(30,n));
        double rayon = min(largeurZoneGraphique()/2, hauteurZoneGraphique()/2)-10;
        nbBandes=n; Px[1]=0; Py[1]=0; Px[0]=Px[1]; Py[0]=Py[1];
        for (int k=1; k<=n; k++) {Px[2*k]=rayon*cos(k*2*Pi/n); Py[2*k]=rayon*sin(k*2*Pi/n); Px[2*k+1]=rayon*cos((k+1)*2*Pi/n); Py[2*k+1]=rayon*sin((k+1)*2*Pi/n);} 
    }
    initTrace(); dessinerSituation();
} 

public void actionBouton4(){    //Parametres
    echelle=demanderNombre("Echelle", "Donner un facteur d'Žchelle", echelle);
    vitesse=demanderNombre("Vitesse", "Vitesse en pixels", vitesse);
    nbTraces=demanderEntier("Trace", "Longueur de la trace", nbTraces); modeTrace = (nbTraces > 0);
    initTrace(); dessinerSituation();
} 

public void actionBouton5(){    //Quitter
     quitter();
}

// etc..
/**************  Les actions des menus  ****************************/
public void actionMenu1Item1(){    
} 

public void actionMenu1Item2(){
}

public void actionMenu1Item3(){ 
}

public void actionMenu1Item4(){
}

// etc..
/*************** Les actions des glissieres *********************************/  
public void actionGlissiere1(double d){
}

// etc..
/**************** Les actions de la souris *******************************/
    
    public void clicSouris(double x, double y){
        
    }
    
    public void debutGlisser(double x, double y){
        noPoint=trouverPoint(x,y);
    }
    
    public void finGlisser(double x, double y){
        noPoint=-1;
    }
    
    public void glisserEnCours(double x, double y){ 
        if (noPoint>=0) {Px[noPoint]=x; Py[noPoint]=y; dessinerSituation();}       
    }
    
    public int trouverPoint(double x, double y) {
        double seuil = 4*4;
        for (int k=0; k<dimPoints; k++) {
            if (distCarree(Px[k],Py[k],x,y)<seuil) {return k;}
        }
        return -1;
    }
    
    public double distCarree(double u,double v,double x,double y) {return (u-x)*(u-x)+(v-y)*(v-y);}
    
    
/********************* Changement de taille de la fenetre *******************/ 
    public void actionTailleChange(){
    // Placer ici les actions a realiser lors d'un changement de taille de la fenetre
        dessinerSituation();
    }
/***************************************************************************
 * 
 *                  NE PAS MODIFIER CETTE SECTION 
 *                  
 **************************************************************************/    
     
    public static String[][] Menus = {nomsMenus1, nomsMenus2, nomsMenus3, nomsMenus4, nomsMenus5, nomsMenus6, nomsMenus7, nomsMenus8};    
    
    public Rebonds(int l, int h, String titre, String[] nomsBoutons1, String[] nomsBoutons2, String[][] Menus, boolean avecTexte){
        super(l, h, titre, nomsBoutons1, nomsBoutons2, Menus, avecTexte);
    }
    
    public Rebonds() {
        this(baseFenetre, hauteurFenetre, titreFenetre, nomsBoutonsLigne1, nomsBoutonsLigne2, Menus, zoneTexte);
    }
    
    public static void executer(boolean applet){
        initGlissieres();
        ajoutDeGlissieres();
        Rebonds maFenetre = new Rebonds();
        faireApplet(applet);
        maFenetre.toFront();
        maFenetre.initialisation();
    }
    
    public static void main(String[] args){
        javax.swing.SwingUtilities.invokeLater(new Runnable(){
            public void run(){
                executer(false);
            }
        });
    }

     
}  
