-----------------------------------------------------------------------------
-- Nom fichier      : Tracer_Approche_Pi                                      
-- Auteur           : R. Chelouah                                          
-- Date             : 06/12/2003                                           
--                                                                         
-- But              :  Dessinner un l'approche de la valeur de Pi                                    
--                     l'utilisateur entre :
--                     les dimensions de la fenetre Spider
--                     la precision de calcul de Pi 
--                     la fenetre d'observation 
--                                                                        
-- Date de modif.   :                                                      
-- Raison           :                                                      
-- Modules appeles  :  Ada.Numerics, 
--                     Spider, Spider.Draw    
-- Mat. particulier :                                                      
-- Compilation      :  Gnat                                      
-- Edition de liens :  Gnat                                      
-- Mode d'execution :  Console                                             
-----------------------------------------------------------------------------
   with ada.Text_IO;                        use ada.Text_IO;               
   with ada.Integer_text_IO;                use ada.Integer_text_IO;       
   with ada.Long_Float_Text_IO;             use ada.Long_Float_Text_IO;   -- Module d'entree/sortie de reels
 
   with ada.Numerics;                       use ada.Numerics;             -- pour la constante Pi

   with Spider;                             use spider;                   -- pour la fenetre graphique
       

   -- procedure principale
   procedure Tracer_Approche_Pi is
   
      Mon_Choix    : Character ;          -- Variable mon choix
      Increment    : constant := 2;       -- Increment pour le numerateur et denominateur
   
      Long_X       : Integer ;            -- Dimensions de la fenetre de visualisation
      Long_Y       : Integer ; 
      
      Vue_X        : Integer;             -- Fenetre de vue sur X
      Vue_Y        : Integer := 5;        -- Fenetre de vue Sur Y

      Decalage_X   : Positive;            -- Decaler l'axe des Y par rapport aux bords de la fenetre Spider
      Decalage_Y   : Positive;            -- Decaler l'axe des X par rapport aux bords de la fenetre Spider
      
      Echelle_X    : Long_Float ;         -- Facteur d'echelle sur l'axe X 
      Echelle_Y    : Long_Float ;         -- Facteur d'echelle sur l'axe Y
      
      Precision    : Long_Float ;         -- Precision d'approche de la valeur Pi avec Wallis

      Ancien_Pi    : Long_Float;          -- Valeur de Pi a calculer
      Nouveau_Pi   : Long_Float;          -- Nouveau Pi apres chaque etape

      Numerateur   : Integer;             -- Numerateur du terme de Wallis
      Denominateur : Integer;             -- Denominateur du terme de Wallis
      Compteur     : integer;             -- Compteur de boucles effectuees
      
   begin -- Tracer_Approche_Pi
      
      -- presentation du programme
      Put_Line(" Ce programme calcule approximativement le nombre Pi ");
      Put_Line(" a l'aide de la suite de Wallis.");
      New_Line;
      Put_Line(" Cette suite se calcule ainsi : Pi/2 = 2/1*2/3*4/3*4/5*6/5*6/7...");
     
      -- boucle de repetition avec loop
      loop
          New_Line(2);         
          put_Line(" Les dimensions de votre fenetre graphique  entre 100 et 600 : ");
      
          put(" Donner la valeur de la longueur X de la fenetre : ");
          Get(Long_X);
          Skip_Line;
          
          put(" Donner la valeur de largeur Y de la fenetre     : ");
          Get(Long_Y);
          Skip_Line;
          
          New_Line(2);
            
          put(" Donner la precision sur le calcul de Pi entre 0.1 ..0.00001 : ");
          Get(Precision);
          Skip_Line;
          
          put(" Donner la longueur X de la vue : 1..10000  : ");
          Get(Vue_X);
          Skip_Line;
          
          Init_Size_Window(" Visualisation de l'approche de Pi :" &
                            Integer'Image(Long_X)&"x"&Integer'Image(Long_Y), 
                            Long_X, Long_Y);

          -- Decalage de l'axe Y est egal a la largeur d'un caractere
          Decalage_X := Get_Width_Char;
         
          -- Decalage de l'axe X est egal a la hauteur d'un caractere
          Decalage_Y := Get_Height_Char;
  
          -- Le vrai espace visualisation dans la fenetre spider
          Long_X := Long_X - Decalage_X;
          Long_Y := Long_Y - Decalage_Y;
          
          -- Calcul des facteurs d'echelle dans le vrai espace de visualisation
          Echelle_X := Long_Float(Long_X)/Long_Float(Vue_X);
          Echelle_Y := Long_Float(Long_Y)/Long_Float(Vue_Y);
          
          -- Choisir la couleur rouge et tracer des axes                         
          Set_Color_Pen(Red);
          Line_To(Decalage_X, Long_Y , Long_X + Decalage_X, Long_Y); -- axe horizontal
          Line_To(Decalage_X, 0, Decalage_X, Long_Y);                -- axe vertical
          
          -- Choisir la couleur noire pour le trace de la constante Pi
          Set_Color_Pen(Blue);
          Line_To(Decalage_X,
                  Integer(Long_Float(Long_Y)-Pi*Echelle_Y),
                  Long_X + Decalage_X,
                  Integer(Long_Float(Long_Y)-Pi*Echelle_Y));



          -----------------------------------------------------------------------------------
          -- Partie optionnelle, affichage de quelques constantes sur la fenetre spider
          -----------------------------------------------------------------------------------
          -- representer l'origine par 0, et les valeurs max et min sur les axes
          Move_To(0,  Long_Y);
          Display_Text("0");
          
          Move_To(0, 0);
          Display_Text(Integer'Image(Vue_Y));
          
          Move_To(Long_X-Decalage_X, Long_Y);
          Display_Text(Integer'Image(Vue_X));
          
          -- choisir la couleur bleue pour le trace du texte donnant la valeur de Pi
          Set_Color_Pen(Brown);
          Move_To(2*Decalage_X, Integer(Long_Float(Long_Y)-Pi*Echelle_Y)+Decalage_Y);
          Display_Text("Pi = 3.14159_26535_89793");

          ------------------------------------------------------------------------------------          
          -- Initialisation des parametre de l'algorithme wallis
          Ancien_Pi    := 2.0;
          Numerateur   := 2;  -- je pars du premier terme de la suiste de Wallis   
          Denominateur := 1;  -- je pars du premier terme de la suiste de Wallis 
          Compteur     := 0;  -- c'est la position de mon premier
          
          loop
              -- Si le nombre de boucle deja effectue est pair, on augment de 2 
              -- le denominateur, sinon c'est le numerateur qui est augmenter de 2
              if compteur rem 2 = 0 then
                  denominateur := denominateur + increment;
              else   
                  Numerateur := Numerateur + increment;
              end if;

              -- Calcul du nouveau Pi avec les nouvelles valeurs du denominateur et du numerateur
              Nouveau_Pi := Ancien_Pi * Long_Float(Numerateur)/Long_Float(Denominateur);
              
              -- On vient de faire une boucle de plus
              Compteur := Compteur +1;

              Line_To(Decalage_X + Integer(Long_Float(Compteur-1)*Echelle_X),    -- Xi
                      Integer(Long_Float(Long_Y) - 2.0*Ancien_Pi*Echelle_Y),     -- Yi
                      Decalage_X + Integer(Long_Float(Compteur)*Echelle_X),      -- Xi+1
                      Integer(Long_Float(Long_Y) - 2.0*Nouveau_Pi*Echelle_Y));   -- Yi+1
              
              -- Calcul de Pi jusqu'a ce que la precision soit atteinte
              -- On calcule Pi/2, c'est pour cette raison que la precision doit
              -- etre aussi deux fois plus faible
              exit when  abs(Nouveau_Pi - Ancien_Pi) <= Precision/2.0;

              Ancien_Pi := Nouveau_Pi;
              
          end loop; -- boucle loop
          ------------------------------------------------------------------------------------
          
          -- Affiche du Pi calcule
          Put(" Voici la valeur du Pi calcule avec une precision de ");
          Put(Precision,1,5,0);
          Put(" : ");
          Put(2.0 * Nouveau_Pi,2,6,0);
          New_Line;
          Put(" Voici le nombre d'iterations necessaires pour l'obtenir : ");
          Put(Compteur, 0); 
          
          ------------------------------------------------------------------------------
          -- Partie optionnelle, affichage des résultats de sortie sur la fenetre spider
          ------------------------------------------------------------------------------          
          Move_To(Long_X - (4* Long_X/5), Long_Y -( Long_Y /3));
          Display_Text("Nombre d'iterations est de : " & Integer'Image(Compteur));
          Move_To(Long_X - (4* Long_X/5), Long_Y -( Long_Y /3) - 2*Decalage_Y);
          Display_Text("La precision est de : " & Float'Image(Float(Precision)));
          ------------------------------------------------------------------------------
         
          New_Line;            
          Put(" Taper une touche pour continuer... ");
          Skip_Line;
                   
          New_Line;
          Put( " voulez vous quitter ? tapez [O/N] : " );
          Get(Mon_Choix);
          Skip_Line;
          Close_Window;
          
          exit when Mon_Choix = 'o' or Mon_Choix = 'O';
          
      end loop; -- boucle de repetition
           
   end Tracer_Approche_Pi;  --  fin de la procedure