import java.awt.Graphics; 
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener; 
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.BorderLayout; 
import javax.swing.BorderFactory;
import javax.swing.JLabel; 
import javax.swing.JButton;
import java.awt.Dimension;
import javax.swing.JPanel; 
import java.awt.Font;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;	// applet 
import java.util.ArrayList; 
 
import java.awt.*; 
import java.awt.event.*;
import javax.swing.*;

//public class fenetreattract extends JPanel {	//applet JFrame 
public class fenetreattract extends JFrame { 
        static panneauattract pan = new panneauattract();
        static JLabel lpas = new JLabel();
        static JLabel lrac = new JLabel("degré");
   			static JLabel lvide = new JLabel("");
   
        static JButton bsearch = new JButton("<html>Recherche<br>d'attracteurs<br>nbvar="+pan.NBVAR+" type="+pan.TYPE_ATTRACT+"</html>");
        static JButton bhamiltonien = new JButton("<html>Recherche<br>d'attracteurs<br>Hamiltoniens</html>"); 
        static JButton bcyclenext = new JButton("<html>Cycle<br>suivant</html>");
        static JButton brapide = new JButton("<html>Affichage<br>progressif</html>");
        static JButton bmanuel = new JButton("<html>Affichage<br>par cycles<br>manuel</html>");
        static JButton bdetail = new JButton("<html>Détail des<br>coefficients</html>");
        static JButton bcoloration = new JButton("<html>Coloration<br>1 ou 2 dim</html>");
        static JButton bfond = new JButton("<html>Fond<br>noir et blanc</html>");
        static JButton bzoomin = new JButton("<html>Zoom<br>in</html>");
        static JButton bzoomout = new JButton("<html>Zoom<br>out</html>");
             
        static JButton bprojection = new JButton("<html>Projection<br>:plan</html>");
        static JButton b4emedim = new JButton("<html>4eme dimension<br>:couleur</html>");
        static JButton b3emedim = new JButton("<html>3eme dimension<br>:ombre</html>");
        static JButton bnextgroupe = new JButton("<html>Groupe<br>d'attracteurs<br>suivant</html>");
        static JButton bnextattract = new JButton("<html>Attracteur<br>suivant</html>");
        static JButton bchoix = new JButton("<html>Choix du<br>coefficient<br>traveling</html>");
        static JButton bmodifp = new JButton("<html>Incremente<br>coefficient</html>");
        static JButton bmodifm = new JButton("<html>Décremente<br>coefficient</html>");
      	static JButton btravel_coeff = new JButton("<html>Traveling<br>coefficient<br>automatique</html>");
      	static JButton btravel_iter = new JButton("<html>Traveling<br>nombre<br>iterations</html>");
      	static JButton baccelerer = new JButton("<html>Doubler<br>le pas du<br>traveling</html>");
      	static JButton bralentir = new JButton("<html>Réduire<br>le pas du<br>traveling</html>");
      	static JButton bperiode = new JButton("<html>Visualiser<br>1 itération<br>du point</html>");
        static JButton bcoeff = new JButton("<html>Modifier<br>coefficient</html>"); 
        static JButton bdelta = new JButton("<html>Delta<br>différentiel</html>"); 
        static JButton btravel = new JButton("<html>Delta<br>traveling</html>"); 
        static JButton bnmax = new JButton("<html>Nb Itérations<br>maximum</html>"); 
        static JButton bpasmax = new JButton("<html>Nb Itérations<br>d'un cycle</html>"); 
        static JButton bNBVAR = new JButton("<html>Nb de<br>variables</html>"); 
        static JButton btype_attract = new JButton("<html>Type attracteurs<br>à chercher</html>"); 
        static JButton bhelp = new JButton("<html>Aide et<br>commentaires</html>");
				private Dimension dim = new Dimension(95, 55);	//95 
				static JPanel menu = new JPanel();  
				static JPanel menugauche = new JPanel();
				static JPanel menudroite = new JPanel();
				static JPanel zonedroite = new JPanel();

				static String str=new String();
				Timer t;

