/******************************************************
 *  Fichier   : chaos_billard.c
 *  Utilité   : Introduire la théorie du chaos par le biais 
 *               des trajectoires d'une boule de billard.
 *  Auteur    : Radonde pierre -- pierre.radonde@eisti.fr
 *              Fontaine loïc  -- loic.fontaine@eisti.fr
 *  Version   : finale
 *  Cration   : 11/02/2004
 *  Remarques : 
 *      ¤  Programme réalisé en GTK 1.2
 *      ¤  Commande de compilation (avec gcc):
 *  gcc -Wall -g chaos_billard.c -o Billard `gtk-config --cflags` `gtk-config --libs`
 ******************************************************/

/*******************************
 *  INCLUSION DES LIBRAIRIES.
 *******************************/
#include <gtk/gtk.h>
#include <stdio.h> 
#include <math.h>
#include <tgmath.h>

/*********************************
 *  Déclaration des commentaires.
 *********************************/
// Surface par défaut
gchar* surface="rectangle";
//======================================================================
// Commentaire : Initialisation commentaire
gchar* text="Séléctionnez une surface de jeu puis entrez vos valeurs.";
//======================================================================
// Commentaire : Trajectoire passe pas dans la surface de jeu
gchar* txt_hors_zone="La trajectoire ne passe pas par la surface de jeu."; 
//======================================================================
// Commentaire : Conclusion non-chaotique -- rectangle
gchar* txt_rect="Les trajectoires ne sont pas chaotiques, elles sont bien alignées.";
  //====================================================================
// Commentaire : Conclusion non-chaotique -- cercle
gchar* txt_cercle="Il y a une caustique au centre du cercle,
on peut observer la formation d'une rosasse;
les trajectoires ne sont pas chaotiques.";
//======================================================================
// Commentaire : Conclusion chaotique
gchar* txt_tronk="Il n'y a pas de caustique, les trajectoires sont chaotiques,
imprévisibles sur le long terme.";
//======================================================================
// Commentaire : Pas assez de trajectoires
gchar* txt_occurence="Augmentez les d'occurences pour mieux voir le phénomène."; 
//======================================================================

 
/******************************************************
 *  Fonction  : close_fenetre
 *  Utilité   : Quitte le programme
  *  Remarques : Fonction appelée lors de la fermeture 
 *               de la fenetre (par la croix) ou de l'appui
 *               sur le bouton fermer.
 ******************************************************/
gint 
close_fenetre (GtkWidget* widget, GdkEvent* event, gpointer user_data) 
{
  gtk_main_quit();
  return (FALSE);
}

/******************************************************
 *  Fonction  : dessiner
 *  Utilité   : Dessine la surface de jeu dans la zone de dessin
 *  Remarques : Fonction appelée par les fonctions intermediaires
 *               de choix de la surface ou par la fonction 'effacer'.
 ******************************************************/
void 
dessiner (GtkWidget* widget, gpointer user_data)
{
  GdkGC* gc;        //Contexte graphique
  GdkWindow* graph; //Zone d'affichage
  GtkWidget* zone;  //Zone de dessin

  /* Récupération de la zone graphique */
  zone = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (user_data), "zone"));
  /* Déclaration de la zone de dessin */
  graph = zone->window;
  /* Création du contexte graphique */
  gc = gdk_gc_new (graph);
  
  if (surface=="rectangle") // Option par defaut
    {/* Tracage du rectangle */
      gdk_draw_line (graph, gc, 50, 80, 350, 80);
      gdk_draw_line (graph, gc, 50, 80, 50, 320);
      gdk_draw_line (graph, gc, 350, 80, 350, 320);
      gdk_draw_line (graph, gc, 50, 320, 350, 320); 
    }
  else
    if (surface=="cercle")
      /* Tracage du cercle */
      gdk_draw_arc (graph,gc,FALSE,80,50,300,300,0,23040);
    else
      { /* <=> if (surface=="cercle tronque") */
	/* Tracage du cercle tronqué */
	gdk_draw_arc (graph,gc,FALSE,80,50,300,300,3840,15360);
	gdk_draw_line (graph, gc, 305, 70, 305, 330);
      }
}

/******************************************************
 *  Fonction  : effacer
 *  Utilité   : Efface la zone de dessin
 *  Remarques : Fonction appelée lors de l'appui sur le
 *               bouton 'effacer'.
 *              On detruit la zone de dessin, 
 *               puis on en recrée une autre.
 ******************************************************/
