Output grafico: disegni un po' più complessi.
L'insieme di Mandelbrot.

L'insieme di Mandelbrot (IdM), che prende il nome dal matematico Bénoit B. Mandelbrot, è l'insieme dei numeri complessi c tali che la successione dei moduli di tutti i numeri complessi zi che, dato z0 = 0, si deducono aggiungendo c al quadrato dell'elemento precedente,

Eqn001.gif

sia formata da numeri reali finiti:

Denominando tale successione come successione di Mandelbrot, si può dimostrare che, se un elemento di tale successione ha modulo maggiore o uguale 2, la successione diverge e quindi, appena nello sviluppo della successione si incontra un numero di modulo maggiore o uguale a 2, si può essere sicuri che il numero complesso c generatore della successione non appartiene a IdM.

Indicando con il termine di permanenza l'indice dell'ultimo numero della successione con modulo minore di 2, si può dire che i numeri con permanenza finita non appartengono a IdM ovvero che IdM è l'insieme dei numeri complessi con permanenza infinita.

Un valore abbastanza alto di permanenza minima costituisce quindi un filtro per selezionare molti numeri complessi non appartenenti all'insieme.

Calcolando infatti la permanenza di un adeguato numero di numeri complessi di modulo minore di 2 si potranno infatti scartare tra essi tutti quelli con permanenza inferiore alla minima stabilita.

Viceversa per quanto sia alta, ma finita, la permanenza minima stabilita, non si potrà essere sicuri che tutti i complessi non scartati appartengano all'insieme.

Rappresentando graficamente i numeri con una permanenza abbastanza alta si otterrà comunque una buona rappresentazione dell'insieme e il grafico sarà tanto migliore quanto maggiore si fissa la permanenza minima.

Per ottenere un'immagine abbastanza vivace dei punti vicini alla frontiera dell'IdM, si rappresentano i punti non appartenenti all'insieme, quindi con permanenza finita, con colori diversi a seconda della loro permanenza.

La frontiera di IdM non è una linea continua, interrotta al più da qualche singolarità, come quelle studiate dalla geometria classica (poligoni, circonferenze, coniche, curve algebriche, curve trigonometriche, esponenziali e logaritmiche, ecc. ).

Una figura di questo genere manifesta proprietà assolutamente inedite rispetto a quelle classiche:

Figure che godono di queste proprietà sono dette frattali.

Nell'esempio seguente si dichiara la classe principale Mandelbrot derivandola da JFrame, se ne dichiarano i campi e se ne redige il costruttore.

public class Mandelbrot
extends JFrame
implements ActionListener