 /*       static double deltaX;
        static double deltaY; 
        static double x;
        static double y; */
        static ArrayList <String>  liste; 
        
        
public void initattract()
	{
	} 

public void listeattractg() 
{ 
String st1;

liste= new ArrayList <String >() ; 
for (int i=0;i<pan.attracteurs.length;i++)
	{
	st1=pan.attracteurs[i][0]+" "+pan.attracteurs[i][2];
	if (st1.equals(pan.nomattractgroupe))
		{
		if (liste.contains(pan.attracteurs[i][1]+" "+pan.attracteurs[i][2])==false)
				{liste.add(pan.attracteurs[i][1]+" "+pan.attracteurs[i][2]);}
		}
	}
pan.nomattractg=new String [liste.size()];
for (int i=0;i<liste.size();i++)
	{pan.nomattractg[i]=liste.get(i);}
}

public void affiche(String str,String str2)
{ 
JOptionPane.showMessageDialog
	    							(null, 
	     							str, 
	     							str2, 
	     							JOptionPane.INFORMATION_MESSAGE);
}
   
public void help()
{
int indexhelp=0;
String tabhelp[]={"Attracteurs étranges","Dimension fractale","Exposant de Lyapunov","Distance de Hausdorff","Logistic map et extension au plan complexe",
	"Symétries et rotations","Attracteur symétrique","Transformations affines - IFS","Application linéaire contractante","Théorème du point fixe","Théorème du collage",
	"Pavage périodique symétrique","Codage des formules","Familles d'attracteurs","3ème et 4ème dimension","Colorisation","Travelling"};
	     						
String reponse="help";
while (reponse!= null) 
	{ 
	reponse = (String) JOptionPane.showInputDialog
	    							(null,
	     							"Choisir une rubrique de l'aide des attracteurs étranges",
	     							"Attracteurs étranges - http://www.pdbzro.com/gags", 
	     							JOptionPane.QUESTION_MESSAGE,
	     							null,
	     							tabhelp,
	     							tabhelp[indexhelp]);
	 for (int i=0;i<tabhelp.length;i++)	
	 		{
	 		if (reponse==tabhelp[i])
	 				{
	 				switch (i)
	 					{
						case 0:{ 
str="A partir des coordonnées d'un point initial, un attracteur étrange se construit en itérant un grand nombre de fois une formule sur les coordonnées successives obtenues.\n";
str=str+"soit, en 4 dimensions :   (Xn+1,Yn+1,Zn+1,Wn+1) = f(Xn,Yn,Zn,Wn)\n";
str=str+"L'ensemble des point images, s'il ne diverge pas vers l'infini mais couvre seulement une région limitée, est appelé l'attracteur du système de formules\n";
str=str+"l'attracteur peut être :\n";
str=str+"   - un point fixe\n"; 
str=str+"   - un cycle de période plus ou moins grande\n";
str=str+"   - un ensemble de points, le plus souvent cahotique, et parfois avec des symétries et rotations, mais pas de translations\n";
str=str+"Poincaré a montré qu'un ensemble limite d'un système d'équations différentielles à 2 dimensions, qui ne contient pas de point d'équilibre est une orbite périodique\n";
str=str+"et donc que tout système macroscopique repasse une infinité de fois aussi près que l'on veut de son état initial, après un cycle qui peut être très long \n\n"; 
str=str+"Les premiers 100 points sont ignorés, ils servent à converger vers le bassin d'attraction de l'attracteur\n";
str=str+"Les premiers 1000 points ne sont pas affichés non plus, ils servent à calculer les bornes de l'attracteur et à définir les facteurs d'échelle pour l'affichage\n";
str=str+"en supposant que ces 1000 premiers points parcourent tout l'attracteur.\n";
str=str+"Parfois, l'attracteur continue à grossir après les 1000 points, (Hopalong, Martin) il est alors nécessaire d'utiliser le bouton \"zoom out\" pour recadrer l'attracteur\n\n";
str=str+"L'attracteut peut s'afficher en mode progressif (1000 points par seconde) ou en mode rapide\n";
str=str+"en mode progressif, on peut choisir un passage de cycle à cycle manuel ou automatique, c'est à dire afficher 1000 points par 1000 points\n";
str=str+"Lorsque l'attracteur est affiché, on peut faire calculer encore autant de cycles de 1000 points que nécessaire\n";
str=str+"On peut aussi visualiser les itérations successives du point et en suivre le mouvement.\n\n";
str=str+"Les attracteurs se classent par leur nombre de variable (1 à 4), par le degré des polynomes (2 à 5), par les fonctions utilisées et par le nom de leur découvreur\n";
str=str+"On distingue les attracteurs standards des attracteurs différentiels, pour lesquels les fonctions portent sur les coordonnées et calculent les dérivées\n";
str=str+"On calcule alors d'abord les derivées puis les nouvelles coordonnées par : Xn+1 = Xn + epsilon * X'\n";
str=str+"Certains attracteurs sont non polynomiaux, et font intervenir les fonctions abs, sinus, cosinus, sqrt, ...\n\n";
str=str+"Voir le livre : \"Strange Attractors: Creating Patterns in Chaos\" par Julien C. Sprott, dont ce programme est issu en ce qui concerne les attacteurs polynomiaux.\n";
str=str+"En choisissant judicieusement les fonctions parmi les transformations du plan, on peut faire en sorte que l'attracteur ait des axes de symetries et des rotations\n";
str=str+"voir le livre : \"Symmetry in chaos\" de Michael Field et Martin Golubitsky dont ce programme utilise les algorithmes.\n";
 
break;}

						case 1:{
str="La dimension fractale représente la densité avec laquelle l'attracteur remplit la région du plan\n";
str=str+"On trace un cercle qui englobe au moins 1 point, soit N1 points puis un deuxième cercle de même centre et de rayon double, qui englobe N2 points\n";
str=str+"On pose dim = log2 (N2 / N1)\n\n";
str=str+"Si les points sont très dispersés, N1=N2 et dim=0\n";
str=str+"Si les points sont également répartis N2=4*N1 et dim=2\n";
str=str+"Les attracteurs visuellement interessants ont une dimension fractale voisine de 1\n\n";
str=str+"La dimension de Hausdorff d’un ensemble E est le réel d > 0 vérifiant :\n";
str=str+"    n = m^d  soit d=log(n)/log(m) \n";
str=str+"tel qu’après une réduction d’un facteur m, il faut n objets réduits pour reconstituer l’ensemble initial\n\n";
str=str+"la dimension du flocon de Koch est log(4)/log(3)\n";
str=str+"celle du triangle de Sierpinski est log(3)/log(2)\n";
str=str+"pour une famille de n contractions sans recouvrement de rapport k on a n*k^d=1  (k=1/m)\n";
str=str+"pour une famille de n contractions de rapports Ki, somme(Ki^d)=1\n";

break;} 

					case 2:{
str="L'exposant de Lyapunov caractérise la vitesse d'éloignement des points correspondant aux itérations successives\n";
str=str+"On prend L = sigma( log2 (Dn+1 / Dn) / N)\n\n";
str=str+"Si l'écart double, l'exposant vaut 1\n";
str=str+"Si l'écart est divisé par 2, l'exposant vaut -1\n";
str=str+"Si l'attracteur est cahotique l'exposant est positif\n";
str=str+"un cycle a un exposant voisin de 0.\n";
break;}

					case 3:{ // distance de Hausdorff
str="On recherche un nombre appelé distance entre deux figures et qui soit grand si elles sont très différentes et petit si elles se ressemblent beaucoup\n";
str=str+"Et étant nul s’il s’agit des mêmes figures.\n\n";
str=str+"Pour cela, on définit la notion de \"compact\", ensemble de points bornable par un disque\n";
str=str+"et on définit un enclos à la distance D (ou D-voisinage) d'un compact, comme l'ensemble tel que tous ses points sont à une distance usuelle < D d'un des points du compact\n";
str=str+"c'est l'ensemble des disques de rayon D centré sur un des points du compact\n\n";
str=str+"Etant donné deux compacts E et F, on considère le plus petit De-voisinage de E contenant F et le plus petit Df-voisinage de F contenant E\n";
str=str+"La distance de Hausdorff entre E et F est le maximum de De et Df\n";
str=str+"C’est donc aussi la plus petite valeur de r telle que F est inclus dans le r-voisinage de E, et E dans le r-voisinage de F.\n";
str=str+"Attention, ce n'est pas la distance la plus courte pour aller de E à F\n\n";
str=str+"La distance de Hausdorff entre deux points est la distance usuelle\n\n";
str=str+"Les propriétés suivantes se démontrent facilement :\n";
str=str+"     dist(E,F)=dist(F,E)\n";
str=str+"     dist(E,F)=0 <=> E=F\n";
str=str+"     dist(E,F)<=dist(E,G)+dist(G,F)\n";
str=str+"     si une transformation diminue (ou augmente) la distance entre deux points dans un rapport k, elle diminue la distance de Hausdorff entre deux figures dans le même rapport k\n";

break;}
					case 4:{   // logistic map et extension au plan complexe
str="La \"logistic map\" : f(Xn+1)=lambda*Xn*(1-Xn) (avec lambda entre 0 et 4) est un attracteur a une seule variable qui a été très étudié par les mathématiciens\n";
str=str+"pour modéliser l'accroissement d'une population limitée, en tenant compte d'une manière simpliste des proportions de naissance et de disparition.\n\n";
str=str+"Selon la valeur de lambda, la population croit, décroit ou oscille en suivant des periodes à 2, 4, 8 ... cycles\n";
str=str+"c'est le premier attracteur que le programme affiche\n";
str=str+"elle n'est pas symétrique : f(-x) != -f(x)\n\n";
str=str+"on la rend symetrique en rendant ses monomes impaires : f(Xn+1)=lambda*Xn*(1-Xn*Xn)\n";
str=str+"en variant lambda, on trouve également à cette variante symetrique de la logistic map, des points de doublement de période\n\n";
str=str+"on l'étend à deux dimensions en utilisant les nombres complexes : f(z)=lambda*z*(1-z*z') avec z=x+i*y et z'=x-i*y\n";
str=str+"soit xnew=lambda*x(1-(x*x+y*y))\n";
str=str+"et ynew=lambda*y*( 1-(x*x+y*y))\n";
str=str+"y/x est constant, donc partant de Z0, tous les iterés sont sur la droite O Z0 et y ont le comportement de la logistic map\n";
str=str+"on peut généraliser la formule en f(z)=(lambda + alpha*z*z') * z\n";
break;} 
					case 5:{ // symetries et rotations
str="En choisissant les formules d'itérations, on peut s'arranger pour que l'attracteut ait des degrés de symetrie\n";
str=str+"c'est à dire qu'on recherche des formules F telles que, S représentant une symetrie ou une rotation,  F(S(z)) = S(F(z)).\n";
str=str+"si on ajoute des translations, le systeme diverge et n'est plus un attracteur\n\n";
str=str+"Un carré a 4 rotations : r90, r180=r90*r90, r270=r90*r90*r90 et r360=identité=r90*r90*r90*r90\n";
str=str+"il a aussi 4 symetries : 2 médiatrices des cotés et 2 diagonales. \n\n";
str=str+"Or S, r90*S, r180*S, r270*S conservent chacune un des axes de symetrie\n";
str=str+"il suffit dont de considérer r90 et éventuellement S\n\n";
str=str+"Un polygone regulier de n cotés a n rotations de 360/n et n symetries\n"; 
str=str+"en notation complexe, les rotations se notent : Rot(z) = exp(2*i*pi/n) * z\n";
str=str+"et la symetrie est simplement la conjugaison du complexe : S(z) = z'\n";

break;} 
					case 6:{ // symetric icons
str="une fonction de R->R peut être mise sous la forme d'un polynome en x (un developpement de Taylor)\n";
str=str+"   f(x)=a0 + a1*x + a2*x2 + ... + an*xn\n";
str=str+"une fonction f est invariante pour toutes les transformations p d'un groupe de transformations si f(p(x)) = f(x) \n";
str=str+"elle commute (est équivariante) si f(p(x)) = p(f(x))\n";
str=str+"si f(-x) = f(x) le polynome doit être pair f(x)= a0 +  a2*x2 + ... a2n*x2n\n";
str=str+"si f(-x) = -f(x) le polynome doit être impair : f(x)= (a0 + a2*U + ... + an*U^(n-1)) * x avec U=x^2\n\n";
str=str+"Ce développement s'étend pour une fonction complexe f(z) equivariante de C -> C :\n";
str=str+"     soit f(z)=somme (Ajk * z^j * z'^k)   (z' est le complexe conjugé de z)\n";
str=str+"comme f est invariante pour la symetrie, f(z')=f'(z), donc Ajk=Ajk'\n";
str=str+"comme f est equivariante pour les rotations, f(Rot(z))=Rot(f(z)), f(z)= f(omega*z)/omega avec omega=exp(2*i*pi/n), donc Ajk=0 ou j=k+1 mod n\n";
str=str+"en regroupant les termes, on obtient : f(z)=somme(Pk(z*z') * z^(nk+1)   +   Qk(z*z') * z'^(n(k+1)-1))), P et Q étant des polynomes\n";
str=str+"en appliquant recursivement les trois identités (sur la 2ème partie des 2 premières) :\n";
str=str+"     z^(nk+1)=(z^nk) + z'^nk)*z - (zz')*z'^(nk-1) \n";
str=str+"     z'^(n(k+1)-1)=(z^nk + z'^nk)*z'^(n-1)  -  (zz')^(n-1)*z^(n(k-1)+1)\n";
str=str+"     z^nk + z'^nk=2*real(z^nk)=2*real((z^n)^k)=(z^n+z'^n)^k\n";
str=str+"f peut être mise sous la forme d'un polynome a deux variables U=z*z' et V=z^n + z'^n : \n";
str=str+"     f(z)=P(U,V)*z  + Q(U,V)*z'^(n-1) \n\n";
str=str+"En se restreignant au 1er degré, on obtient ainsi pour la fonction d'itération d'un point\n";
str=str+"     f(z)=(lambda + alpha U(z) + beta V(z)) * z + gamma * z'^(n-1)\n\n";
str=str+"gamma*z'^(n-1) est le terme symetrique de plus petit degré\n";
str=str+"beta*real(z^n)) est le terme de degré supérieur\n";
str=str+"(lambda+alpha*z*z')*z est la logistic map étendue\n";
str=str+"en passant aux coordonnées polaires (r,teta), et en se rappelant que le produit de 2 compexes est (r1*r2,teta1+teta2)\n";
str=str+"on controle facilement que ces transformations symetriques élémentaires respectent F(S(Z)) = S(F(z)) \n\n";
str=str+"Comme variante, on peut ajouter un terme qui n'a pas la symetrie axiale : omega*i*z\n";
str=str+"     F(z)=(lambda + alpha * z * z' + beta * real(z^n) + omega*i)*z + gamma * z'^(n-1))\n";
str=str+"si omega !=0, l'attracteur n'a donc que des rotations et pas d'axes de symetries\n";
str=str+"si omega=0, l'attracteur a des axes de symetries en plus des rotations\n\n";
str=str+"Comme autre variante, on peut ajouter un terme non polynomial introduisant une singuliarité à l'origine : \n";
str=str+"     F(z)=(lambda + alpha * z * z' + beta * real(z^n) + delta * Real((z/|z|)^(n*p))) * |z|) * z + gamma * z'^(n-1)\n";
str=str+"L'attracteur dépend du point initial. Par exemple, l'attracteur obtenu en partant de S(z) est soit le même que celui obtenu en partant de z, et a la symetrie S\n";
str=str+"soit complètement disjoint\n";
 
break;}
					case 7:{ // ifs
str="Etant donné n, le degré de symétrie souhaité, on considère le groupe des transformations affines du plan constitué par les n rotations de 2*i*pi/n\n";
str=str+"et éventuellement la symétrie par rapport à l'axe des x : Sx\n\n";
str=str+"on ajoute une transformation lineaire C variable dont on s'assure qu'elle est contractante c'est à dire qu'elle diminue la distance entre deux points dans un rapport k<1\n";
str=str+"     X=a*x+b*y+e\n";
str=str+"     Y=c*x+d*y+f\n\n";
str=str+"La composition de cette transformation contractante avec chacune des rotations et symetries, toutes de rapport 1, est une application contractante\n";
break;}

	case 8:{ // application linéaire contractante
str="Une application linéaire se définit par\n";
str=str+"     X=a*x+b*y+e\n";
str=str+"     Y=c*x+d*y+f\n\n";
str=str+"La contraction signifie que la distance entre les deux itérés des points (x1,y1) et (x2,y2) est inférieure à la distance des 2 points dans un rapport k<1 :\n";
str=str+"     (a*(x1-x2)+b*(y1-y2))^2  +  (c*(x1-x2)+d(y1-y2))^2 < (x1-x2)^2 + (y1-y2)^2\n";
str=str+"     (a2+c2-1)*(x1-x2)^2  +  (b2+d2-1)*(y1-y2)^2 + 2*(x1-x2)*(y1-y2)*(a*b+c*d) < 0 pour tout x1,x2,y1,y2\n";
str=str+"donc en particulier si x1=x2 ou si y1=y2 on doit avoir a2+c2-1<0 et  b2+d2-1<0\n\n";
str=str+"posons t=(y1-y2)/(x1-x2)\n";
str=str+"     (b2+d2-1)*t^2+2*(a*b+c*d)*t+(a2+c2-1) < 0\n";
str=str+"le sommet de cette parabole, dont le coefficient de t^2 est négatif, est atteint lorsque la dérivée f'(t)=2*(b2+d2-1)*t + 2*(a*b+c*d)=0 \n";
str=str+"il vaut -(a*b+c*d)^2/(b2+d2-1)+(a2+c2-1)\n";
str=str+"et en developpant, on trouve que la parabole est toujours négative si et seulement si\n";
str=str+"     a2+b2+c2+d2<1-(ad-bc)^2\n\n";
break;}

	case 9:{ // théorème du point fixe
str="L'ensemble de ces transformations constitue un IFS (iterated function system) de n+1 transformations contractantes : Ri°C et Sx°C\n";
str=str+"qui converge vers un attracteur borné unique, ne dépendant pas du point de départ. \n\n";
str=str+"L'orbite est bornée car\n";
str=str+"dist(Un-U0) <= dist(Un-Un-1) + ... + dist(U1,U0)\n";
str=str+"            <= k^n*dist(U1,U0) + ...+ dist(U1,U0)\n";
str=str+"            <= (1-k^n)/(1-k) * dist(U1-U0)\n\n";
str=str+"L'attracteur existe car la suite des transformations de l'ensemble U0 converge, vers C tel que f(C)=C :\n";
str=str+"     dist(Un+1,Un)<=k*dist(Un,Un-1) <= k^n * dist(U1,U0) avec k=max(Ki)\n\n";
str=str+"L'attracteur ne dépend pas du point de départ, car, étant donnés deux ensembles (deux points ou deux images) de départ,\n";
str=str+"à chaque itération leurs images ont une distance moindre, de l'ordre de k^n qui tend vers 0, et les orbites des deux points suivent donc la même trajectoire\n\n";
str=str+"L'attracteur est unique car si l'on suppose qu'il y a deux attracteurs E et F, a une distance de Hausdorff ef, leur distance apres execution d'une des transformations est <= k*ef\n";
str=str+"soit k^n*ef après n itérations et cette distance tend donc vers 0 puisque k<1\n\n";
str=str+"     dist( f(E) , f(F) ) = dist(E,F) car ce sont des points fixes\n";
str=str+"     dist( f(E) , f(F) ) <= k*dist(E,F) car c'est contractant\n";
str=str+"donc dist(E,F)<=k*dist(E,F), donc k>=1, qui est absurde donc E=F\n\n";
str=str+"On a les majorations suivantes :\n";
str=str+"    dist (Un,C) <= k^n * dist(U1,U0)\n";
str=str+"et  dist (Un,C) <= k^n/(1-k) * dist(U1,U0)\n\n";
str=str+"L'algorithme le plus simple consiste donc, partant d'un point quelconque, à appliquer au hasard successivement l'une de ces transformations.\n\n";
str=str+"l'ensemble C des images successives du point de départ est borné, c'est l'attracteur de l'IFS\n";
str=str+"par définition, C=T1(C) U T2(C) U .... U Tn(C), et C contient des contractions auto similaires de lui même\n\n";
str=str+"Si on donne des probabilités de choix inégales aux transformations, l'attracteur reste le même mais la fréquence de frappe des pixels change, et donc la colorisation\n\n";

	break;}

	case 10:{ // theoreme du collage
str="Barnsley a démontré que pour tout ensemble E de points (une photo par exemple), il existe un IFS dont l'attracteur C approche cet ensemble\n\n";
str=str+"En effet on peut recouvrir l'ensemble E par un nombre fini de petits disques Di de rayon r et dont les centres sont dans E, et pour chaque disque définir une contraction Ki<1/2 de E dans Di\n";
str=str+"par definition Fi(E) est inclu dans Di\n";
str=str+"F(E)=Union(Fi(E)) est inclus dans union(Di) qui est inclu par definition dans l'enclos à la distance r de E\n";
str=str+"donc distance( E,f(E) ) <= r\n";
str=str+"or distance( E,C )<=distance( E,f(E) )+distance( f(E),C ) \n";
str=str+"comme C est l'attracteur C=f(C) et distance( f(E),C) )=distance( f(E),f(C) ) <= k*distance(E,C) avec k=1/2\n";
str=str+"donc distance(E,C) <= distance( E,f(E) )+distance(E,C)/2\n";
str=str+"et, CQFD, distance(E,C) <= 2*distance(E,f(E))<=2*r\n\n";
str=str+"On a ainsi construit un attracteur C aussi proche de E que l'on souhaite\n\n";

break;}

					case 11:{
str="Pour réaliser un pavage périodique à base carrée on recherche des attracteurs limités au carré unité, et possédant sur ce carré les symetries du carré\n";
str=str+"puis on effectue des translations de ce carré pour rempir le plan.\n";
str=str+"si l'itération d'une coordonnée du point sort du carré, on en retire tout simplement la partie entière\n";
str=str+"soit : f(x + n , y + m) = f(x,y); avec 0 < x,y < 1 et n, m entiers\n";
str=str+"Pour respecter les symetries, il  faut que f(S(z)) = S(f(z)) + (m,n); pour chacune des rotations/symetries du carré ou de l'hexagone\n\n";
str=str+"Dans le cas du pavage hexagonal, à la fin du calcul, avant les translations, on transforme le carré en losange d'angle égal à 60°\n";
break;}
					case 12:{
str="Chaque attracteur se définit par la liste des coefficients des nbvar fonctions correspondant à ses nbvar coordonnées\n"; 
str=str+"Pour les attracteurs polynomiaux, Sprott utilise les caractères ascii pour coder ces coefficients par pas de 0.1( !=-4.4, A=-1.2, a=2, z=4.5 - le 0 est codé par M)\n";
str=str+"la première lettre donne le nombre de variables et le degré des fonctions :\n";
str=str+"Avec pour 2 variables et au deuxième  degré on a un système de 2 fonctions :\n";
str=str+"    Xn+1 = a1 + a2*Xn + a3*Xn*Xn + a4*Xn*Yn + a5*Yn + a6*Yn*Yn\n";
str=str+"    Yn+1 = a7 + a8*Xn + a9*Xn*Xn + a10*Xn*Yn + a11*Yn + a12*Yn*Yn\n\n";
str=str+"En mode \"recherche des attracteurs\", le programme choisit au hasard les coefficients (compris entre -4 et +4) jusqu'à trouver une solution qui ne diverge pas\n\n";
str=str+"Pour les attracteurs non polynomiaux, le programme effectue un recalibrage des coefficients\n\n";
str=str+"Les attracteurs obtenus en inversant X et Y ou en faisant d'autres symétries (X -> -X ou Y->-Y, ...) ou des rotations sont identiques\n";
str=str+"de même pour des homothéties, d'autant que le programme effectue automatiquement un changement d'échelle\n";
str=str+"Si X ne dépend que de Yn-1 et Y que de Xn-1, en fait X dépend de Xn-2 et Y de Yn-2 - avec donc un vrai degré double - l'attracteur a une forme de tissus écossais\n\n";
str=str+"Les systemes hamiltoniens, à 2 variables, préservent des zones qui restent vides - généralement ils se dilatent dans une direction et se contractent dans l'autre\n";
str=str+"par exemple le système : Xn+1 = a1 + a2Xn + a3Xn2 + a4Xn3 + a5Xn4 + a6Xn5 ± Yn et Yn+1 = a22 -± Xn\n";
str=str+"en affichage progressif, ils se remplissent région par région alors que la plupart des attracteurs se remplissent uniformément\n";
break;}

				case 13:{
str="1- Attracteurs standards : coordonnées = f(coordonnées)\n"; 
str=str+"A à D = 1 variable et degré de 2 à 5\n"; 
str=str+"E à H = 2 variable et degré de 2 à 5\n";
str=str+"I à L = 3 variables et degré de 2 à 5\n";
str=str+"M à P = 4 variables et degré de 2 à 5\n\n"; 
str=str+"2- Attracteurs différentiels : dérivée des coordonnées=f(coordonnées)\n";
str=str+"Q à T = différentiel, 3 variables, degré de 2 à 5\n";
str=str+"U à X = differentiel, 4 variables, degré de 2 à 5\n\n"; 
str=str+"3- Attracteurs non polynomiaux sur x et y; z=x2+y2 et w=f(nombre_iteration) = (iter - 1000) / (iter_max - 1000)\n";
str=str+"Y = 4 variables - valeur absolue : Xn+1 = a1 + a2Xn + a3Yn + a4|Xn| + a5|Yn|\n";
str=str+"Z = 4 variables - AND and OR : Xn+1 = a1 + a2Xn + a3Yn + a4Xn AND a5Yn + a6Xn OR a7Yn\n";
str=str+"[ = 4 variables - puissance non entières (et racines) : Xn+1 = a1 + a2Xn + a3Yn + a4|Xn|a5 + a6|Yn|a7\n";
str=str+"\\ = 4 variables - sinus : Xn+1 = a1 + a2Xn + a3Yn + a4sin(a5Xn + a6) + a7sin(a8Yn + a9)\n";
str=str+"] = 4 variables - hamiltonien symetrique : Xn+1 = 10a1 + [Xn + a2sin(a3Yn + a4)]cos t + Yn sin t  et  t = 2 pi / (13 + 10a6)\n";
str=str+"^ = 4 variables - différentiel, sinus : X’ = a1Y et Y’ = a2X + a3X3 + a4X2Y + a5XY2 + a6Y + a7Y3 + a8sin Z\n\n";

str=str+"3- Pour les autres attracteurs, la première lettre est suivie de la valeur décimale exacte des coefficients en ascii, séparés par un espace : \n";
str=str+"# = 2 variables - Field, Rotations sans Symetries, F(z)=(lambda +alpha * z*conjug(z) + beta * real(z^n) + omega*i)*z + gamma * conjug(z^(n-1))\n"; // omega!=0 delta=0
str=str+"$ = 2 variables - Field Rotations et Symetries, F(z)=(lambda +alpha * z * conjug(z) + beta * real(z^n) ) * z + gamma * conjug(z^(n-1))\n"; // omega=0 delta=0
str=str+"% = 2 variables - Rotations, symetries et irrégularités, F(z)=(lambda + alpha * z * conjug(z) + beta * real(z^n) + delta * Real((z/|z|)^(n*p))) * |z|) * z  + gamma * conjug(z^(n-1))\n"; // omega=0 
str=str+"& = 2 variables - Field rotations fractal, F(z)=(lambda + alpha*z*conjug(z) + beta*real(z^n) + omega*i) * z + gamma*conjug(z^(n-1))\n";
str=str+", = 2 variables - Field symmetric fractal, F(z)=(lambda + alpha*z*conjug(z) + beta*real(z^n)) * z + gamma*conjug(z^(n-1))\n";
str=str+"() = 2 variables - Field square quilt, F(z)=(lambda + alpha*z*conjug(z) + beta*real(z^n) + omega*i) * z + gamma*conjug(z^(n-1))\n";
str=str+"*+ = 2 variables - Field hexagonal quilt, F(z)=(lambda + alpha*z*conjug(z) + beta*real(z^n) + omega*i) * z + gamma*conjug(z^(n-1))\n";
str=str+", = 2 variables - quadrup two, log sinus : X = Y -sign(X)*sin(log(abs(a2 X - a3)))*arctg(t*t), Y = a1 - x, t=abs(a3 X - a2)\n";
str=str+"- = 2 variables - Ikeda, sinus : t = 0.4-6.0/(1+(X*X)+(Y*Y)), X = 1+a1*(X*cos(t)-Y*sin(t)), Y = a1*(X*sin(t)+Y*cos(t))\n";
str=str+". = 2 variables - martin, sinus : X = Y - sin(X), Y = a1 - X\n"; 
str=str+"/ = 2 variables - Gingerbread man - valeur absolue : Xn+1 = a1 - Yn + a2|Xn| et Yn+1=Xn\n";
str=str+"0 = 2 variables - Hopalong, X = Y - sign(X)*sqrt(abs(a2*X - a3))  et  Y = a1-X\n";
str=str+"1 = 2 variables - Mira : X = a2 Y + f(X), Y = -X+f(X), f(X)=a1 X - (1-a1) 2 X2/(1+X2)\n";
str=str+"2 = 2 variables - Mira bis : X = a2 Y + f(X), Y = -X+f(X), f(X)=a1 X + (1-a1) 2 X2/(1+X2)\n";
str=str+"3 = 2 variables - Kaneko : X = a1 x+(1-a1)(1-a2 Y2), Y = X\n"; 
str=str+"4 = 2 variables - ham, sinus : t=Math.tan(X), Z2=t*t, W=sin(Y), W2=W*W, X = Z2-W2+a1, Y = a3*Z*W + a2\n";
str=str+"5 = 2 variables - three ply, sinus : X = Y - sign(X)*abs(sin(X)*cos(a2)+a3-X*sin(a1+a2+a3)), Y=a1-X\n";
str=str+"6 = 3 variables - Pickover : X = sin(a1 Y) - Z cos(a2 X), Y = Z sin(a3 X) - cos (a4 Y), Z = sin(X)\n";
str=str+"7 = 3 variables - Pickover bis : X = a1 cos(a4 sin(a1 Y)) - a3 sin(a2 X), Y=a2 sin(a3 cos(a2 X)) - a4 cos(a1 Y), Z=X+Y\n";
str=str+"8 = 2 variables - Peter de Jong : X = sin(a1 Y) - cos (a2 X), Y = sin(a3 X) - cos (a4 Y)\n";
str=str+"9 = 2 variables - Swinson : X = a4 sin(a1 X) - sin(a2 Y), Y = a3 cos(a1 X) + cos(a2 Y)\n";
str=str+": = 2 variables - Clifford : X = sin(a1 Y) + a3 cos(a1 X), Y = sin(a2 X) + a4 cos(a2 Y)\n";
str=str+"; = 1 variable  - logistic map : X = a1 * X * (1-X)\n";
str=str+"< = 2 variables - logistic map symetrique : X=a1 X(1-X2-Y2), Y = a1*Y*(1-X2-Y2)\n\n";
 
//str=str+"- = 2 variables - popcorn, sinus tg :  X' = sin(Y+tan(a1*Y)) et Y' = sin(X+tan(a1*X))\n";
//str=str+"5 = 2 variables - Kantor : X = X cos a1 + (X2-Y) sin a1, Y = x sin a1 - (X2-Y) cos a1\n";

break;}
				case 14:{
str="Le programme affiche l'attracteur en 2 dimensions\n";
str=str+"S'il n'y a qu'une variable, on prend X=Xn-prev et Y=Xn, pour montrer que la condition initiale est vite oubliée\n";
str=str+"les 3ème et 4ème dimensions sont représentées par de la couleur, des ombres, des bandes, des tranches, des stéréogrammes ou des anaglyphes\n";
str=str+"On peut projeter sur un plan, une sphère, un cylindre ou un tore\n";
break;}
 
			case 15:{ 
str="On peut choisir d'avoir un fond blanc ou noir, mais le noir est la meilleur solution lorsque les points ne sont pas denses\n";
str=str+"Le choix de la couleur peut s'effectuer au fur et à mesure des calculs, ou à la fin, en ayant enregistré les données de tous les points :\n";
str=str+"Le noir et blanc est la manière la plus simple d'afficher les points, au fur et à mesure\n";
str=str+"on peut choisir de coloriser le point selon le nombre d'itération effectué par rapport au nombre total prévu, ou selon le logarithme de ce nombre\n\n";
str=str+"Dans une palette de n couleurs, on peut affecter la 1ère couleur (bleu) aux pixels atteints une fois , la deuxième à ceux atteints 2 fois, ....  \n";
str=str+"Mais ainsi, et surtout si le nombre d'itération est très grand, les points atteints plus de n fois sont tous en blanc\n\n"; 
str=str+"En attendant la fin des calculs on peut calculer maxhit, le nombre de frappe du pixel le plus souvent atteint\n";
str=str+"et choisir la couleur selon le quotient par maxhit du nombre de frappe d'un pixel (ou le logarithme de ce nombre)\n"; 
str=str+"Il faut bien remarquer que de nombreux points différents peuvent exciter le même pixel\n";
str=str+"la gamme de couleur va de bleu pour les petits nombres à vert, rose, rouge, jaune et blanc pour les plus gros nombres\n";
str=str+"en utilisant la visualisation des itérations d'un point, on constate que le point est plus souvent dans les zones jaunes que dans les zones bleues\n\n"; 
str=str+"les colorisations faites au fur et à mesure sont faussées dans le cas d'ajouts de cycles, puisqu'on ne recalcule pas la couleur des premiers points\n";
str=str+"et que les derniers points ajoutés sont jaunes (dans le cas de la colorisation par nombre d'itération)\n";
str=str+"le traveling du nombre d'itérations n'a pas cet inconvénient puisque on recalcule tout à chaque étape\n";
str=str+"Les éventuels points fixes ou périodiques s'affichent comme des points très souvent atteints, en blanc (ou en jaune)\n";
break;}

				case 16:{
str="Un attracteur étant affiché on peut modifier les coefficients, dont le détail est visible dans \"détail des coefficients\"\n";
str=str+"choisir le numéro du coefficient à modifier (x0 et y0 sont deux coefficients supplémentaires)\n";
str=str+"utiliser les boutons incrémenter ou décrémenter\n";
str=str+"Le bouton traveling automatique entraine un enchainement de modifications du coefficient choisi\n";
str=str+"changer le sens du traveling en reappuyant sur ce bouton lorsque l'attracteur disparait\n";
str=str+"Le pas de mofification est 0.005 pour les coefficients des fonctions comme pour x0 et y0\n\n";
str=str+"On peut aussi effectuer un traveling sur le nombre maximum d'itérations\n";
str=str+"dans tous les cas de traveling, la valeur du coefficient est visible dans la zone d'affichage des paramètres\n\n";
break;}
	 				default:{}
	 				} 
	 			affiche(str,reponse);
	 			indexhelp++; 
	 			if (indexhelp==tabhelp.length) {indexhelp=0;}
	 			}
	 		} // for
	 } // while
} // help 

public void mmaj()
{
if (pan.numattract!=0)
	{
	str="<html>"+pan.fullnomattractgroupe+"<br>"+pan.attracteurs[pan.numattract][1]+"<br>"
		+"dimension="+pan.attracteurs[pan.numattract][4]+" "
		+"Lyapunov="+pan.attracteurs[pan.numattract][5]+"</html>";
	}
else
	{
	str="<html>"+pan.nomtypeattract[pan.type_attract]+" :"+pan.nbvar+" variables</html>";
	}
lpas.setText(str);
lpas.repaint();
bsearch.setText("<html>Recherche<br>d'attracteurs<br>nbvar="+pan.NBVAR+" type="+pan.TYPE_ATTRACT+"<br>"+pan.nomtypeattract[pan.TYPE_ATTRACT]+"</html>");
bsearch.repaint();

str="<html>"
//	+"degré="+pan.degre
//	+"<br>nb var="+pan.nbvar
//	+"<br>type_attract="+pan.type_attract
	+"<br>Lyapunov="+pan.lyapunov
	+"<br>dim="+pan.fractal_dim
	+"<br>delta="+pan.stepsize
	+"<br>max="+pan.iter_max
	+"<br>cycle="+pan.iter_cycle
	+"<br>dcoeff="+pan.pastravel_coeff
	+"<br>diter="+pan.pastravel_iter
	+"<br>x0 y0="+pan.x0+" "+pan.y0; 
if (pan.modifcoeff<=pan.index_coeff)
	{str=str+"<br>a"+pan.modifcoeff+"="+pan.A[pan.modifcoeff];}
//	+"<br>3°dim="+pan.nom3emedim[pan.num3emedim]
//	+"<br>4°dim="+pan.nom4emedim[pan.num4emedim]
//	+"<br>projection="+pan.nomprojection[pan.numprojection]
	str=str+"<br></html>";
lrac.setText(str);
lrac.repaint();
}

public void maj()
{ 
mmaj(); 
if (pan.flag==false) {
//	System.out.println("repaint"); 
	pan.anti_intempestif=5215;
	pan.repaint();}
}

public fenetreattract()
						{
/* applet */
  this.setTitle("Attracteurs étranges");
  Dimension dime = Toolkit.getDefaultToolkit().getScreenSize();
  int theight = (int)dime.getHeight()-50;
	int twidth  = (int)dime.getWidth()-50;
  this.setSize(twidth, theight);
  this.setLocationRelativeTo(null);                           
  this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	this.setUndecorated(false); 
 
							liste= new ArrayList <String >() ;   		
            	for (int i=1;i<pan.attracteurs.length;i++)
            		{
            		if (liste.contains(pan.attracteurs[i][0]+" "+pan.attracteurs[i][2])==false)
            			{liste.add(pan.attracteurs[i][0]+" "+pan.attracteurs[i][2]);} 
            		} 
            	pan.nomgroupe=new String[liste.size()];
            	pan.fullnomgroupe=new String[liste.size()];
            	for (int i=0;i<liste.size();i++) 
            		{pan.nomgroupe[i]=liste.get(i);
            		String detail="";
            		for (int j=0;j<pan.lettre_groupe.length;j++)
            			{ if (pan.nomgroupe[i].charAt(pan.nomgroupe[i].length()-1) == pan.lettre_groupe[j][0].charAt(0))
            					{detail=pan.lettre_groupe[j][1];}
            			}
            		pan.fullnomgroupe[i]=pan.nomgroupe[i]+" : "+detail;
            		}
          
            	pan.nomattractgroupe=pan.nomgroupe[0];
            	pan.fullnomattractgroupe=pan.fullnomgroupe[0];
            	listeattractg();							
           
            this.setLayout(new BorderLayout()); 
           
						pan.haut=theight-150;
						pan.longueur=twidth-500-160-50;  //1320; 
						if (pan.haut>1200) {pan.haut=1200;};
						if (pan.longueur>1200) {pan.longueur=1200;};       
            menu.setPreferredSize(new Dimension(pan.longueur+160, 70)); 
            menugauche.setPreferredSize(new Dimension(160, pan.haut)); 
            menudroite.setPreferredSize(new Dimension(160, pan.haut));
            zonedroite.setPreferredSize(new Dimension(500, pan.haut));
    				pan.setPreferredSize(new Dimension(pan.longueur, pan.haut));
          
            lpas.setPreferredSize(new Dimension(260, 70)); //270
            lvide.setPreferredSize(new Dimension(10, 60)); 
             
            bsearch.setPreferredSize(new Dimension(140, 90));
            bdetail.setPreferredSize(dim);
						bcoloration.setPreferredSize(dim);
						bfond.setPreferredSize(dim);
           
	      		bcyclenext.setPreferredSize(dim);
						brapide.setPreferredSize(dim);
						bmanuel.setPreferredSize(dim);

						bnextattract.setPreferredSize(dim);
						bnextgroupe.setPreferredSize(dim);
						bprojection.setPreferredSize(dim);
						b4emedim.setPreferredSize(dim);
						b3emedim.setPreferredSize(dim);
						bcoeff.setPreferredSize(dim);
						baccelerer.setPreferredSize(dim);
						bralentir.setPreferredSize(dim);
						btravel.setPreferredSize(dim);
						bdelta.setPreferredSize(dim);
						bnmax.setPreferredSize(dim);
						bpasmax.setPreferredSize(dim);
						bNBVAR.setPreferredSize(dim);
						btype_attract.setPreferredSize(dim);
						bhamiltonien.setPreferredSize(dim);
						bperiode.setPreferredSize(dim);
						bchoix.setPreferredSize(dim);
						bmodifp.setPreferredSize(dim);
						bmodifm.setPreferredSize(dim);
						btravel_coeff.setPreferredSize(dim);
						btravel_iter.setPreferredSize(dim);
						bhelp.setPreferredSize(dim);	
						bzoomin.setPreferredSize(dim);
						bzoomout.setPreferredSize(dim);
						lrac.setPreferredSize(new Dimension(200, 160));					

						bsearch.addActionListener(new fsearch());
						bdetail.addActionListener(new fdetail());
						bdelta.addActionListener(new fdelta());
						bnmax.addActionListener(new fnmax());
						bpasmax.addActionListener(new fpasmax());
						bNBVAR.addActionListener(new fNBVAR());
						btype_attract.addActionListener(new ftype_attract());
						bhamiltonien.addActionListener(new fhamiltonien());
						bchoix.addActionListener(new fchoix());
						bperiode.addActionListener(new fperiode());
						btravel.addActionListener(new ftravel());
						bcoeff.addActionListener(new fcoeff());
						baccelerer.addActionListener(new faccelerer());
						bralentir.addActionListener(new fralentir());
						bmodifp.addActionListener(new fmodifp());
						bmodifm.addActionListener(new fmodifm());
						btravel_coeff.addActionListener(new ftravel_coeff());
						btravel_iter.addActionListener(new ftravel_iter());
						bcyclenext.addActionListener(new fcyclenext());
						brapide.addActionListener(new frapide()); 
						bmanuel.addActionListener(new fmanuel());
						bcoloration.addActionListener(new fcoloration());
						bfond.addActionListener(new ffond());
						bzoomin.addActionListener(new fzoomin());
						bzoomout.addActionListener(new fzoomout());
					
						bnextattract.addActionListener(new fnextattract());
						bnextgroupe.addActionListener(new fnextgroup());
						bprojection.addActionListener(new fprojection());	
						b4emedim.addActionListener(new f4emedim());	
						b3emedim.addActionListener(new f3emedim());	
						bhelp.addActionListener(new fhelp());
 
						//menu.add(lpas);
            
            menugauche.add(bmanuel);
            menugauche.add(bcyclenext);
            menugauche.add(bsearch);
            menugauche.add(bhamiltonien);
            //menugauche.add(lrac);
            menugauche.add(bnmax);
            menugauche.add(bpasmax);
            menugauche.add(bdelta);
            menugauche.add(btravel);
            menugauche.add(bNBVAR);
            menugauche.add(btype_attract);
            
            menudroite.add(bdetail);
            menudroite.add(bchoix);
            menudroite.add(bcoeff);
            menudroite.add(baccelerer);
            menudroite.add(bralentir);
            menudroite.add(bmodifp);
            menudroite.add(bmodifm);
            menudroite.add(btravel_coeff);
            menudroite.add(btravel_iter);
            
            menu.add(bperiode);
            menu.add(brapide);  
            menu.add(bnextattract); 
            menu.add(bnextgroupe); 
            menu.add(lvide);
            menu.add(bprojection);
            menu.add(b4emedim);
            menu.add(b3emedim);
            menu.add(bcoloration);
            menu.add(bfond);
            menu.add(bzoomin);
            menu.add(bzoomout);
            menu.add(bhelp);
         
            this.add(menu, BorderLayout.NORTH);
            this.add(menugauche,BorderLayout.WEST);
            this.add(zonedroite,BorderLayout.EAST);
            
            zonedroite.add(lpas,BorderLayout.WEST);
            zonedroite.add(lrac,BorderLayout.WEST);
            zonedroite.add(menudroite,BorderLayout.EAST);
            
            this.add(pan, BorderLayout.CENTER);
  
      			//	this.setContentPane(container);
            this.setVisible(true);
             			
 						t=new Timer();
 						t.schedule(new timetask(),500,300);
      			str="bbbb";
      			mmaj();
        		}
        class timetask extends TimerTask 
        	{
        	public void run() 
        		{
        		mmaj();
        		if (pan.flag==false)
        			{ 
        			if (pan.sens != 0)
        					{
        					if (pan.travel==0)
        						{
        						if (pan.modifcoeff<=pan.index_coeff)
        							{pan.A[pan.modifcoeff]=pan.A[pan.modifcoeff]+pan.sens*pan.pastravel_coeff;
        						
        							if ((pan.type_attract<10) || (pan.type_attract!=16))
        								{
                				if (pan.A[pan.modifcoeff]<-4.4) {pan.sens=-1;}
                				if (pan.A[pan.modifcoeff]>4.4) {pan.sens=-1;}
                				}
                			}
                		if (pan.modifcoeff==pan.index_coeff+1)
                			{pan.x0=pan.x0+pan.sens*pan.pastravel_coeff;}
                		if (pan.modifcoeff==pan.index_coeff+2)
                			{pan.y0=pan.y0+pan.sens*pan.pastravel_coeff;}
                		}
                	else
                		{pan.iter_max=pan.iter_max+pan.sens*pan.pastravel_iter;
                		if (pan.iter_max<pan.iter_search) {pan.iter_max=50000; pan.sens=0;}
                		}
                			
                	pan.act=1;
                	pan.rapide=true; /* redo */
                	maj();
                	}

        			if ((pan.rapide==false) && (pan.manuel==false) && (pan.nbiter<pan.iter_max))
								{pan.act=2;	/* iter */
								maj();
								}
							} 
         		}
        }
 