void 
effacer (GtkWidget* widget, gpointer user_data) 
{
  GtkWidget* zone;  //  Zone de dessin 
  GtkWidget* boite; //  Boite contenant la zone de dessin
  GtkWidget* com;   //  Zone de commentaire	

  /*  Récupération des parametres */
  zone = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (user_data), "zone"));
  boite = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (user_data), "boitev"));
  gtk_widget_destroy (zone);
  /* Récupération et réinitialisation de la zone de commentaire */
  com = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (user_data), "com"));
  gtk_label_set_text (GTK_LABEL(com),text);

  /*  Création d'une nouvelle zone de dessin, avec les mêmes paramètres */
  zone = gtk_drawing_area_new ();
  gtk_drawing_area_size (GTK_DRAWING_AREA (zone), 400, 400);
  gtk_object_set_data (GTK_OBJECT (user_data), "zone", zone);
  gtk_container_add (GTK_CONTAINER (boite), zone);
  gtk_widget_show (zone);

  while (gtk_events_pending ())
    gtk_main_iteration();

  /* Redessine la surface de jeu selectionné dans la nouvelle zone de dessin */
  dessiner(widget, user_data);
}

/******************************************************
 *  Fonctions : choix_surface
 *  Utilité   : Définissent les surfaces de jeu
 *  Remarques : Fonction intermediaire appelée lors de la
 *               séléction du bouton radio correspondant
 *              On affecte une valeur à une variable   
 *               globale, efface la zone de dessin, puis
 *               dessine la nouvelle surface de jeu.
 ******************************************************/
void choix_surface_rectangle (GtkWidget* widget, gpointer user_data)
{ 
  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
    surface="rectangle";
    effacer(widget, user_data);
    /*while (gtk_events_pending ())
      gtk_main_iteration();
      dessiner(widget, user_data);*/
  }
}
void choix_surface_cercle (GtkWidget* widget, gpointer user_data)
{ 
  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
    surface="cercle";
    effacer(widget, user_data);
    /*while (gtk_events_pending ())
      gtk_main_iteration();
      dessiner(widget, user_data);*/
  }
}
void choix_surface_cercle_t (GtkWidget* widget, gpointer user_data)
{ 
  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
    surface="cercle tronque";
    effacer(widget, user_data);
    /*while (gtk_events_pending ())
    gtk_main_iteration();
    dessiner(widget, user_data);*/
  }
}

/******************************************************
 *  Fonction  : test_egalite
 *  Utilité   : Décide si deux points sont égaux
 *  Remarques : Utilile pour les surfaces circulaires :
 *               un point est égal a un autre si il y a 
 *               4 ou moins de 4 pixels entre eux.
 ******************************************************/
int test_egalite(double xa,double ya,double xb,double yb)
{
  float dist;
  // calcul de la distance entre les points
  dist = sqrt(((xa-xb)*(xa-xb))+((ya-yb)*(ya-yb)));
  if (dist<=4)
    return 1;
  else
    return 0;
}

/******************************************************
 *  Fonctions : fermer_dialogue(1)
 *  Utilité   : Ferme la fenetre de dialogue qui
 *               affiche la conclusion du tracé.
 *  Remarques : Prend en compte le bouton fermer 
 *               ET la croix en haut de la fenetre.
 ******************************************************/
gint fermer_dialogue (GtkWidget* widget, gpointer user_data) 
{
  gtk_widget_destroy (user_data);
  return (FALSE);
}
gint fermer_dialogue1 (GtkWidget* widget, GdkEvent* event, gpointer user_data) 
{
  gtk_widget_destroy (user_data);
  return (FALSE);
}


/******************************************************
 *  Fonction  : tracer_rectangle
 *  Utilité   : ¤ Trace les trajectoires dans le rectangle.
                ¤ Affiche la conclusion du tracé.
 *  Remarques : Fonction appelée par la fonction : tracer
 ******************************************************/
