------------------------------------------------------------------------------------------------ -- Nom : Power_Calculator / fait partie du programme Power Fractal -- -- -- -- Auteurs : Gregory Burri & Adrien Crivelli -- ------------------------------------------------------------------------------------------------ -- But : Outils de calculs des fractals ainsi que de l'antialiasing -- ------------------------------------------------------------------------------------------------ with Ada.Numerics; use Ada.Numerics; with Ada.Numerics.Generic_Elementary_Functions; --Fonctions mathematiques avancees with Ada.Numerics.Generic_Complex_Types; with Ada.Text_IO; package body Power_Calculator is ------------------------------------------------------------------------------------------------ -- Nom : Calcul_Antialiasing -- -- But : Contracter une matrice en une autre 4 fois plus petite -- -- -- -- Parametres ---------------------------------------------------------------------------------- -- In : La matrice a antialiasinger -- -- -- -- return : La matrice traitee -- ------------------------------------------------------------------------------------------------ function Calcul_Antialiasing(Matrice_Antialiasing : T_Matrice_Tampon) return T_Matrice_Tampon is X, Y : Natural; --Variables pour le parcours de la matrice --La matrice de retour, qui est evidement 2 fois plus petite que celle en entrer Matrice_Retour : T_Matrice_Tampon ( 0..(Matrice_Antialiasing'Last(1) - 1) / 2, 0..(Matrice_Antialiasing'Last(2) - 1) / 2 ); begin --Calcul_Antialiasing X := 0; --Parcours toutes les colonnes impaires while X <= Matrice_Antialiasing'Last(1) - 1 loop Y:=0; --Parcours toutes les lignes impaires while Y <= Matrice_Antialiasing'Last(2) - 1 loop --Fait la moyenne de quatre points pour n'en former qu'un seul Matrice_Retour(X/2, Y/2).R := Byte ((Integer(Matrice_Antialiasing(X, Y).R) + Integer(Matrice_Antialiasing(X + 1,Y).R) + Integer(Matrice_Antialiasing(X, Y + 1).R) + Integer(Matrice_Antialiasing(X + 1, Y + 1).R)) / 4); Matrice_Retour(X/2, Y/2).G := Byte ((Integer(Matrice_Antialiasing(X, Y).G) + Integer(Matrice_Antialiasing(X + 1,Y).G) + Integer(Matrice_Antialiasing(X,Y + 1).G) + Integer(Matrice_Antialiasing(X + 1, Y + 1).G)) / 4); Matrice_Retour(X/2, Y/2).B := Byte ((Integer(Matrice_Antialiasing(X, Y).B) + Integer(Matrice_Antialiasing(X + 1,Y).B) + Integer(Matrice_Antialiasing(X, Y + 1).B) + Integer(Matrice_Antialiasing(X + 1, Y + 1).B)) / 4); Y:=Y+2; end loop; X:=X+2; end loop; return Matrice_Retour; --retourne la matrice quatre fois plus petite end; ------------------------------------------------------------------------------------------------ -- Nom : Change_Angle -- -- But : Changer l'angle d'un nombre complexe par rapport au centre de l'ecran -- -- -- -- Parametres ---------------------------------------------------------------------------------- -- In : * La fractal, -- -- -- -- In out : * Partie reel du nb complexe : A -- -- * Partie imaginaire du nb complexe : B -- ------------------------------------------------------------------------------------------------ procedure Change_Angle (A, B : in out Long_Float; Fractal : Cara_Fractal) is Rayon : Long_Float; --Le rayon du nombre complexe Phi : Long_Float; --Le nouvel angle calcule --L'angle en parametre est converti en radian Angle_Rad : Long_Float := Pi * Fractal.Angle / 180.0; --Pour pouvoir faire des operations (sin cos etc..) sur des Long_Float package Elementary_Functions_Long_Float is new Ada.Numerics.Generic_Elementary_Functions (Long_Float); use Elementary_Functions_Long_Float; begin --Ramene l'origine du nombre complexe au centre de l'ecran A := A - Fractal.Centre.X; B := B - Fractal.Centre.Y; -- --Pour eviter la division par zero if A /= 0.0 then --Si 'A' est negatif => (l'angle est compris entre : 90 < angle < -90) if A < 0.0 then --Calcul de l'angle en additionnant a l'angle de base l'angle que l'on veut Phi := Arctan( B / A ) + Angle_Rad + Pi; else Phi := Arctan( B / A ) + Angle_Rad; -- end if; else --si l'angle est compris entre : 180 < angle < 360 alors if B < 0.0 then --Calcul de l'angle en additionnant a Pi/2.0 l'angle que l'on veut Phi := Pi / 2.0 + Angle_Rad + Pi; else Phi := Pi / 2.0 + Angle_Rad; -- end if; end if; Rayon := Sqrt( A**2 + B**2 ); --Calcul le rayon (module) A := Rayon * Cos( Phi ); --Calcul la partie reel B := Rayon * Sin( Phi ); --Calcul la partie imaginaire --Ramene l'origine du nombre comples au centre (0,0) A := A + Fractal.Centre.X; B := B + Fractal.Centre.Y; -- end Change_Angle; ------------------------------------------------------------------------------------------------ -- Nom : Mandel_Gen -- -- But : Genere une matrice d'iteration selon l' ensemble de Mandelbrot -- -- Z(n+1) = Z(n)^2 + Z(o) -- -- Parametres ---------------------------------------------------------------------------------- -- In : * Largeur_Zone et Hauteur_Zone : Dimension de la zone de calcul -- -- * Fractal : L'ensemble des caracteristiques de la fractal -- -- -- -- return : * Une matrice contenant la fractal sous forme de nombre d'iteration pour chaque -- -- point -- ------------------------------------------------------------------------------------------------ function Mandel_Gen (Largeur_Zone, Hauteur_Zone : Natural; Fractal : Cara_Fractal) return T_Matrice_Iteration is ------Nombre complexe : Z = A + Bj------ package Complex_Long_Float is new Ada.Numerics.Generic_Complex_Types(Long_Float); use Complex_Long_Float; use Ada.Text_IO; Zo : Complex; Pas : Complex; Za : Complex; Zs : Complex; N : constant Natural := 20; --Precision de l'interpolation Ao,Bo-- la valeur reel et imaginaire du point en cours de traitement : Z(o) : Long_Float; Nb_Iteration : Float; --Pour compter le nombre d'iteration --La matrice est cree et retournee Matrice_Retour : T_Matrice_Iteration (0..Largeur_Zone, 0..Hauteur_Zone); --la hauteur et la largeur en long float Largeur_Zone_Tmp_Float : Long_Float := Long_Float(Largeur_Zone); Hauteur_Zone_Tmp_Float : Long_Float := Long_Float(Hauteur_Zone); --Variable precalculee pour ne pas avoir a la calculer a chaque iteration Pre_Calcul : Long_Float; begin -- Mandel_Gen Pre_Calcul := (2.0 * Largeur_Zone_Tmp_Float) * Fractal.Zoom; --Parcours toute la dimension X de l'affichage (pixel) for X in 0..Largeur_Zone loop --Parcours toute la dimension Y de l'affichage (pixel) for Y in 0..Hauteur_Zone loop --Convertie la valeur x du point a l'ecran(pixel) en valeur reel sur la fractal --Voir la doc pour plus d'informations Ao := ((Long_Float(X) / Largeur_Zone_Tmp_Float) - 0.5 ) / Fractal.Zoom + Fractal.Centre.X ; --Convertie la valeur y du point a l'ecran(pixel) en valeur reel sur la fractal --Voir la doc pour plus d'informations Bo := (-2.0 * Long_Float(Y) + Hauteur_Zone_Tmp_Float) / Pre_Calcul + Fractal.Centre.Y; Change_Angle(Ao, Bo, Fractal); Zo := Compose_From_Cartesian(Ao , Bo); Za := Zo; Nb_Iteration := 0.0; --Initialise le compteur d'iteration a 0 --Boucle calculant la divergence d'un point du plan M : loop Zs := Za**2 + Zo; Pas := Zs/Long_Float(N) - Za/Long_Float(N); for I in 1..N loop --Sort si le nombre maximale d'iteration a ete atteind --ou si le module du nb complexe a dapasse la limite de divergence. --Astuce : la limite represente en fait le carre du module, --ce qui permet de faire moins de calculs exit M when (Re(Za)**2 + Im(Za)**2) > Fractal.C_Diverge_Limite ; Nb_Iteration := Nb_Iteration + 1.0/Float(N); Za := Za + Pas; end loop; --Za := Zs; --a enlever exit when Nb_Iteration >= Float(Fractal.Nb_Iteration_Max); end loop M; --Enregistre le point calcule dans la matrice d'iteration (Global) Matrice_Retour(X,Y) := Nb_Iteration; --Put(Float'Image(Nb_Iteration)); end loop; end loop; for I in Matrice_Retour'range(1) loop Put_Line(Float'Image(Matrice_Retour(I,0))); end loop; return Matrice_Retour; --Retourne la matrice end Mandel_Gen; ------------------------------------------------------------------------------------------------ -- Nom : Julia_Gen -- -- But : Genere une matrice d'iteration selon l' ensemble de Julia -- -- Z(n+1) = Z(n)^2 + c 'c' etant une constante arbitraire -- -- Parametres ---------------------------------------------------------------------------------- -- In : * Largeur_zone et Hauteur_Zone : Dimension de la zone de calcul -- -- * Fractal : L'ensemble des caracteristiques de la fractal -- -- -- -- return : * Une matrice contenant la fractal sous forme de nombre d'iteration pour chaque -- -- point -- ------------------------------------------------------------------------------------------------ function Julia_Gen (Largeur_Zone, Hauteur_Zone : Natural; Fractal : Cara_Fractal) return T_Matrice_Iteration is ------Nombre complexe : Z = A + Bj------ package Complex_Long_Float is new Ada.Numerics.Generic_Complex_Types(Long_Float); use Complex_Long_Float; use Ada.Text_IO; Pas : Complex; Za : Complex; Zs : Complex; C : Complex := Compose_From_Cartesian (Fractal.Cx, Fractal.Cy); N : constant Natural := 20; --Precision de l'interpolation Ao,Bo-- la valeur reel et imaginaire du point en cours de traitement : Z(o) : Long_Float; Nb_Iteration : Float; --Pour compter le nombre d'iteration --La matrice est cree et retournee Matrice_Retour : T_Matrice_Iteration (0..Largeur_Zone, 0..Hauteur_Zone); --la hauteur et la largeur en long float Largeur_Zone_Tmp_Float : Long_Float := Long_Float(Largeur_Zone); Hauteur_Zone_Tmp_Float : Long_Float := Long_Float(Hauteur_Zone); --Variable precalculee pour ne pas avoir a la calculer a chaque iteration Pre_Calcul : Long_Float; begin -- Mandel_Gen Pre_Calcul := (2.0 * Largeur_Zone_Tmp_Float) * Fractal.Zoom; --Parcours toute la dimension X de l'affichage (pixel) for X in 0..Largeur_Zone loop --Parcours toute la dimension Y de l'affichage (pixel) for Y in 0..Hauteur_Zone loop --Convertie la valeur x du point a l'ecran(pixel) en valeur reel sur la fractal --Voir la doc pour plus d'informations Ao := ((Long_Float(X) / Largeur_Zone_Tmp_Float) - 0.5 ) / Fractal.Zoom + Fractal.Centre.X ; --Convertie la valeur y du point a l'ecran(pixel) en valeur reel sur la fractal --Voir la doc pour plus d'informations Bo := (-2.0 * Long_Float(Y) + Hauteur_Zone_Tmp_Float) / Pre_Calcul + Fractal.Centre.Y; Change_Angle(Ao, Bo, Fractal); Za := Compose_From_Cartesian(Ao , Bo); Nb_Iteration := 0.0; --Initialise le compteur d'iteration a 0 --Boucle calculant la divergence d'un point du plan M : loop Zs := Za**2 + C; Pas := Zs/Long_Float(N) - Za/Long_Float(N); for I in 1..N loop --Sort si le nombre maximale d'iteration a ete atteind --ou si le module du nb complexe a dapasse la limite de divergence. --Astuce : la limite represente en fait le carre du module, --ce qui permet de faire moins de calculs exit M when (Re(Za)**2 + Im(Za)**2) > Fractal.C_Diverge_Limite ; Nb_Iteration := Nb_Iteration + 1.0/Float(N); Za := Za + Pas; end loop; Za := Zs; --a enlever exit when Nb_Iteration >= Float(Fractal.Nb_Iteration_Max); end loop M; --Enregistre le point calcule dans la matrice d'iteration (Global) Matrice_Retour(X,Y) := Nb_Iteration; --Put(Float'Image(Nb_Iteration)); end loop; end loop; --Put(Float'Image(Matrice_Retour(0,0))); return Matrice_Retour; --Retourne la matrice end Julia_Gen; end Power_Calculator;