        class fsearch implements ActionListener
        	{
                @Override 
                public void actionPerformed(ActionEvent e) 
                	{ 
                	pan.sens=0;
                	pan.hamiltonien=false;
        					pan.search_mode=true;
        					pan.act=0;	/* all */
        					maj();
                	} 
        	}
       class fhamiltonien implements ActionListener
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{	
                	pan.sens=0;								
									pan.hamiltonien=true;
									pan.NBVAR=2;
									pan.TYPE_ATTRACT=0;
									pan.search_mode=true;
        					pan.act=0;	/* all */
									maj(); 
                	}
        	}          
   
        class fcyclenext implements ActionListener 
        	{ 
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
                	/*pan.manuel=true;
                	pan.rapide=false; */
                	pan.iter_max=pan.iter_max+pan.iter_cycle;
             			pan.act=2;	/* iter */
             			maj();
                	}
        	} 
       	class fmanuel implements ActionListener 
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
                	if (pan.manuel==true)
                		{
                		pan.manuel=false;
                		bmanuel.setText("<html>Affichage<br>par cycles<br>Manuel</html>");
                		}
                	else
                		{
                		pan.manuel=true;
             				bmanuel.setText("<html>Affichage<br>par cycles<br>Automatique</html>");
             				}
             			pan.act=1;	/* redo */
             			maj();
                	} 
        	} 
        class frapide implements ActionListener 
        	{ 
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
                	pan.sens=0;
                	if (pan.rapide==true)
                		{
                		pan.rapide=false; 
                		brapide.setText("<html>Affichage<br>rapide</html>");
                		}
                	else
                		{
                		pan.rapide=true;
             				brapide.setText("<html>Affichage<br>progressif</html>");
             				}
             		
             			pan.search_mode=false;
             			pan.act=1;	/* redo */
             			maj();
                	}
        	}
      	class fdetail implements ActionListener
        	{
                @Override
                public void actionPerformed(ActionEvent ev) 
                	{ 
                  str="<html>";
                  if (pan.numattract>0)
                  	{str=str+pan.attracteurs[pan.numattract][0]+"<br>";
                  	str=str+pan.attracteurs[pan.numattract][2]+"<br>";
                  	str=str+pan.fullnomattractgroupe+"<br>";
                  	str=str+pan.attracteurs[pan.numattract][1]+"<br>";
                  	if (pan.attracteurs[pan.numattract][4] != "x")
                  		{str=str+"Dimension fractale="+pan.attracteurs[pan.numattract][4]+"<br>";
                  		str=str+"Lyapunov="+pan.attracteurs[pan.numattract][5]+"<br>";}
										str=str+pan.attracteurs[pan.numattract][3]+"<br><br>";} 
									else
										{str=str+"Dimension fractale="+pan.fractal_dim+"<br>";
                  	str=str+"Lyapunov="+pan.lyapunov+"<br><br>";}
if (pan.type_attract<2)
{ 
int index_coeff = 1;
char[] XY=new char[5];
String sign;		
	XY[1] = 'X';
	XY[2] = 'Y';
	XY[3] = 'Z';
	XY[4] = 'W';
	for (int I = 1; I <= pan.nbvar; I++) {
		if (pan.type_attract == 1)
			{str=str+"<br>"+XY[I]+"\' = ";}
		else
			{str=str+"<br>"+XY[I]+" = ";}
		if (Math.abs(pan.A[index_coeff]) >0.0001) { str=str+ pan.A[index_coeff];}
		index_coeff = index_coeff + 1;
		for (int I1 = 1; I1 <= pan.nbvar; I1++) {
			sign="+"; if (pan.A[index_coeff]<0) {sign="";}
			if (Math.abs(pan.A[index_coeff]) >0.0001) { str=str + sign +pan.A[index_coeff] + "*" + XY[I1];}
			index_coeff = index_coeff + 1;
			for (int I2 = I1; I2 <= pan.nbvar; I2++) {
				sign="+"; if (pan.A[index_coeff]<0) {sign="";};
				if (Math.abs(pan.A[index_coeff]) >0.0001) { str=str + sign+pan.A[index_coeff] +"*" + XY[I1] + "*" + XY[I2];}
				index_coeff = index_coeff + 1;
				for (int I3 = I2; (pan.degre > 2) && (I3 <= pan.nbvar); I3++) {
					sign="+"; if (pan.A[index_coeff]<0) {sign="";}
					if (Math.abs(pan.A[index_coeff]) >0.0001) { str=str + sign+pan.A[index_coeff] +"*" +XY[I1] +"*" +XY[I2] +"*" +XY[I3];}
			 		index_coeff = index_coeff + 1;
					for (int I4 = I3; (pan.degre > 3) && (I4 <= pan.nbvar); I4++) { 
						sign="+"; if (pan.A[index_coeff]<0) {sign="";}
						if (Math.abs(pan.A[index_coeff]) >0.0001) { str=str + sign+pan.A[index_coeff] +"*" +XY[I1] +"*" +XY[I2] +"*" +XY[I3] +"*" +XY[I4];}
						index_coeff = index_coeff + 1;
						for (int I5 = I4; (pan.degre > 4) && (I5 <= pan.nbvar); I5++) {
							sign="+"; if (pan.A[index_coeff]<0) {sign="";}
							if (Math.abs(pan.A[index_coeff]) >0.0001) { str=str + sign+pan.A[index_coeff] +"*" +XY[I1] +"*" +XY[I2] +"*" +XY[I3] +"*" +XY[I4] +"*" +XY[I5];}
							index_coeff = index_coeff + 1;
							}
						}
					}
				}
			}
		}	
	}	
else
	{
	if (pan.type_attract==2)	// Y
		{
		str=str+"X = "+ pan.A[1]+"+" + pan.A[2]+"*X+" + pan.A[3]+"*Y+" + pan.A[4]+"*|X|+" + pan.A[5]+"*|Y|<br>";
		str=str+"Y = "+ pan.A[6]+"+" + pan.A[7]+"*X+" + pan.A[8]+"*Y+" + pan.A[9]+"*|X|+" + pan.A[10]+"*|Y|<br>";
		str=str+"Z = X*X + Y*Y<br>";
		}
	if (pan.type_attract==3)	// Z
		{
		str=str+"X = "+ pan.A[1]+"+" + pan.A[2]+"*X+" + pan.A[3]+"*Y+" + pan.A[4]+"*X AND "+pan.A[5]+"*Y+" + pan.A[6]+"*X OR "+pan.A[7]+"*Y<br>";
		str=str+"Y = "+ pan.A[8]+"+" + pan.A[9]+"*X+" + pan.A[10]+"*Y+" + pan.A[11]+"*X AND "+pan.A[12]+"*Y+" + pan.A[13]+"*X OR "+pan.A[14]+"*Y<br>";
		str=str+"Z = X*X + Y*Y<br>";
		}
	if (pan.type_attract==4)	// [
		{
		str=str+"X = "+ pan.A[1]+"+" + pan.A[2]+"*X+" + pan.A[3]+"*Y+" + pan.A[4]+"*|X|^"+pan.A[5]+"+" + pan.A[6]+"*|Y|^"+pan.A[7]+"<br>";
		str=str+"Y = "+ pan.A[8]+"+" + pan.A[9]+"*X+" + pan.A[10]+"*Y+" + pan.A[11]+"*|X|^"+pan.A[12]+"+" + pan.A[13]+"*|Y|^"+pan.A[14]+"<br>";
		str=str+"Z = X*X + Y*Y<br>";
		}
	if (pan.type_attract==5)	// \\
		{
		str=str+"X = "+ pan.A[1]+"+" + pan.A[2]+"*X+" + pan.A[3]+"*Y+" + pan.A[4]+"*sin("+pan.A[5]+"*X+" + pan.A[6]+")+" + pan.A[7]+"*sin("+pan.A[8]+"*Y+" + pan.A[9]+")<br>";
		str=str+"Y = "+ pan.A[10]+"+" + pan.A[11]+"*X+" + pan.A[12]+"*Y+" + pan.A[13]+"*sin("+pan.A[14]+"*X+" + pan.A[15]+")+" + pan.A[16]+"*sin("+pan.A[17]+"*Y+" + pan.A[18]+")<br>";
		str=str+"Z = X*X + Y*Y<br>";
		} 
	if (pan.type_attract==6)	// ]
		{
		str=str+"X = 10*"+ pan.A[1] +" + [X + "+pan.A[2]+"*sin("+pan.A[3]+"*Y+"+pan.A[4]+")]*cos[2pi/(13+10*"+pan.A[6]+")] + Y*sin[2pi/(13+10*"+pan.A[6]+")]<br>";
		str=str+"Y = 10*"+ pan.A[5] +" - [X + "+pan.A[2]+"*sin("+pan.A[3]+"*Y+"+pan.A[4]+")]*sin[2pi/(13+10*"+pan.A[6]+")] + Y*cos[2pi/(13+10*"+pan.A[6]+")]<br>";
		str=str+"Z = X*X + Y*Y<br>";
		}
	if (pan.type_attract==7)	// ^ 
		{
		str=str+"X = X + 0.1*"+ pan.A[1]+"*Y<br>";
		str=str+"Y = Y + 0.1*(" +pan.A[2]+"*X+" + pan.A[3]+" X^3+" + pan.A[4]+ "*X^2Y+" + pan.A[5]+"*XY^2+" + pan.A[6]+"*Y+" + pan.A[7]+"*Y^3+" + pan.A[8]+"*sin Z<br>";
		str=str+"Z = [Z + 0.1*(" +pan.A[9]+" + 1.3)] mod 2pi<br>";
		} 
	if (pan.type_attract==10) // # field rotation omega!=0 delta=0
		{str=str+"F(z)=(lambda +alpha * z*conjug(z) + beta * real(z^n) + omega*i)*z + gamma * conjug(z^(n-1))<br>";}
	if (pan.type_attract==11) // # field rotation et symetrie omega=0 delta=0
		{str=str+"F(z)=(lambda +alpha * z * conjug(z) + beta * real(z^n) ) * z + gamma * conjug(z^(n-1))<br>";}
	if (pan.type_attract==12) // # field irregularite omega=0 delta!=0
		{str=str+"F(z)=(lambda + alpha * z * conjug(z) + beta * real(z^n) + delta * Real((z/|z|)^(n*p))) * |z|) * z + gamma * conjug(z^(n-1))<br>";}
	if (pan.type_attract==13) // # field fractal ifs rotations
		{str=str+"F(z)=(lambda +alpha*z*conjug(z)+beta*real(z^n)+omega*i)*z+gamma*conjug(z^(n-1))<br>";}
	if (pan.type_attract==14) // # field fractal ifs rotations et symetrie
		{str=str+"F(z)=(lambda +alpha*z*conjug(z)+beta*real(z^n)+omega*i)*z+gamma*conjug(z^(n-1))<br>";}
	if (pan.type_attract==15) // # quilt carré
		{str=str+"F(z)=(lambda +alpha*z*conjug(z)+beta*real(z^n)+omega*i)*z+gamma*conjug(z^(n-1))<br>";}
	if (pan.type_attract==17) // # quilt hexa
		{str=str+"F(z)=(lambda +alpha*z*conjug(z)+beta*real(z^n)+omega*i)*z+gamma*conjug(z^(n-1))<br>";}
	if (pan.type_attract==19)	// , quadrup two
		{str=str+"X = Y -sign(X)*sin(log(abs(a2 X - a3)))*arctg(t*t)<br>Y = a1 - x<br>t=abs(a3 X - a2)<br>";}
	if (pan.type_attract==20)	// ) Ikeda 
		{str=str+"t = 0.4-6.0/(1+(X*X)+(Y*Y))<br>X = 1+a1*(X*cos(t)-Y*sin(t))<br>Y = a1*(X*sin(t)+Y*cos(t))<br>";}
	if (pan.type_attract==21)	// . martin
		{str=str+"X = Y - sin(X)<br>Y = a1 - X<br>";}		
	if (pan.type_attract==22)	//  / gingerbread man 
		{str=str+"X = a1 - Y+ a2 |X|<br>"; 
		str=str+"Y = X<br>";} 
	if (pan.type_attract==23)	// 0 martin hopalong 
		{str=str+"X = Y - sign(X)*sqrt(abs(a2*X - a3))<br>";
		str=str+"Y = a1-X<br>";} 
	if (pan.type_attract==24)	// 1 mira
		{str=str+"X = a2 Y + f(X)<br>"; 
		str=str+"Y = -X+f(X)<br>"; 
		str=str+"f(X)=a1 X - 2*(1-a1)*X2/(1+X2)<br>";
		str=str+"-1'<'a1'<'1 et 0.9'<'a2'<'=1 ";}
	if (pan.type_attract==25)	// 2 gumoski-mira
		{str=str+"X = a2 Y + f(X)<br>"; 
		str=str+"Y = -X+f(X)<br>";
		str=str+"f(X)=a1 X + (1-a1) 2 X2/(1+X2)<br>";}
	if (pan.type_attract==26)	// 3 kaneko
		{str=str+"X = a1 x+(1-a1)(1-a2 Y2)<br>";
		str=str+"Y = X<br>";}
if (pan.type_attract==27)	// * Ham
		{str=str+"t=Math.tan(X)<br>Z2=t*t<br>W=sin(Y)<br>W2=W*W<br>X = Z2-W2+a1<br>Y = a3*Z*W + a2<br>";}
	if (pan.type_attract==28)	// + three ply
		{str=str+"X = Y - sign(X)*abs(sin(X)*cos(a2)+a3-X*sin(a1+a2+a3))<br>Y=a1-X<br>";}
	if (pan.type_attract==29)	// 6 pickover
		{str=str+"X = sin(a1 Y) - Z cos(a2 X)<br>";
		str=str+"Y = Z sin(a3 X) - cos (a4 Y)<br>";
		str=str+"Z = sin(X)<br>";}
	if (pan.type_attract==30)	// 7 pickover bis
		{str=str+"X = a1 cos(a4 sin(a1 Y)) - a3 sin(a2 X)<br>";
		str=str+"Y = a2 sin(a3 cos(a2 X)) - a4 cos(a1 Y)<br>";
		str=str+"Z=X+Y<br>";} 
	if (pan.type_attract==31)	// 8 peter de jong
		{str=str+"X = sin(a1 Y) - cos (a2 X)<br>";
		str=str+"Y = sin(a3 X) - cos (a4 Y)<br>";}
	if (pan.type_attract==32)	// 9 swinson
		{str=str+"X = a4 sin(a1 X) - sin(a2 Y)<br>";
		str=str+"Y = a3 cos(a1 X) + cos(a2 Y)<br>";}
	if (pan.type_attract==33)	// : clifford
		{str=str+"X = sin(a1 Y) + a3 cos(a1 X)<br>";
		str=str+"Y = sin(a2 X) + a4 cos(a2 Y)<br>";}
	if (pan.type_attract==34)	// ; logistic map 1d
		{str=str+"X = a1 * X * (1-X)<br>";}
	if (pan.type_attract==35)	// < logistic map symetrique 2D
		{str=str+"X = a1 * X * (1-X*X-Y*Y)<br>";
		str=str+"Y = a1 * Y * (1-X*X-Y*Y)<br>";}
	if (pan.type_attract==39)	// - popcorn
		{str=str+"X' = sin(Y+tan(a1*Y))<br>Y' = sin(X+tan(a1*X))<br>";}
	if (pan.type_attract==36)	// 5 pickover tesselation
		{str=str+"X = X cos a1 + (X2-Y) sin a1<br>";
		str=str+"Y = x sin a1 - (X2-Y) cos a1<br>";}

	if (pan.type_attract<10)	{str=str+"w = (iter - 1000) / (iter_max - 1000)<br>";}
	}	
									str=str+"<br><br>Liste des coefficients non nuls :<br>";
									for (int i=1;i<=pan.index_coeff;i++)
										{
										if (Math.abs(pan.A[i])>0.0001)
											{str=str+"a"+i+"="+pan.A[i]+"<br>";}
										}	
									str=str+"Coefficient de traveling : " +pan.modifcoeff+"<br>";		
									str=str+"x0="+pan.x0+" y0="+pan.y0+"<br>";	
								
									str=str+"</html>";
									affiche(str,"détail de l attracteur");
                	}

        	}
    		class fhelp implements ActionListener
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{ 
                       help();
                	}

        	} 
   
      	class fprojection implements ActionListener
        	{
                @Override 
                public void actionPerformed(ActionEvent e) 
                	{
                	int i=pan.numprojection+1;
 									if (i==pan.nomprojection.length) {i=0;}
									String  reponse = (String) JOptionPane.showInputDialog
	    							(null,
	     							"Choisir un type de projection", 
	     							"Boutons personnalises", 
	     							JOptionPane.QUESTION_MESSAGE,
	     							null,
	     							pan.nomprojection, 
	     							pan.nomprojection[i]);
	     						for (i=0;i<pan.nomprojection.length;i++)
	     							{if (reponse.equals(pan.nomprojection[i]))
	     								{
	     								pan.numprojection=i;
	     								bprojection.setText("<html>Projection<br>:"+reponse+"</html>");
	     								bprojection.repaint();
	     								}
	     							} 
	     						pan.act=1;	/* redo */
     							maj();
	     						}
	     		}
	     	class f4emedim implements ActionListener
        	{
                @Override 
                public void actionPerformed(ActionEvent e) 
                	{
                	int i=pan.num4emedim+1;
 									if (i==pan.nom4emedim.length) {i=0;}
									String  reponse = (String) JOptionPane.showInputDialog
	    							(null,
	     							"Choisir un mode pour la 4eme dimension", 
	     							"Boutons personnalises", 
	     							JOptionPane.QUESTION_MESSAGE,
	     							null,
	     							pan.nom4emedim, 
	     							pan.nom4emedim[i]);
	     						for (i=0;i<pan.nom4emedim.length;i++)
	     							{if (reponse.equals(pan.nom4emedim[i]))
	     								{
	     								pan.num4emedim=i;
	     								b4emedim.setText("<html>4eme dimension<br>:"+reponse+"</html>");
	     								b4emedim.repaint();
	     								}
	     							} 
	     						pan.act=1;	/* redo */
     							maj();
	     						}
	     		}
	    class f3emedim implements ActionListener
        	{
                @Override 
                public void actionPerformed(ActionEvent e) 
                	{
                	int i=pan.num3emedim+1;
 									if (i==pan.nom3emedim.length) {i=0;}
									String  reponse = (String) JOptionPane.showInputDialog
	    							(null,
	     							"Choisir un mode pour la 3eme dimension", 
	     							"Boutons personnalises", 
	     							JOptionPane.QUESTION_MESSAGE,
	     							null,
	     							pan.nom3emedim, 
	     							pan.nom3emedim[i]);
	     						for (i=0;i<pan.nom3emedim.length;i++)
	     							{if (reponse.equals(pan.nom3emedim[i]))
	     								{
	     								pan.num3emedim=i;
	     								b3emedim.setText("<html>3eme dimension<br>:"+reponse+"</html>");
	     								b3emedim.repaint();
	     								}
	     							} 	     						
	     						pan.act=1; /* redo */
     							maj();
	     						}
	     		}
     	class fnextgroup implements ActionListener
        	{
                @Override 
                public void actionPerformed(ActionEvent e) 
                	{
                	pan.sens=0;
                	int i=pan.numgroupe+1;
 									if (i==pan.nomgroupe.length) {i=0;}
									String  reponse = (String) JOptionPane.showInputDialog
	    							(null,
	     							"Choisir un groupe d'attracteurs à analyser", 
	     							"Boutons personnalises", 
	     							JOptionPane.QUESTION_MESSAGE,
	     							null,
	     							pan.fullnomgroupe, 
	     							pan.fullnomgroupe[i]);
 
	     						if (reponse != null)
	     							{
	     							for (i=0;i<pan.nomgroupe.length;i++)
	     								{if (reponse.equals(pan.fullnomgroupe[i]))
	     									{
	     									pan.fullnomattractgroupe=reponse;
	     									pan.nomattractgroupe=pan.nomgroupe[i];
	     									pan.numgroupe=i;
	     									pan.numattractg=0;
	     									}
	     								}
	     							} 
	     						listeattractg();
	     						for (i=0;i<pan.attracteurs.length;i++)
	     							{
	     							if (pan.nomattractg[0].equals(pan.attracteurs[i][1]+" "+pan.attracteurs[i][2]))
	     								{
	     								pan.numattract=i; 
                      } 
                     }
	     						initattract();
	     						pan.search_mode=false;
	     						pan.act=0;	/* all */
	     						maj();
	     						}
	     		}
       	class fnextattract implements ActionListener
        	{ 
                @Override
                public void actionPerformed(ActionEvent e) 
                	{ 
                	pan.sens=0;
                	int i=pan.numattractg+1;
 									if (i==pan.nomattractg.length) 
 										{i=pan.numgroupe+1;
 										if (i==pan.nomgroupe.length) {i=0;}
 										pan.numgroupe=i; 
 										pan.nomattractgroupe=pan.nomgroupe[i];
 										pan.fullnomattractgroupe=pan.fullnomgroupe[i]; 
 										listeattractg();
 										i=0;}
 										//System.out.println(" bug1 "+i);
 										//System.out.println(" bug2 "+pan.nomattractg[i]);
									String  reponse = (String) JOptionPane.showInputDialog
	    							(null,
	     							"Choisir un attracteur à analyser dans le groupe "+pan.nomattractgroupe, 
	     							"Boutons personnalises", 
	     							JOptionPane.QUESTION_MESSAGE,
	     							null,
	     							pan.nomattractg,
	     							pan.nomattractg[i]); 
	 								if (reponse != null)
	 									{ 
	     							for (i=0;i<pan.nomattractg.length;i++)
	     								if (reponse.equals(pan.nomattractg[i]))
	     									{ 
	     									pan.numattractg=i;
	     									}	
	     							for (i=0;i<pan.attracteurs.length;i++)
	     								{
	     								if (reponse.equals(pan.attracteurs[i][1]+" "+pan.attracteurs[i][2]))
	     									{
	     									pan.numattract=i;
	     									} 
                      }
                     }
									initattract();
									pan.search_mode=false;
									pan.act=0;	/* all */
									maj();
                	}
        	} 
      class fcoloration implements ActionListener
        {
                @Override
                public void actionPerformed(ActionEvent e) 
                	{ 
                	int i=pan.coloration+1; 
 									if (i==pan.nomcoloration.length) {i=0;}
									String  reponse = (String) JOptionPane.showInputDialog
	     							(null, 
     							"Choisir un mode de coloration pour 1 et 2 dim", 
	     							"Boutons personnalises",
      							JOptionPane.QUESTION_MESSAGE, 
	     							null, 
	     							pan.nomcoloration, 
	     							pan.nomcoloration[i]);
	     						if (reponse != null)
	     							{for (i=0;i<pan.nomcoloration.length;i++)
	     								if (reponse.equals(pan.nomcoloration[i]))
	     									{ 
	     									pan.coloration=i;	     								
	     									} 
	     							pan.act=1;	/* redo */
										maj(); 
										}
                	}
        	} 
       class ffond implements ActionListener
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
                	int c=pan.couleur_fond;
                	pan.couleur_fond=pan.couleur_not_fond;
                	pan.couleur_not_fond=c;
                	pan.COLR[0]=pan.couleur_not_fond;
          
                	if (pan.fond_blanc==false)
                		{pan.fond_blanc=true;}
                	else
                		{pan.fond_blanc=false;}
								
	     						pan.act=1;	/* redo */
									maj();
                	}
        	} 
   	class fdelta implements ActionListener 
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{ 
            			String  reponse = (String) JOptionPane.showInputDialog
	    							(null, 
	     							"Valeur du delta pour formules différentielles (0.1 au début)", 
	     							"delta", 
	     							JOptionPane.QUESTION_MESSAGE);
	     							double i;
	     							
	     								try
		     								{i=Double.parseDouble(reponse);
	     									}
	     								catch(Exception ee)
	     									{i=0;}
	     								if ((i<1)&&(i>0))
            						{pan.stepsize=i;
            						}
 										pan.act=2;	/* iter */
                    maj();  
                	}
        	}   
  	class fcoeff implements ActionListener
        	{ 
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
            			String  reponse = (String) JOptionPane.showInputDialog
	    							(null,
	     							"Modification du coefficient a"+pan.modifcoeff+" ("+pan.A[pan.modifcoeff]+")", 
	     							"coefficient", 
	     							JOptionPane.QUESTION_MESSAGE);
	     							double i;
	 
	     								try
		     								{i=Double.parseDouble(reponse); 
	     									}
	     								catch(Exception ee)
	     									{i=3000.;}
	     								if ((i!=3000.))
            						{pan.A[pan.modifcoeff]=i;
            						} 
 										pan.act=2;	/* iter */
                    maj(); 
                	}
        	}     
   	class ftravel implements ActionListener
        	{ 
                @Override
                public void actionPerformed(ActionEvent e) 
                	{ 
            			String  reponse = (String) JOptionPane.showInputDialog
	    							(null, 
	     							"Valeur du delta pour le traveling des coefficients (0.005 au début)", 
	     							"delta traveling", 
	     							JOptionPane.QUESTION_MESSAGE);
	     							double i;
	     							
	     								try
		     								{i=Double.parseDouble(reponse);
	     									}
	     								catch(Exception ee)
	     									{i=0;}
	     								if ((i<1)&&(i>0))
            						{pan.pastravel_coeff=i;
            						}
 										pan.act=2;	/* iter */
                    maj();
                   
                	}
        	}        
    	class fnmax implements ActionListener 
        	{ 
                @Override
                public void actionPerformed(ActionEvent e) 
                	{ 
            			String  reponse = (String) JOptionPane.showInputDialog
	    							(null, 
	     							"Valeur maximum du nombre d'itérations (50000 au début, et >1500)", 
	     							"Itérations", 
	     							JOptionPane.QUESTION_MESSAGE);
	     							int i;
	     							
	     								try
		     								{i=Integer.parseInt(reponse);
	     									}
	     								catch(Exception ee)
	     									{i=0;}
	     								if (i>1500)
            						{pan.iter_max=i;
            						}
 										pan.act=2;	/* iter */
                    maj();
                   
                	}
        	}      
       class fpasmax implements ActionListener 
        	{ 
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
            			String  reponse = (String) JOptionPane.showInputDialog
	    							(null, 
	     							"Valeur du nombre d'itérations d'un cycle (1000 au début et >50)", 
	     							"Itérations", 
	     							JOptionPane.QUESTION_MESSAGE);
	     							int i;
     							
	     								try
		     								{i=Integer.parseInt(reponse);
	     									}
	     								catch(Exception ee)
	     									{i=0;}
	     								if (i>50)
            						{pan.iter_cycle=i;
            						}
 										pan.act=1;	/* redo */
                    maj();
                 
                	}
        	}      
 	class fNBVAR implements ActionListener 
        	{ 
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
            			String  reponse = (String) JOptionPane.showInputDialog
	    							(null, 
	     							"Nombre de variable des attracteurs à chercher (1-4)", 
	     							"NBVAR", 
	     							JOptionPane.QUESTION_MESSAGE);
	     							int i;
	     							
	     								try
		     								{i=Integer.parseInt(reponse);
	     									}
	     								catch(Exception ee)
	     									{i=-1;}
	     								if ((i>0) && (i<5))
            						{pan.NBVAR=i;
            						}
 
                     mmaj();
                    
                	}
        	}         
 	class ftype_attract implements ActionListener 
        	{ 
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
                	String  reponse = (String) JOptionPane.showInputDialog
	     							(null, 
     							"Type des attracteurs à chercher", 
	     							"types d attracteurs", 
      							JOptionPane.QUESTION_MESSAGE, 
	     							null,
	     							pan.nomtypeattract,
	     							pan.nomtypeattract[pan.TYPE_ATTRACT]);
	     						for (int i=0;i<pan.nomtypeattract.length;i++)
	     							if (reponse.equals(pan.nomtypeattract[i]))
	     								{ 
	     								pan.TYPE_ATTRACT=i;	     								
	     								}             						
                  mmaj();
                	}
        	}  
        class fmodifp implements ActionListener
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
                	pan.sens=0;
                	if (pan.travel==0)
                		{
                		if (pan.modifcoeff<pan.index_coeff+1)
                			{pan.A[pan.modifcoeff]=pan.A[pan.modifcoeff]+pan.pastravel_coeff;
                			if (pan.A[pan.modifcoeff]>4.4)
                				{pan.A[pan.modifcoeff]=-4.4;}
                			} 
                		if (pan.modifcoeff==pan.index_coeff+1)
                			{pan.x0=pan.x0+pan.pastravel_coeff;}
                		if (pan.modifcoeff==pan.index_coeff+2)
                			{pan.y0=pan.y0+pan.pastravel_coeff;}
                		}
                	else
                		{pan.iter_max=pan.iter_max+pan.pastravel_iter;}
                	pan.act=1;	/* redo */ 
                	pan.search_mode=false;
                  maj();
                	}
        	} 
        class fmodifm implements ActionListener
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
                	pan.sens=0;
                	if (pan.travel==0)
                		{
                		if (pan.modifcoeff<pan.index_coeff+1)
                			{pan.A[pan.modifcoeff]=pan.A[pan.modifcoeff]-pan.pastravel_coeff;
                			if (pan.A[pan.modifcoeff]<-4.4)
                				{pan.A[pan.modifcoeff]=4.4;}
                			}
                		if (pan.modifcoeff==pan.index_coeff+1)
                			{pan.x0=pan.x0-pan.pastravel_coeff;}
                		if (pan.modifcoeff==pan.index_coeff+2)
                			{pan.y0=pan.y0-pan.pastravel_coeff;}
                		}
                	else
                		{pan.iter_max=pan.iter_max-pan.pastravel_iter;
                		if (pan.iter_max<pan.iter_search) {pan.iter_max=50000;pan.sens=0;}
                		}
                	pan.act=1;	/* redo */
                	pan.search_mode=false;
                  maj();
                	}

        	} 
       class ftravel_coeff implements ActionListener
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
                	if (pan.travel==1) {pan.sens=1;}
                	pan.travel=0;	/* coeff */
                	if (pan.sens != 0) {pan.sens=-pan.sens;}
                	if (pan.sens == 0) {pan.sens=1;}
                	pan.act=1;	/* redo */
                	pan.search_mode=false;
                  maj();
                	}

        	} 
       class ftravel_iter implements ActionListener
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
                	if (pan.travel==0) {pan.sens=1;}
                	pan.travel=1;	/* coeff */
                	if (pan.sens != 0) {pan.sens=-pan.sens;}
                	if (pan.sens == 0) {pan.sens=1;}
                	pan.act=1;	/* redo */
                	pan.search_mode=false;
                  maj();
                	}

        	}
       class fralentir implements ActionListener
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
                	if (pan.travel==0)
                		{pan.pastravel_coeff=pan.pastravel_coeff/2.;}
                	else
                		{pan.pastravel_iter=pan.pastravel_iter/2.;}
                  mmaj();
                	}

        	} 
    class faccelerer implements ActionListener
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
                	if (pan.travel==0)
                		{pan.pastravel_coeff=pan.pastravel_coeff*2.;}
                	else
                		{pan.pastravel_iter=pan.pastravel_iter*2.;}
                  mmaj();
                	}
        	}
       class fperiode implements ActionListener
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
                	pan.sens=0;
                	pan.act=3;		/* un iterate */
                  maj();
                	}
        	}
       class fzoomin implements ActionListener
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
                	pan.zoom=pan.zoom/2;
                	pan.act=1;		/* redo */
                  maj();
                	}
        	}
       class fzoomout implements ActionListener
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{
                	pan.zoom=pan.zoom*2;
                	pan.act=1;		/* redo */
                  maj();
                	}
        	}
       class fchoix implements ActionListener
        	{
                @Override
                public void actionPerformed(ActionEvent e) 
                	{ 
                	pan.sens=0;
                  String  reponse = (String) JOptionPane.showInputDialog
	    							(null, 
	     							"Index du coefficient à modifier (1-"+pan.index_coeff+")", 
	     							"modif coeff", 
	     							JOptionPane.QUESTION_MESSAGE);
	     							int i;
	     						
	     								try
		     								{i=Integer.parseInt(reponse);
	     									} 
	     								catch(Exception ee)
	     									{i=-1;}
	     								if ((i>0) && (i<pan.index_coeff+3))
            						{pan.modifcoeff=i;
            						}
                	}

        	} 
}