void tracer_rectangle (GtkWidget* widget, gpointer user_data) 
{
  /* Déclaration des variables : */
  GtkWidget* zone;             // Zone de dessin
  GdkGC* gc;                   // Contexte Graphique 
  GdkWindow* graph;            // Zone d'affichage
  GtkWidget* com;              // Zone de commentaire
  GtkWidget* popup;            // Fenetre de conclusion
  GtkWidget* boutonfermer;     // Bouton pour la fermer

  int occurences; // Nombre d'occurence voulues
  double xd, yd;  // Coordonnées du point de départ de la trajectoire
  double xa, ya;  // Coordonnées du point d'arrivée de la trajectoire
  int cpt;        // Compteur des occurences
  float a, b;     // Coef. directeur initial de la fonction : y=a*x+b
  int test=1;     // Test pour voir si il faut tracer la trajectoire ou pas
  //GtkWidget* message;

  /* INITIALISATIONS : */
  cpt=1; 
 
  /* Récupération des paramètres pour permettre le dessin */
  zone = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (user_data), "zone"));
  graph = zone->window;
  gc = gdk_gc_new (graph);

  /* Récupération de la zone de commentaire */
  com = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (user_data), "com"));

  /* Récupération des coef de la fonction : a et b ainsi que du nb d'occ */
  a = g_strtod (gtk_entry_get_text(GTK_ENTRY (gtk_object_get_data (GTK_OBJECT (user_data), 
								   "saisie_a"))), NULL);
  b =  g_strtod (gtk_entry_get_text(GTK_ENTRY (gtk_object_get_data (GTK_OBJECT (user_data), 
								    "saisie_b"))), NULL);
  occurences=g_strtod (gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data (GTK_OBJECT(user_data), 
									 "saisie_occ"))), NULL); 
  /***====================================================================***/

  
  /*  Clacul du point de départ 
      c'est (xa,ya) mais il deviendra (xd,yd) en entrant dans la boucle */
  ya=80;
  xa=(ya-b)/a;
  if ((xa<=50) || (xa>=350))
    {   
      ya=320;
      xa=(ya-b)/a;
      if ((xa<=50) || (xa>=350))
	{
	  xa=50;
	  ya=a*xa+b;
	  if ((ya<=80) || (ya>=320))
	    {
	      xa=350;
	      ya=a*xa+b;
	    }
	}
    } 
  if (!(((xa==50) || (xa==350)) && ((ya==80) || (ya==320))) && 
      //si le point n'est pas à un angle du rectangle et
      !( ((xa<50) || (xa>350)) || ((ya<80) || (ya>320)) )
      //si le point n'est pas dans le rectangle
      )
    {
      //§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
      //Commentaire -- Conclusion
      //§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
      popup =  gtk_dialog_new ();
      gtk_window_set_title (GTK_WINDOW (popup), "Conclusion");
      
      if (occurences>=6)
	// Conclusion : Caustique et pas chaos
	gtk_container_add (GTK_CONTAINER (GTK_DIALOG(popup)->vbox), 
			   gtk_label_new (txt_rect));
      else
	// Conclusion : Mettez plus de rebond
	gtk_container_add (GTK_CONTAINER (GTK_DIALOG(popup)->vbox), 
			   gtk_label_new (txt_occurence)); 
      
      boutonfermer = gtk_button_new_with_label("ok");
      gtk_container_add (GTK_CONTAINER (GTK_DIALOG(popup)->action_area), boutonfermer);
      gtk_signal_connect (GTK_OBJECT (boutonfermer), "clicked",
			  GTK_SIGNAL_FUNC (fermer_dialogue), popup);
      gtk_signal_connect (GTK_OBJECT (popup), "delete-event",
			  GTK_SIGNAL_FUNC (fermer_dialogue1), popup);
      /* Option de la fenetre de dialogue et affichage */
      gtk_window_set_modal (GTK_WINDOW (popup), TRUE);
      gtk_widget_show_all (popup);
      //§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
      
      while (cpt<=occurences)
	{
	  /* Calcul des valeurs du point de départ (xd,yd) : */
	  xd=xa; yd=ya;
	  
	  /* Calcul des valeurs du point d'arrivée (xa,ya) : */
	  xa=350;
	  ya=a*xa+b;
	  if ((ya<=80) || (ya>=320) || (test_egalite(xa,ya,xd,yd)==1))
	    { 
	      xa=50;
	      ya=a*xa+b;
	      if ((ya<=80) || (ya>=320) || (test_egalite(xa,ya,xd,yd)==1))
		{
		  ya=320;
		  xa=(ya-b)/a;
		  if ((xa<=50) || (xa>=350) || (test_egalite(xa,ya,xd,yd)==1))
		    {
		      ya=80;
		      xa=(ya-b)/a;
		      if  ((xa<=50) || (xa>=350) || (test_egalite(xa,ya,xd,yd)==1))
			{gtk_label_set_text(GTK_LABEL(com),txt_hors_zone);
			cpt=occurences+1; // fin du tracer
			test=0;}
		    }
		}
	    }
	  
	  /*   Affichage dans le shell des valeurs de xd,yd et xa,ya 
	       pour vérification ou débogage. */
	  /*printf("%d \n",cpt);
	    printf("(xd,yd)=( %f,", xd);
	    printf(" %f )\n", yd);
	    printf("(xa,ya)=( %f,", xa);
	    printf(" %f )\n\n", ya);*/
	  
	  /* Tracage de la trajectoire de (xd,yd) à (xa,ya) : */
	  if (test==1)
	    gdk_draw_line (graph, gc, xd, yd, xa, ya);
	  
	  /* Modification de la valeur de a et de b : */
	  a=-a;
	  b=ya-a*xa;
	  
	  /* Incrementation compteur : */
	  cpt=cpt+1;
	}
    }
  else
    gtk_label_set_text(GTK_LABEL(com),txt_hors_zone);
}

/******************************************************
 *  Fonction  : tracer_cercle
 *  Utilité   : ¤ Trace les trajectoires dans le cercle.
 *              ¤ Affiche la conclusion du tracé.
 *  Remarques : Fonction appelée par la fonction : tracer
 ******************************************************/
