/**
 * julia.java
 *
 * trace l'ensemble de Juia avec des couleurs aléatoires
 * possibilité de zoomer et de changer de paramètres
 * modifié le 18/04/20
 *
 * @ author Jean-Paul Quelen
 */

import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;

public class julia extends JPanel implements MouseListener, ActionListener {
	static final long serialVersionUID = 200418L;
	int xmax, ymax, Niter, NCouleur, x, y, n, nm1;
	double Zoom, Rayon2, pas, xo, yo, parmjuliax, parmjuliay;
	double Cy, Cx, Zx, Zy, Z;
	int [] [] TCouleur;
	Random r;
	TextField tfx, tfy, mult;
	Button b;

	public julia() {
		setCursor (new Cursor (Cursor.CROSSHAIR_CURSOR));

		add (mult = new TextField ("x 1", 10));
		Font f = new Font (Font.SANS_SERIF, Font.PLAIN, 10);
		mult.setFont (f);
		mult.setBackground (Color.black);
		mult.setForeground (Color.white);

		add (b = new Button ("Nouveau tracé"));
		b.setFont (f);

		parmjuliax = 0.1;
		add (tfx = new TextField ("0.1", 10));

		parmjuliay = 0.6;
		add (tfy = new TextField ("0.6", 10));

		NCouleur = 256;
		Niter = 256;
		b.addActionListener (this);
		addMouseListener (this);
	}

	private void init() {

// (ré)initialisation
		xo = yo = 0;
		Zoom = 1.0;
		Rayon2 = 4.0;
		pas = 4.0 / Zoom / (xmax > ymax ? xmax : ymax);
		y = 0;
		Cy = yo - ymax * pas / 2.0;
		mult.setText ("x 1");
// nouvelles couleurs
		TCouleur = new int [Niter] [3];
		r = new Random ();
		int Niterm1 = Niter - 1;
		TCouleur [Niterm1] [0] = TCouleur [Niterm1] [1] = TCouleur [Niterm1] [2] = 0;
		for (n = 0; n < Niterm1; n++)
			for (int p = 0; p < 3; p++)
				TCouleur [n] [p] = Math.abs (r.nextInt ()) % NCouleur;
// affichage des paramètres
		tfx.setText (Double.toString (parmjuliax));
		tfy.setText (Double.toString (parmjuliay));
	}

	private double tfd (TextField tf, double d) {
		try {
			d = Double.parseDouble (tf.getText());
		}
		catch (NumberFormatException nfe) {}
		tf.setText (Double.toString (d));
		return d;
	}

	public void update (Graphics g) {
		paint (g);
	}

	public void paint (Graphics g) {
		if (xmax != getWidth() || ymax != getHeight()) {
			xmax = getWidth();
			ymax = getHeight();
			init();
		}
		while (y < ymax) {
			Cx = xo - xmax * pas / 2.0;
			for (x = 0; x < xmax; x ++ ) {
				Zx = Cx;
				Zy = Cy;
				n = 1;
				while (((Zx * Zx + Zy * Zy) < Rayon2) & (n < Niter)) {
					Z = Zx * Zx - Zy * Zy + parmjuliax;
					Zy = 2.0 * Zx * Zy + parmjuliay;
					Zx = Z;
					n++;
				}
				nm1 = n - 1;
				g.setColor (new Color (TCouleur [nm1] [0], TCouleur [nm1] [1], TCouleur [nm1] [2])); 
				g.drawLine (x, y, x, y);
				Cx += pas;
			}
			Cy += pas;
			y++;
		}
	}

	public void actionPerformed (ActionEvent e) {
		if (e.getSource() == b) {
			parmjuliax = tfd (tfx, parmjuliax);
			parmjuliay = tfd (tfy, parmjuliay);
			init();
			repaint();
		}
	}

	public void mousePressed (MouseEvent e) {
		parmjuliax = tfd (tfx, parmjuliax);
		parmjuliay = tfd (tfy, parmjuliay);
		xo += pas * (e.getX () - xmax / 2.0);
		yo += pas * (e.getY () - ymax / 2.0);
		Zoom *= 2.0;
		pas = 4.0 / Zoom / (xmax > ymax ? xmax : ymax);
		y = 0;
		Cy = yo - ymax * pas / 2.0;
		mult.setText ("x " + (int) Zoom);
		repaint();
	}

	public void mouseReleased (MouseEvent e) {}
	public void mouseClicked (MouseEvent e) {}
	public void mouseEntered (MouseEvent e) {}
	public void mouseExited (MouseEvent e) {}

////////////////////////////////////////////////////////////////////////////////

	public static void main (String [] args) {
		int w = 600;
		int h = 600;

		julia j = new julia();

		JFrame f = new JFrame ("Ensemble de Julia");
		f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
		f.add (j);
		f.setSize (w, h);
		f.setVisible (true);
	}

}