{
  Container client;
  MandCanvas canvas;
  JPanel pn_figura, pn_laterale, pn_medio,pn_input, pn_output, pn_ix, 
    pn_perm, pn_nc, pn_xmin, pn_xmax, pn_ymin, pn_ymax, pn_sup, pn_inf;
  JTextField ed_perm, ed_nc;
  JLabel lb_xmin, lb_xmax, lb_ymin, lb_ymax, lb_ix;
  Bottone bt_zoomp, bt_zoomm, bt_su, bt_giu, bt_destra, bt_sinistra, 
    bt_reset, bt_prec, bt_seg, bt_refresh;

  Lista lista;
//---------------------------------------------------------------
  public Mandelbrot()
    {
      setTitle("Mandelbrot");
      Border border;
      Font font = new Font("Verdana",Font.PLAIN,10);
      Font bf = new Font("Arial",Font.BOLD,16);

      client = getContentPane();
      client.setLayout(new BoxLayout(client,BoxLayout.PAGE_AXIS));

      pn_figura = new JPanel();
      pn_figura.setLayout(new BoxLayout(pn_figura,BoxLayout.LINE_AXIS));

      canvas = new MandCanvas();
      canvas.setPreferredSize(new Dimension(500, 500));
      pn_figura.add(canvas);

      pn_laterale = new JPanel();
      pn_laterale.setLayout(new BoxLayout(pn_laterale,BoxLayout.PAGE_AXIS));
      pn_laterale.setPreferredSize(new Dimension(130,500));

      pn_sup = new JPanel();
      pn_sup.setPreferredSize(new Dimension(100,80));
      pn_sup.setLayout(new BorderLayout());

//comando 7: reset
      bt_reset = new Bottone("Reset",bf,Color.cyan,Color.black,"7");
      bt_reset.addActionListener(this);
      pn_sup.add(bt_reset,BorderLayout.NORTH);

//comando 5: zoom +
      bt_zoomp = new Bottone("Zoom +",bf,Color.pink,Color.black,"5");
      bt_zoomp.addActionListener(this);
      pn_sup.add(bt_zoomp,BorderLayout.CENTER);

//comando 6: zoom -
      bt_zoomm = new Bottone("Zoom -",bf,Color.yellow,Color.black,"6");
      bt_zoomm.addActionListener(this);
      pn_sup.add(bt_zoomm,BorderLayout.SOUTH);

      pn_laterale.add(pn_sup);

      pn_medio = new JPanel();
      pn_medio.setLayout(new BorderLayout());
      pn_medio.setPreferredSize(new Dimension(100,80));
      pn_medio.setBackground(Color.lightGray);

//comando 1
      bt_su = new Bottone("\u25b2",bf,Color.green,Color.red,"1");
      bt_su.addActionListener(this);
      pn_medio.add(bt_su,BorderLayout.NORTH);

//comando 2
      bt_giu = new Bottone("\u25BC",bf,Color.green,Color.red,"2");
      bt_giu.addActionListener(this);
      pn_medio.add(bt_giu,BorderLayout.SOUTH);

//comando 3
      bt_sinistra = new Bottone("\u25C4",bf,Color.green,Color.red,"3");
      bt_sinistra.addActionListener(this);
      pn_medio.add(bt_sinistra,BorderLayout.WEST);

//comando 4
      bt_destra = new Bottone("\u25BA",bf,Color.green,Color.red,"4");
      bt_destra.addActionListener(this);
      pn_medio.add(bt_destra,BorderLayout.EAST);

      pn_laterale.add(pn_medio);

      pn_inf = new JPanel();
      pn_inf.setLayout(new BorderLayout());
      pn_inf.setPreferredSize(new Dimension(100,80));

//comando 8: refresh
      bt_refresh = new Bottone("Aggiorna",bf,Color.pink,Color.black,"8");
      bt_refresh.addActionListener(this);
      pn_inf.add(bt_refresh,BorderLayout.CENTER);

//comando 9: indietro
      bt_prec = new Bottone("Precedente",bf,Color.cyan,Color.black,"9");
      bt_prec.addActionListener(this);
      pn_inf.add(bt_prec,BorderLayout.NORTH);

//comando 10: avanti
      bt_seg = new Bottone("Seguente",bf,Color.yellow,Color.black,"10");
      bt_seg.addActionListener(this);
      pn_inf.add(bt_seg,BorderLayout.SOUTH);

      pn_laterale.add(pn_inf);

      pn_figura.add(pn_laterale);
      client.add(pn_figura);

      pn_output = new JPanel();
      pn_output.setPreferredSize(new Dimension(300, 40));
      border = BorderFactory.createEmptyBorder();
      pn_output.setBorder(border); 
      pn_output.setLayout(new BoxLayout(pn_output,BoxLayout.LINE_AXIS));

      pn_xmin = new Titolato("x min");
      
      lb_xmin = new JLabel(String.valueOf(canvas.xmin));
      lb_xmin.setFont(font);
      pn_xmin.add(lb_xmin);

      pn_output.add(pn_xmin);

      pn_xmax = new Titolato("x max");
      
      lb_xmax = new JLabel(String.valueOf(canvas.xmax));
      lb_xmax.setFont(font);
      pn_xmax.add(lb_xmax);
      pn_output.add(pn_xmax);

      pn_ymin = new Titolato("y min");
     
      lb_ymin = new JLabel(String.valueOf(canvas.ymin));
      lb_ymin.setFont(font);
      pn_ymin.add(lb_ymin);
      pn_output.add(pn_ymin);

      pn_ymax = new Titolato("y max");
      lb_ymax = new JLabel(String.valueOf(canvas.ymax));
      lb_ymax.setFont(font);
      pn_ymax.add(lb_ymax);
      pn_output.add(pn_ymax);

      client.add(pn_output);

      pn_input = new JPanel();
      pn_input.setPreferredSize(new Dimension(400, 44));
      pn_input.setBorder(BorderFactory.createEmptyBorder()); 
      pn_input.setLayout(new BoxLayout(pn_input,BoxLayout.LINE_AXIS));

      pn_ix = new Titolato("N. figura");
      lb_ix = new JLabel("0");
      lb_ix.setFont(font);
      pn_ix.add(lb_ix);
      pn_input.add(pn_ix);


      pn_perm = new Titolato("Permanenza");
      
      ed_perm = new JTextField(String.valueOf(canvas.permanenza));
      ed_perm.setPreferredSize(new Dimension(50,20));
      pn_perm.add(ed_perm);
      pn_input.add(pn_perm);
 
      pn_nc = new Titolato("N. colori");
      ed_nc = new JTextField(String.valueOf(canvas.n_colori));
      ed_nc.setPreferredSize(new Dimension(50,20));
      pn_nc.add(ed_nc);
      pn_input.add(pn_nc);

      client.add(pn_input);

      lista = new Lista();
      lista.add();
    }

Le istruzioni nel costruttore servono soprattutto a confezionare l'interfaccia grafica dell'applicazione.

fig01.png

La classe interna più importante per il funzionamento dell'applicazione è la classe MandCanvas, derivata dalla classe java.awt.Canvas che rappresenta la zona nella quale avviene la rappresentazione dell'insieme. La figura è prodotta dal metodo update di MandCanvas e più specificamente dal ciclo

      for (xpl=dimensione; xpl>=0; xpl--)
        {
          y = ymax;
          for (ypl=dimensione;ypl>=0;ypl--)
            {
              ix_colore = fMandelbrot(x,y)/passo;
              if (ix_colore>n_colori-2) ix_colore=n_colori-1;
              big.setColor(tavolozza.colore[ix_colore]);
              big.drawLine(xpl,ypl,xpl,ypl); 
              y -= incr;
            };
          x -= incr;
        }

Il ciclo percorre tutti i punti del quadrato esaminato che rappresenta una porzione del piano complesso. Per ognuno di questi punti calcola il valore prodotto dalla funzione di Mandelbrot con permanenza assegnata in input e quindi il colore con cui rappresentarlo.
L'insieme dei colori è definito dalla classe Tavolozza a seconda del numero di colori assegnato in input.

L'applicazione, con l'uso dei bottoni laterali, permette di spostare l'inquadratura e di ingrandirla o ridurla.

È inolte possibile, con il mouse, scegliere un quadrato del grafico e ingrandirlo su tutta la canvas evidenziando particolari sempre più minuti.

L'applicazione registra tutte le figure prodotte e con i bottoni Precedente e Seguente è possibile scorrere tra di esse.

Il bottone Aggiorna ridisegna la figura corrente se si cambia il numero dei colori.

 


Esempio.

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import java.io.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.ArrayList;

/************************************************************************/
public class Mandelbrot
extends JFrame
implements ActionListener

{
  Container client;
  MandCanvas canvas;
  JPanel pn_figura, pn_laterale, pn_medio,pn_input, pn_output, pn_ix, 
    pn_perm, pn_nc, pn_xmin, pn_xmax, pn_ymin, pn_ymax, pn_sup, pn_inf;
  JTextField ed_perm, ed_nc;
  JLabel lb_xmin, lb_xmax, lb_ymin, lb_ymax, lb_ix;
  Bottone bt_zoomp, bt_zoomm, bt_su, bt_giu, bt_destra, bt_sinistra, 
    bt_reset, bt_prec, bt_seg, bt_refresh;

  Lista lista;
//---------------------------------------------------------------
  public Mandelbrot()
    {
      setTitle("Mandelbrot");
      Border border;
      Font font = new Font("Verdana",Font.PLAIN,10);
      Font bf = new Font("Arial",Font.BOLD,16);

      client = getContentPane();
      client.setLayout(new BoxLayout(client,BoxLayout.PAGE_AXIS));

      pn_figura = new JPanel();
      pn_figura.setLayout(new BoxLayout(pn_figura,BoxLayout.LINE_AXIS));

      canvas = new MandCanvas();
      canvas.setPreferredSize(new Dimension(500, 500));
      pn_figura.add(canvas);

      pn_laterale = new JPanel();
      pn_laterale.setLayout(new BoxLayout(pn_laterale,BoxLayout.PAGE_AXIS));
      pn_laterale.setPreferredSize(new Dimension(130,500));

      pn_sup = new JPanel();
      pn_sup.setPreferredSize(new Dimension(100,80));
      pn_sup.setLayout(new BorderLayout());

//comando 7: reset
      bt_reset = new Bottone("Reset",bf,Color.cyan,Color.black,"7");
      bt_reset.addActionListener(this);
      pn_sup.add(bt_reset,BorderLayout.NORTH);

//comando 5: zoom +
      bt_zoomp = new Bottone("Zoom +",bf,Color.pink,Color.black,"5");
      bt_zoomp.addActionListener(this);
      pn_sup.add(bt_zoomp,BorderLayout.CENTER);

//comando 6: zoom -
      bt_zoomm = new Bottone("Zoom -",bf,Color.yellow,Color.black,"6");
      bt_zoomm.addActionListener(this);
      pn_sup.add(bt_zoomm,BorderLayout.SOUTH);

      pn_laterale.add(pn_sup);

      pn_medio = new JPanel();
      pn_medio.setLayout(new BorderLayout());
      pn_medio.setPreferredSize(new Dimension(100,80));
      pn_medio.setBackground(Color.lightGray);

//comando 1
      bt_su = new Bottone("\u25b2",bf,Color.green,Color.red,"1");
      bt_su.addActionListener(this);
      pn_medio.add(bt_su,BorderLayout.NORTH);

//comando 2
      bt_giu = new Bottone("\u25BC",bf,Color.green,Color.red,"2");
      bt_giu.addActionListener(this);
      pn_medio.add(bt_giu,BorderLayout.SOUTH);

//comando 3
      bt_sinistra = new Bottone("\u25C4",bf,Color.green,Color.red,"3");
      bt_sinistra.addActionListener(this);
      pn_medio.add(bt_sinistra,BorderLayout.WEST);

//comando 4
      bt_destra = new Bottone("\u25BA",bf,Color.green,Color.red,"4");
      bt_destra.addActionListener(this);
      pn_medio.add(bt_destra,BorderLayout.EAST);

      pn_laterale.add(pn_medio);

      pn_inf = new JPanel();
      pn_inf.setLayout(new BorderLayout());
      pn_inf.setPreferredSize(new Dimension(100,80));

//comando 8: refresh
      bt_refresh = new Bottone("Aggiorna",bf,Color.pink,Color.black,"8");
      bt_refresh.addActionListener(this);
      pn_inf.add(bt_refresh,BorderLayout.CENTER);

//comando 9: indietro
      bt_prec = new Bottone("Precedente",bf,Color.cyan,Color.black,"9");
      bt_prec.addActionListener(this);
      pn_inf.add(bt_prec,BorderLayout.NORTH);

//comando 10: avanti
      bt_seg = new Bottone("Seguente",bf,Color.yellow,Color.black,"10");
      bt_seg.addActionListener(this);
      pn_inf.add(bt_seg,BorderLayout.SOUTH);

      pn_laterale.add(pn_inf);

      pn_figura.add(pn_laterale);
      client.add(pn_figura);

      pn_output = new JPanel();
      pn_output.setPreferredSize(new Dimension(300, 40));
      border = BorderFactory.createEmptyBorder();
      pn_output.setBorder(border); 
      pn_output.setLayout(new BoxLayout(pn_output,BoxLayout.LINE_AXIS));

      pn_xmin = new Titolato("x min");
      
      lb_xmin = new JLabel(String.valueOf(canvas.xmin));
      lb_xmin.setFont(font);
      pn_xmin.add(lb_xmin);
      pn_output.add(pn_xmin);

      pn_xmax = new Titolato("x max");
      
      lb_xmax = new JLabel(String.valueOf(canvas.xmax));
      lb_xmax.setFont(font);
      pn_xmax.add(lb_xmax);
      pn_output.add(pn_xmax);

      pn_ymin = new Titolato("y min");
     
      lb_ymin = new JLabel(String.valueOf(canvas.ymin));
      lb_ymin.setFont(font);
      pn_ymin.add(lb_ymin);
      pn_output.add(pn_ymin);

      pn_ymax = new Titolato("y max");
      lb_ymax = new JLabel(String.valueOf(canvas.ymax));
      lb_ymax.setFont(font);
      pn_ymax.add(lb_ymax);
      pn_output.add(pn_ymax);

      client.add(pn_output);

      pn_input = new JPanel();
      pn_input.setPreferredSize(new Dimension(400, 44));
      pn_input.setBorder(BorderFactory.createEmptyBorder()); 
      pn_input.setLayout(new BoxLayout(pn_input,BoxLayout.LINE_AXIS));

      pn_ix = new Titolato("N. figura");
      lb_ix = new JLabel("0");
      lb_ix.setFont(font);
      pn_ix.add(lb_ix);
      pn_input.add(pn_ix);


      pn_perm = new Titolato("Permanenza");
      
      ed_perm = new JTextField(String.valueOf(canvas.permanenza));
      ed_perm.setPreferredSize(new Dimension(50,20));
      pn_perm.add(ed_perm);
      pn_input.add(pn_perm);
 
      pn_nc = new Titolato("N. colori");
      ed_nc = new JTextField(String.valueOf(canvas.n_colori));
      ed_nc.setPreferredSize(new Dimension(50,20));
      pn_nc.add(ed_nc);
      pn_input.add(pn_nc);

      client.add(pn_input);

      lista = new Lista();
      lista.add();
    }

//----------------------------------------------------------------------
  public static void main(String args[])
    {
      Mandelbrot m = new Mandelbrot();
      m.pack();
      m.setVisible(true);
    }
 
//----------------------------------------------------------------------
  public void actionPerformed(ActionEvent e)
    {
      String comando$= e.getActionCommand();
      int comando = leggeIntero(comando$);
      disegnare(comando);
    }

//----------------------------------------------------------------------
  public void aggiornaDimensioni()
    {
      lb_xmin.setText(new Float(canvas.xmin).toString());
      lb_ymin.setText(new Float(canvas.ymin).toString());      
      lb_xmax.setText(new Float(canvas.xmax).toString());
      lb_ymax.setText(new Float(canvas.ymax).toString());

      lb_ix.setText(new Integer(lista.ix).toString());       
    }

//----------------------------------------------------------------------
  public void disegnare(int modo)
    {
      boolean aggiungere = (modo < 9) ;

      if (aggiungere) lista.ix = lista.size()-1;

      double d;
      Quaterna qt;
      int p = leggeIntero(ed_perm.getText());
      int c = leggeIntero(ed_nc.getText());
      if (p < c)
        {
          p=c;
          ed_perm.setText(new Integer(p).toString());
        };
      if ((p % c) !=0)
        {
          while ((p % c)!=0) c++;
          ed_nc.setText(new Integer(c).toString());
        };          
      canvas.setPermanenza(p);
      canvas.setNColori(c);
      canvas.setInizio(true);
      d = (canvas.xmax-canvas.xmin)/10;
      switch(modo)
        {
          case 1: //su
            canvas.ymin += d;
            canvas.ymax += d;
            break;
          case 2: //giu
            canvas.ymin -= d;
            canvas.ymax -= d;
            break;
          case 3: //sinistra
            canvas.xmin += d;
            canvas.xmax += d;
            break;
          case 4: //destra
            canvas.xmin -= d;
            canvas.xmax -= d;
            break;

          case 5:  //zoom+
            Quadrato q = canvas.q;
            if (q.mobile)
              canvas.nuovoQuadro(q.x,q.y,q.l);
            else
              {
                canvas.xmin += d;
                canvas.ymin += d;
                canvas.xmax -= d;
                canvas.ymax -= d;
              };
            break;

          case 6:  //zoom-
            canvas.xmin -= d;
            canvas.ymin -= d;
            canvas.xmax += d;
            canvas.ymax += d;
            break;

          case 7:  //reset
            canvas.xmin = -2.5;
            canvas.ymin = -2.5;
            canvas.xmax = 2.5;
            canvas.ymax = 2.5;
            break;

          case 9: //indietro
            if (lista.isEmpty()) return;
            if (lista.ix==0) return;
            lista.ix--;
            aggiungere = false;
            qt = lista.get(lista.ix);
            canvas.xmin = qt.xmin;
            canvas.xmax = qt.xmax;
            canvas.ymin = qt.ymin;
            canvas.ymax = qt.ymax;
            break; 

          case 10: //avanti
            if (lista.isEmpty()) return;
            if (lista.ix == lista.size()-1) return;
            lista.ix++;
            aggiungere = false;

            qt = lista.get(lista.ix);
            canvas.xmin = qt.xmin;
            canvas.xmax = qt.xmax;
            canvas.ymin = qt.ymin;
            canvas.ymax = qt.ymax;
            break;
        }

      if (aggiungere) lista.add();

      aggiornaDimensioni();
      canvas.repaint();

    }

//----------------------------------------------------------------------
  int leggeIntero(String s)
    {
      int result=0;
      if (s==null) return 0;
      try
        {
          Integer r = new Integer(s);
          result = r.intValue();
        }
      catch(ArithmeticException e)
        {
          result = 0;
        };
      return result;
    }


/**************************************************************************************/
class Bottone
extends JButton
{
  Bottone(String t, Font f, Color bg, Color fg, String c)
    {
      setText(t);
      setFont(f);
      setForeground(fg);
      setBackground(bg);
      setActionCommand(c);
    }
}

/**************************************************************************************/
class MandCanvas
extends Canvas
implements MouseListener, MouseMotionListener

{
  static final int dimensione=500;
  public double xmin = -2.5, ymin = -2.5, lato;
  public double xmax = 2.5, ymax=2.5;
  public int permanenza = 50, n_colori = 50, passo=1;
  public double x,y,incr;
  int xpl,ypl, xprec, yprec, incrx, incry, ix_colore;
  boolean inizio=true, fare_quadrato=false, disfare_quadrato=false;
  Tavolozza tavolozza;
  Quadrato q,qprec;
  Insets insets;
  Rectangle area;
  BufferedImage bi;
  Graphics2D big;

//----------------------------------------------------------------------
  public MandCanvas()
    {
      addMouseListener(this);
      addMouseMotionListener(this);
      tavolozza = new Tavolozza(n_colori);
      insets = getInsets();
      area = new Rectangle(insets.left,insets.top,dimensione,dimensione);
      bi = new BufferedImage(dimensione,dimensione, BufferedImage.TYPE_INT_RGB);
    }

//---------------------------------------------------------------
  void setInizio(boolean v)
    {
      inizio = v;
    } 

//---------------------------------------------------------------
  void setPermanenza(int p)
    {
      if (p != permanenza) setInizio(true);
      permanenza = p;
    }

//---------------------------------------------------------------
  void setNColori(int nc)
    {
      n_colori = nc;
      tavolozza.setCambio(n_colori != tavolozza.n_c); 
      setInizio(tavolozza.cambiata);
    }

//---------------------------------------------------------------
  void nuovoQuadro(int x1, int y1, int l)
    {
      xmin += x1*incr;
      ymin += y1*incr;
      xmax = xmin+l*incr;
      ymax = ymin+l*incr;
    }

//---------------------------------------------------------------
  public void disegnaQuadrato()
    {
      fare_quadrato = true;
      setInizio(false);
      repaint();
    }

//---------------------------------------------------------------
  public void cancellaQuadrato()
    {
      disfare_quadrato = true;
      setInizio(false);
      repaint();
    }

//---------------------------------------------------------------
  public void paint(Graphics g)
    {
      update(g);
    }

//---------------------------------------------------------------
  public void update(Graphics g)
    {
      Graphics2D g2 = (Graphics2D)g;
      if (!inizio)
        {
          if (disfare_quadrato)
            {
              big.setColor(Color.black);
              big.setXORMode(Color.white);
              if (qprec.l>0) big.draw(qprec);
              g2.drawImage(bi,0,0,this);
              qprec.Azzera();
              disfare_quadrato = false;
            }
          if (fare_quadrato)
            {
              big.setColor(Color.black);
              big.setXORMode(Color.white);
              if (qprec.l>0) big.draw(qprec);
              big.draw(q);
              qprec.Copia(q);
              fare_quadrato = false;
              g2.drawImage(bi,0,0,this);
            }
          return;
        }

      q = new Quadrato();
      qprec = new Quadrato();

      if (tavolozza.cambiata)
        tavolozza = new Tavolozza(n_colori);

      passo = permanenza/n_colori;
      lato = xmax-xmin;
      incr = lato/dimensione;
      x = xmax;
      big = bi.createGraphics();

      for (xpl=dimensione; xpl>=0; xpl--)
        {
          y = ymax;
          for (ypl=dimensione;ypl>=0;ypl--)
            {
              ix_colore = fMandelbrot(x,y)/passo;
              if (ix_colore>n_colori-2) ix_colore=n_colori-1;
              big.setColor(tavolozza.colore[ix_colore]);
              big.drawLine(xpl,ypl,xpl,ypl); 
              y -= incr;
            };
          x -= incr;
        }

      g2.drawImage(bi,0,0,this);
    }

//---------------------------------------------------------------
  int fMandelbrot(double xi, double yi)
    {
      double x,y,xx=0,yy=0,xy=0;
      int result=0;
      do
        {
          y = 2*xy+yi;
          x = xx-yy+xi;
          xx = x*x;
          yy = y*y;
          xy = x*y;
          result++;
        } while( (xx+yy < 4) && (result < permanenza));
      result--;
      return (result);
    }

//---------------------------------------------------------------
  public void mousePressed(MouseEvent e)
    {
     
      xpl = e.getX();
      ypl = e.getY();
      xprec = xpl;
      yprec = ypl; 
      if (!area.contains(xpl,ypl)) return;

      if (q.mobile)
        {
          if (!q.contains(xpl,ypl))
            {
              q.setMobile(false);
              cancellaQuadrato();
            };
          q.setIniziato(false);
          return;
        };
      q.setLocation(xpl,ypl);
      xprec = 0;
      yprec = 0;
      q.setIniziato(true);
      q.setMobile(false);
    }

//---------------------------------------------------------------
  public void mouseReleased(MouseEvent e)
    {
      xpl = e.getX();
      ypl = e.getY();
      if (!area.contains(xpl,ypl)) return;
      if (q.mobile)
        {
          xprec = -1;
          yprec = -1;
          return;
        };
      if (q.iniziato)
        {
          q.setMobile(true);
          qprec.Copia(q);
        };
    }

//---------------------------------------------------------------
  public void mouseDragged(MouseEvent e)
    {
      xpl = e.getX();
      ypl = e.getY();
      if (xprec>=0) incrx = xpl-xprec;
      if (yprec>=0) incry = ypl-yprec;
      if (q.mobile) //spostamento: modifica origine
        {
          q.setLocation(q.x+incrx,q.y+incry);
          xprec=xpl;
          yprec=ypl;
          disegnaQuadrato();
          disegnaQuadrato();
          return;
        };
      if (!area.contains(xpl,ypl)) return;
      q.setLato(xpl-q.x);
      disegnaQuadrato();
      disegnaQuadrato();
    }
//---------------------------------------------------------------
// These methods are required by MouseMotionListener.
  public void mouseMoved(MouseEvent e){}
  public void mouseClicked(MouseEvent e){}
  public void mouseExited(MouseEvent e){}
  public void mouseEntered(MouseEvent e){}
//---------------------------------------------------------------
}
/**************************************************************************/
class Tavolozza
{
  int n_c;
  boolean cambiata;
  Color[] colore;
  Tavolozza(int nc)
    {
      n_c = nc;
      cambiata = false;
      colore = new Color[nc];
      FaColori();
    }
//---------------------------------------------------------------
  void setCambio(boolean cambio)
    {
      cambiata = cambio;
    }
//---------------------------------------------------------------
  void FaColori()
    {
      int i=0,j=0,k=0,r,rosso,verde,blu;
      double d,q;
      q = n_c/6;
      d = 255/q;
      if (d < 1) d = 1;
      while (i < n_c)
        {
          switch(k)
            {
              case 0:
//comincia nero, finisce azzurro
                r = (int)Math.round(j*d);
                rosso = 1;
                verde = r;
                blu = r;
                j++;
                if (r>254)
                  {
                    blu = 254;
                    verde = 254;
                    j = 0;
                    k++;
                  };
                break;
              case 1:
//comincia azzurro, finisce viola
                r = (int)Math.round(j*d);
                j++;
                verde = 255-r;
                blu = 254;
                rosso = r;
                if (rosso>254)
                  {
                    rosso = 254;
                    verde = 1;
                    j = 0;
                    k++;
                  };
                break;
              case 2:
//comincia viola, finisce rosso
                r = (int)Math.round(j*d);
                j++;
                verde = 1;
                rosso = 254;
                blu = 255-r;
                if (blu < 0)
                  {
                    blu = 1;
                    j = 0;
                    k++;
                  };
                break;
              case 3:
//comincia rosso, finisce marrone
                r = (int)Math.round(j*d);
                j++;
                rosso = 255-r;
                blu = r;
                verde = 1;
                if (rosso < 0)
                  {
                    rosso = 1;
                    blu = 254;
                    j = 0;
                    k++;
                  };
                break;
              case 4:
//comincia verde, finisce giallo
                r = (int)Math.round(j*d);
                j++;
                rosso = r;
                verde = r;
                blu = 255-r;
                if (r>254)
                  {
                    verde = 254;
                    rosso = 254;
                    blu = 1;
                    j = 0;
                    k++;
                  };
                break;
              default:
//comincia giallo, finisce bianco
                r = (int)Math.round(j*d);
                j++;
                rosso = 255;
                verde = 255;
                blu = r;
                if (blu>255)
                  {
                    blu = 255;
                  };
            };
          if (i==n_c-1)
            {
              rosso = 255;
              verde =255;
              blu = 255;
            };
          colore[i] = new Color(rosso,verde,blu);
          i++;
        };
     }  
}

/**************************************************************************************/
class Titolato
extends JPanel

{
  Font font = new Font("Verdana",Font.BOLD,11);
  TitledBorder border;
//---------------------------------------------------------------
  Titolato(String titolo)
    {
      setPreferredSize(new Dimension(40,20));
      border = BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(),titolo); 
      border.setTitleFont(font);
      setBorder(border);
      setLayout(new FlowLayout(FlowLayout.LEFT,5,0));
    }
//---------------------------------------------------------------
}

/**************************************************************************************/
class Quadrato
extends Rectangle

{
  boolean iniziato,mobile;
  int l;
//---------------------------------------------------------------
  Quadrato()
    {
      super();
      l = 0;
      iniziato = false;
      mobile = false;
    }

//---------------------------------------------------------------
  public void setIniziato(boolean v)
    {
      iniziato = v;
    }
//---------------------------------------------------------------
  public void setMobile(boolean v)
    {
      mobile = v;
    }
//---------------------------------------------------------------
  public void setLato(double lato)
    {
      l = (int)lato;
      setSize(l,l);
    }
//---------------------------------------------------------------
  public void Copia(Quadrato sorg)
    {
      l = sorg.l;
      iniziato = sorg.iniziato;
      mobile = sorg.mobile;
      x = sorg.x;
      y = sorg.y;
      width = sorg.width;
      height = sorg.height;
    }
//---------------------------------------------------------------
  public void Azzera()
    {
      l = 0;
      iniziato = false;
      mobile = false;
      x = 0;
      y = 0;
      width = 0;
      height = 0;
    }
//---------------------------------------------------------------
                                      //fine
}
/**************************************************************************************/
class Quaterna
{
  double xmin,xmax,ymin,ymax;
//---------------------------------------------------------------
  Quaterna(double x1,double y1,double x2,double y2)
    {
      xmin = x1;
      ymin = y1;
      xmax = x2;
      ymax = y2;
    }
//--------------------------------------------------------------- 
  public String toString()
    {
      return "{"+xmin+","+ymin+","+xmax+","+ymax+"}";
    }  
}

/**************************************************************************************/
class Lista
extends ArrayList < Quaterna >
{
  int ix = -1;

//----------------------------------------------------------------------
  public void add()
    {
      add(new Quaterna(canvas.xmin,canvas.ymin,canvas.xmax,canvas.ymax));
      ix++;
    }

//--------------------------------------------------------------- 
  public String toString()
    {
      String s = "";
      if (isEmpty()) return "";
      for (int i=0; i < size(); i++)
        s += get(i).toString();
      return s;
    } 
}
 
}

Il sorgente può essere scaricato da Mandelbrot.zip e scompattato in una cartella del proprio sistema.