void tracer_cercle (GtkWidget* widget, gpointer user_data) 
{
  /* Déclaration des variables : */
  GtkWidget* zone;             // Zone de dessin
  GdkGC* gc;                   // Contexte Graphique 
  GdkWindow* graph;            // Zone d'affichage
  GtkWidget* com;              // Zone de commentaire
  GtkWidget* popup;            // Fenetre de conclusion
  GtkWidget* boutonfermer;     // Bouton pour la fermer


  int occurences; // Nombre d'occurences voulues
  double xd, yd;  // Coordonnées du point de départ de la trajectoire
  double xa, ya;  // Coordonnées du point d'arrivée de la trajectoire
  double xt, yt;  // Coordonnées du point intérmédiaire pour le cercle
  double x1, y1;  // Coordonnées du point d'arrivée de la trajectoire (temp)
  double x2, y2;  // Coordonnées du point d'arrivée de la trajectoire (temp)
  double delta;   // Delta pour eq. du second degrés
  int cpt;        // Compteur des occurences
  float a, b;     // Coef. directeur et point initial de la fonction : y=a*x+b

  int xo=230;        // Centre du cercle et du cercle tronqué
  int yo=200;        // Centre du cercle et du cercle tronqué
  int R=150;         // Rayon du cercle et de la partie circulaire du tronké

  /* INITIALISATIONS : */
  cpt=1;  
  /* Récupération des paramètres pour permettre le dessin */
  zone = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (user_data), "zone"));
  graph = zone->window;
  gc = gdk_gc_new (graph);

  /* Récupération de la zone de commentaire */
  com = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (user_data), "com"));

  /* Récupération des coef de la fonction : a et b ainsi que du nb d'occ */
  a = g_strtod (gtk_entry_get_text(GTK_ENTRY (gtk_object_get_data (GTK_OBJECT (user_data), 
								   "saisie_a"))), NULL);
  b =  g_strtod (gtk_entry_get_text(GTK_ENTRY (gtk_object_get_data (GTK_OBJECT (user_data), 
								    "saisie_b"))), NULL);
  occurences=g_strtod (gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT (user_data), 
									"saisie_occ"))), NULL); 
  /***====================================================================***/

  /******************/
  /* Méthode trigo. */
  /******************/
      
  /* Recherche de la première trajectoire 
     <cf dans la boucle pour plus de détails */
  
  delta =(2*a*b-2*yo*a-2*xo)*(2*a*b-2*yo*a-2*xo)-4*(a*a+1)*(b*b-2*yo*b+yo*yo+xo*xo-R*R);
  if (delta>0)
    {
 
  //§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
  //Commentaire -- Conclusion
  //§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
  popup =  gtk_dialog_new ();
  gtk_window_set_title (GTK_WINDOW (popup), "Conclusion");

  if (occurences>=20)
    // Conclusion : Caustique et pas chaos
    gtk_container_add (GTK_CONTAINER (GTK_DIALOG(popup)->vbox), gtk_label_new (txt_cercle));
  else
    // Conclusion : Mettez plus de rebond
    gtk_container_add (GTK_CONTAINER (GTK_DIALOG(popup)->vbox), gtk_label_new (txt_occurence)); 

  boutonfermer = gtk_button_new_with_label("ok");
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG(popup)->action_area), boutonfermer);
  gtk_signal_connect (GTK_OBJECT (boutonfermer), "clicked",
		      GTK_SIGNAL_FUNC (fermer_dialogue), popup);
  gtk_signal_connect (GTK_OBJECT (popup), "delete-event",
		      GTK_SIGNAL_FUNC (fermer_dialogue1), popup);
  /* Option de la fenetre de dialogue et affichage */
  gtk_window_set_modal (GTK_WINDOW (popup), TRUE);
  gtk_widget_show_all (popup);
  //§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§

      xd=(2*yo*a+2*xo-2*a*b - sqrt(delta))/(2*(a*a+1));
      yd=((a*xd)+b);
      
      xt=(2*yo*a+2*xo-2*a*b + sqrt(delta))/(2*(a*a+1));
      yt=((a*xt)+b);
      
      gdk_draw_line(graph,gc,xd,yd,xt,yt);
      
      /* Affichage dans le shell des valeurs de xd,yd,xa,ya 
	 pour vérification ou débogage. */	    
      /*printf("********************\n0 \n");
      printf("(xd,yd)=( %f,", xd);
      printf(" %f )\n", yd);
      printf("(xt,yt)=( %f,", xt);
      printf(" %f )\n\n", yt);*/
     
    }
  else
    { // Trajectoire en dehors de la figure
      gtk_label_set_text(GTK_LABEL(com),txt_hors_zone);
      cpt=occurences+1;
      xd=50;yd=a*xd+b;
      xt=60;yt=a*xt+b;
      gdk_draw_line(graph,gc,xd,yd,xt,yt);
    }
  
  while(cpt<=occurences)
    {
      /* Affichage dans le shell du compteur pour voir dans 
	 quelle boucle il est lors d'un pantage */
      //printf("%d \n",cpt);
      
      /* Calculs des coéfficients de l'équation de la droite passant par les points D et A.
	 a = y'(xt) -- y est obtenu avec l'équation du cercle */

      if (xo-xt!=0)
	{
	  a=((xt-xo)/(yo-yt));
	  b=(yd+(xd*((xo-xt)/(yo-yt))));
	}
      else
	if (yo-yt!=0)
	  {
	    a=((xo-xt)/(yo-yt));
	    b=(-xd*((xo-xt)/(yo-yt))+yd);
	  }
     

      /* Calculs des points d'intersections avec les équations
	 Système :
	 /  (x-xo)²+(y-yo)²=R²
	 \  y=ax+b
	 <=> ...
	 <=> (a²+1)x²+(ba-2yoa-2xo)x+b²-2yob+yo²+xo²-R²
	 
	 Résolution de l'équation de degrés deux :
	 Delta = b²-4ac */  
      delta =(2*a*b-2*yo*a-2*xo)*(2*a*b-2*yo*a-2*xo)-4*(a*a+1)*(b*b-2*yo*b+yo*yo+xo*xo-R*R);

      if (delta>0) // Théoriquement inutile mais ...
	{
	  x1=(2*yo*a+2*xo-2*a*b - sqrt(delta))/(2*(a*a+1));
	  y1=a*x1+b;
	
	  x2=(2*yo*a+2*xo-2*a*b + sqrt(delta))/(2*(a*a+1));
	  y2=a*x2+b;

	  if (test_egalite(xd, yd, x1, y1)==1)
	    {xd=x1;yd=y1;
	    xa=x2; ya=y2;}
	  else
	    {xd=x2;yd=y2;
	    xa=x1; ya=y1;}
	   	    	    
	  /* Tracage de la trajectoire de (xt,yt) à (xa,ya) */
	  gdk_draw_line (graph, gc, xt, yt, xa, ya);
	    
	  /*   Affichage dans le shell des valeurs de xd,yd,xa,ya 
	       pour vérification ou débogage. */	    
	  /*printf("(xt,yt)=( %f,", xt);
	  printf(" %f )\n", yt);
	  printf("(xa,ya)=( %f,", xa);
	  printf(" %f )\n\n", ya);*/

	  /* Changement des points pour la boucle suivante */
	  xd=xt;yd=yt; // D <-- T
	  xt=xa;yt=ya; // T <-- A
      
	  /* Incrémentation du compteur */
	  cpt=cpt+1; 
	}
    }
    
}

/******************************************************
 *  Fonction  : tracer_cercle_tronque
 *  Utilité   : Trace les trajectoires dans le cercle tronqué.
 *              Affiche la conclusion du tracé.
 *  Remarques : Fonction appelée par la fonction : tracer
 ******************************************************/
void tracer_cercle_tronque (GtkWidget* widget, gpointer user_data) 
{
  /* Déclaration des variables : */
  GtkWidget* zone;  // Zone de dessin
  GdkGC* gc;        // Contexte Graphique 
  GdkWindow* graph; // Zone d'affichage
  GtkWidget* com;   // Zone de commentaire

  GtkWidget* popup;            // Fenetre de conclusion
  GtkWidget* boutonfermer;     // Bouton pour la fermer

  int occurences; // Nombre d'occurences voulues
  double xd, yd;  // Coordonnées du point de départ de la trajectoire
  double xa, ya;  // Coordonnées du point d'arrivée de la trajectoire
  double xt, yt;  // Coordonnées du point intérmédiaire pour le cercle
  double x1, y1;  // Coordonnées du point d'arrivée de la trajectoire (temp)
  double x2, y2;  // Coordonnées du point d'arrivée de la trajectoire (temp)
  double delta;   // Delta pour eq. du second degrés
  int cpt;        // Compteur des occurences
  float a, b;     // Coef. directeur de point initial de la fonction : y=a*x+b

  int xo=230;     // Centre du cercle et du cercle tronqué
  int yo=200;     // Centre du cercle et du cercle tronqué
  int R=150;      // Rayon du cercle et de la partie circulaire du tronké

  /* INITIALISATIONS : */
  cpt=1;  
  /* Récupération des paramètres pour permettre le dessin */
  zone = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (user_data), "zone"));
  graph = zone->window;
  gc = gdk_gc_new (graph);

  /* Récupération de la zone de commentaire */
  com = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (user_data), "com"));

  /* Récupération des coef de la fonction : a et b ainsi que du nb d'occ */
  a = g_strtod (gtk_entry_get_text(GTK_ENTRY (gtk_object_get_data (GTK_OBJECT (user_data), 
								   "saisie_a"))), NULL);
  b =  g_strtod (gtk_entry_get_text(GTK_ENTRY (gtk_object_get_data (GTK_OBJECT (user_data), 
								    "saisie_b"))), NULL);
  occurences=g_strtod(gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT (user_data), 
								       "saisie_occ"))), NULL); 
  /***====================================================================***/

  /******************/
  /* Méthode trigo. */
  /******************/


  /* Recherche de la première trajectoire 
     <cf dans la boucle pour plus de détails */
  
  delta =(2*a*b-2*yo*a-2*xo)*(2*a*b-2*yo*a-2*xo)-4*(a*a+1)*(b*b-2*yo*b+yo*yo+xo*xo-R*R);
  if (delta>0)
    {
      //§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
      //Commentaire -- Conclusion
      //§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
      popup =  gtk_dialog_new ();
      gtk_window_set_title (GTK_WINDOW (popup), "Conclusion");
      
      if (occurences>=20)
	// Conclusion : Caustique et pas chaos
	gtk_container_add (GTK_CONTAINER (GTK_DIALOG(popup)->vbox), 
			   gtk_label_new (txt_tronk));
      else
	// Conclusion : Mettez plus de rebond
	gtk_container_add (GTK_CONTAINER (GTK_DIALOG(popup)->vbox), 
			   gtk_label_new (txt_occurence)); 
      
      boutonfermer = gtk_button_new_with_label("ok");
      gtk_container_add (GTK_CONTAINER (GTK_DIALOG(popup)->action_area), boutonfermer);
      gtk_signal_connect (GTK_OBJECT (boutonfermer), "clicked",
			  GTK_SIGNAL_FUNC (fermer_dialogue), popup);
      gtk_signal_connect (GTK_OBJECT (popup), "delete-event",
			  GTK_SIGNAL_FUNC (fermer_dialogue1), popup);
      /* Option de la fenetre de dialogue et affichage */
      gtk_window_set_modal (GTK_WINDOW (popup), TRUE);
      gtk_widget_show_all (popup);
      //§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
      
      xd=(2*yo*a+2*xo-2*a*b - sqrt(delta))/(2*(a*a+1));
      yd=((a*xd)+b);
      
      xt=(2*yo*a+2*xo-2*a*b + sqrt(delta))/(2*(a*a+1));
      yt=((a*xt)+b);
      
      if (xt<305 || xd <305)
	{
	  //Vérification si ça tombe pas sur la coupure du cercle
	  if (xt>=305)
	    {xt=305;
	    yt=a*xt+b;}
	  else
	    {if (xd>=305)
	      {xd=305;
	      yd=a*xd+b;}
	    }
	  gdk_draw_line(graph,gc,xd,yd,xt,yt);
	  
	  /* Affichage dans le shell des valeurs de xd,yd,xa,ya 
	     pour vérification ou débogage. */	    
	  /*printf("********************\n0 \n");
	  printf("(xd,yd)=( %f,", xd);
	  printf(" %f )\n", yd);
	  printf("(xt,yt)=( %f,", xt);
	  printf(" %f )\n\n", yt);*/
	}
    }
  else
    { // Trajectoire en dehors de la figure
      gtk_label_set_text(GTK_LABEL(com),txt_hors_zone);
      cpt=occurences+1;
      xd=50;yd=a*xd+b;
      xt=60;yt=a*xt+b;
      gdk_draw_line(graph,gc,xd,yd,xt,yt);
    }

  
  while(cpt<=occurences)
    {
      /* Affichage dans le shell du compteur pour voir dans quelle boucle il est lors d'un pantage */
      //printf("%d \n",cpt);
      
      /* Calculs des coéfficients de l'équation de la droite passant par les points D et A.
	 a = y'(xt) -- y est obtenu avec l'équation du cercle */
      
      if (xt!=305)
	{
	  if (xo-xt!=0)
	    {
	      a=((xt-xo)/(yo-yt));
	      b=(yd+(xd*((xo-xt)/(yo-yt))));
	    }
	  else
	    if (yo-yt!=0)
	      {
		a=((xo-xt)/(yo-yt));
		b=(-xd*((xo-xt)/(yo-yt))+yd);
	      }
	}
      else
	{a=-a;
	b=yt-a*xt;}
      
	  /* Calculs des points d'intersections avec les équations
	     Système :
	     /  (x-xo)²+(y-yo)²=R²
	     \  y=ax+b
	     <=> ...
	     <=> (a²+1)x²+(ba-2yoa-2xo)x+b²-2yob+yo²+xo²-R²
	 
	     Résolution de l'équation de degrés deux :
	     Delta = b²-4ac */  
	  delta =(2*a*b-2*yo*a-2*xo)*(2*a*b-2*yo*a-2*xo)-4*(a*a+1)*(b*b-2*yo*b+yo*yo+xo*xo-R*R);
	  
	  if (delta>0) // Théoriquement inutile mais ...
	    {
	      x1=(2*yo*a+2*xo-2*a*b - sqrt(delta))/(2*(a*a+1));
	      y1=a*x1+b;
	      
	      x2=(2*yo*a+2*xo-2*a*b + sqrt(delta))/(2*(a*a+1));
	      y2=a*x2+b;
	      
	      if (xt!=305)
		if (test_egalite(xd, yd, x1, y1)==1)
		  {xd=x1;yd=y1;
		  xa=x2; ya=y2;}
		else
		  {xd=x2;yd=y2;
		  xa=x1; ya=y1;}
	      else
		if (x1<305)
		  {xa=x1; ya=y1;}
		else
		  {xa=x2; ya=y2;}

	      //Vérification si ça tombe pas sur la coupure du cercle
	      if (xa>305)
		{xa=305;
		ya=a*xa+b;}

	      /* Tracage de la trajectoire de (xt,yt) à (xa,ya) */
	      gdk_draw_line (graph, gc, xt, yt, xa, ya);
	      
	      /*   Affichage dans le shell des valeurs de xd,yd,xa,ya 
		   pour vérification ou débogage. */	    
	      /*printf("(xt,yt)=( %f,", xt);
	      printf(" %f )\n", yt);
	      printf("(xa,ya)=( %f,", xa);
	      printf(" %f )\n\n", ya);*/
	      /********************************/
	      
	      /* Changement des points pour la boucle suivante */
	      xd=xt;yd=yt; // D <-- T
	      xt=xa;yt=ya; // T <-- A
	      
	      /* Incrémentation du compteur */
	      cpt=cpt+1; 
	    }
    }
}

/******************************************************
 *  Fonction  : tracer
 *  Utilité   : Apelle la fonction adéquate pour tracer 
 *               les trajectoires dans la bonne surface 
 *               de jeu.
 *  Remarques : Fonction appelée uniquement lors de
 *               l'appui sur le bouton correspondant : Lancer
 ******************************************************/
void tracer (GtkWidget* widget, gpointer user_data) 
{
  GtkWidget* com;
  /* Récupération et modification de la zone de commentaire */
  com = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (user_data), "com"));
  gtk_label_set_text(GTK_LABEL(com),text);

  if (surface=="rectangle")
    tracer_rectangle(widget, user_data);
  else
    if(surface=="cercle")
      tracer_cercle(widget,user_data);
    else
      tracer_cercle_tronque (widget,user_data);
}
  
/******************************************************
 *  PROGRAMME PRINCIPAL
 ******************************************************/
int main(int argc, char **argv) 
{
  GtkWidget*  fenetre;  // Fenetre de l'application
  GtkWidget*  zone;     // Zone de dessin
  GtkWidget*  com;      // Zone de commentaire 
  GtkWidget*  boitev;   // Boite qui contient la zone de dessin, et les boites horizontales 
  GtkWidget*  boiteh_radio;   // Boite des bouton radio de surface de jeu
  GtkWidget*  boiteh;         // Boite permettant l'affichage des boutons 
  GtkWidget*  boiteh_saisie1; // Boite permettant d'entrée le nombre d'occurence à réaliser
  GtkWidget*  boiteh_saisie2; // Boite permettant d'entrée la fonction de la trajectoire
  GtkWidget*  boutonclear;    // Bouton effacer graphique 
  GtkWidget*  boutoncourbe;   // Bouton tracer courbe
  GtkWidget*  boutonfermer;   // Bouton quitter l'application 

  GtkWidget*  label_occ;      // Label "Occurences ="
  GtkWidget*  saisie_occ;     // Zone de sais e du nb d'occ.

  GtkWidget*  label_eq;       // Label "Equation : y ="
  GtkWidget*  saisie_a;       // Zone de saisie du coef dir.
  GtkWidget*  label_fonc;     // Label "X + "
  GtkWidget*  saisie_b;       // Zone de saisie de b

  GtkWidget*  groupe;         // Groupe des boutons radio
  GtkWidget*  bouton_rect;    // Bouton radio de surface rectangle
  GtkWidget*  bouton_cercle;  // Bouton radio de surface circulaire
  GtkWidget*  bouton_ctronk;  // Bouton radio de surface circulaire tronké
	
  /* Initialisation de gtk  */
  gtk_init(&argc,&argv);

  /************************************************************/

  /*  Création de la fenetre principale */
  fenetre = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  /*  Connexion du signal 'delete-event' appelé lors
      de la fermture de l'application */ 
  gtk_signal_connect (GTK_OBJECT (fenetre), "delete-event",			
		      GTK_SIGNAL_FUNC (close_fenetre), NULL);

  /************************************************************/

  /*  Création d'une boite verticale. Celle-ci va contenir
      la boite des boutons, les deux boites de saisie ainsi 
      que la zone de dessin */
  boitev = gtk_vbox_new (FALSE, 8);
  /*  Ajout de la boite dans la fenêtre */
  gtk_container_add (GTK_CONTAINER (fenetre), boitev);
  /*  Association fentre <-> boitev. Pour permettre de
      retrouver la boite lors de l'effacage de la fenêtre  */
  gtk_object_set_data (GTK_OBJECT (fenetre), "boitev", boitev);

  /************************************************************/

  /*  Création de la boite radio et du groupe */
  boiteh_radio = gtk_hbox_new (FALSE, 8);
  groupe = gtk_radio_button_new(NULL);
  /*  Création de bouton "Rectangle" */
  bouton_rect = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(groupe), 
							    "Rectangle");
  gtk_container_add (GTK_CONTAINER (boiteh_radio), bouton_rect);
  gtk_signal_connect (GTK_OBJECT (bouton_rect),"toggled",
		      GTK_SIGNAL_FUNC(choix_surface_rectangle), fenetre);
  /*  Création de bouton "Cercle" */
  bouton_cercle = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(groupe), 
							      "Cercle");
  gtk_container_add (GTK_CONTAINER (boiteh_radio), bouton_cercle);
  gtk_signal_connect (GTK_OBJECT (bouton_cercle),"toggled",
		      GTK_SIGNAL_FUNC(choix_surface_cercle), fenetre);
  /*  Création de bouton "Cercle tronqué" */
  bouton_ctronk = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(groupe), 
							      "Cercle tronqué");
  gtk_container_add (GTK_CONTAINER (boiteh_radio), bouton_ctronk);
  gtk_signal_connect (GTK_OBJECT (bouton_ctronk),"toggled",
		      GTK_SIGNAL_FUNC(choix_surface_cercle_t), fenetre);

  /************************************************************/

  /*  Création de la "boite à boutons"  */
  boiteh = gtk_hbox_new (FALSE, 8);

  /*  Création du bouton pour "Effacer" les trajectoires */
  boutonclear = gtk_button_new_with_label ("Effacer");
  gtk_container_add (GTK_CONTAINER (boiteh), boutonclear);
  gtk_signal_connect (GTK_OBJECT (boutonclear),"clicked",
		      GTK_SIGNAL_FUNC (effacer), fenetre);

  /*    idem pour "Lancer"  */
  boutoncourbe = gtk_button_new_with_label ("Lancer");
  gtk_container_add (GTK_CONTAINER (boiteh), boutoncourbe);
  gtk_signal_connect (GTK_OBJECT (boutoncourbe),"clicked",
		      GTK_SIGNAL_FUNC (tracer), fenetre);

  /*    idem pour "Fermer" */ 
  boutonfermer = gtk_button_new_with_label ("Fermer");
  gtk_container_add (GTK_CONTAINER (boiteh), boutonfermer);
  gtk_signal_connect (GTK_OBJECT (boutonfermer),"clicked",
		      GTK_SIGNAL_FUNC (close_fenetre), fenetre);
	
  /************************************************************/

  /*  Création de la boite de saisie 1 -- Occurences*/
  boiteh_saisie1 = gtk_hbox_new (FALSE,8);
  /*  Création du label "Occurences =" et de sa zone de saisie */
  label_occ = gtk_label_new ("Occurences =");
  gtk_container_add (GTK_CONTAINER (boiteh_saisie1), label_occ);
  saisie_occ = gtk_entry_new ();
  gtk_container_add (GTK_CONTAINER (boiteh_saisie1), saisie_occ);
  /*  Association fenetre <-> zone. Pour recup plus tard  */
  gtk_object_set_data (GTK_OBJECT (fenetre), "saisie_occ", saisie_occ);

  /************************************************************/

  /*  Création de la boite de saisie 2 -- Equation initiale*/
  boiteh_saisie2 = gtk_hbox_new (FALSE,8);
  /*  Création des labels et des zone de saisie */
  label_eq = gtk_label_new ("Equation : y =");
  gtk_container_add (GTK_CONTAINER (boiteh_saisie2), label_eq);
  saisie_a = gtk_entry_new();
  gtk_container_add (GTK_CONTAINER (boiteh_saisie2), saisie_a);
  gtk_object_set_data (GTK_OBJECT (fenetre), "saisie_a", saisie_a);
  label_fonc = gtk_label_new ("X + ");
  gtk_container_add (GTK_CONTAINER (boiteh_saisie2), label_fonc);
  saisie_b = gtk_entry_new();
  gtk_container_add (GTK_CONTAINER (boiteh_saisie2), saisie_b);
  gtk_object_set_data (GTK_OBJECT (fenetre), "saisie_b", saisie_b);

  /************************************************************/

  /*  Création de la zone de dessin */
  zone = gtk_drawing_area_new ();
  /*  Taille par défaut */
  gtk_drawing_area_size (GTK_DRAWING_AREA (zone), 400, 400);
  /*  Association fenetre <-> zone. Pour recup plus tard */
  gtk_object_set_data (GTK_OBJECT (fenetre), "zone", zone);

  /************************************************************/

  /*  Création de la zone de commentaire */
  com = gtk_label_new("Séléctionnez une surface de jeu puis entrez vos valeurs.");
  /*  Association fenetre <-> zone. Pour recupération plus tard */
  gtk_object_set_data (GTK_OBJECT (fenetre), "com", com);

  /************************************************************/

  /*  Ajout des boites horizontales dans la boite verticale */
  gtk_container_add (GTK_CONTAINER (boitev), boiteh_radio); 
  gtk_container_add (GTK_CONTAINER (boitev), boiteh_saisie1);
  gtk_container_add (GTK_CONTAINER (boitev), boiteh_saisie2);
  gtk_container_add (GTK_CONTAINER (boitev), boiteh);
  gtk_container_add (GTK_CONTAINER (boitev), com);
  gtk_container_add (GTK_CONTAINER (boitev), zone);

  /************************************************************/

  /*  On affiche tout ce que l'on vient de créer */
  gtk_widget_show_all (fenetre);

  /*  On entre dans la boucle de traitement des évènements */
  gtk_main ();
  return (0);
}
