
// Mandelbrot.java
// Robert Sedgewick and Kevin Wayne
// Slightly modified by Andrew Davison, Nov. 2022

// https://introcs.cs.princeton.edu/java/32class/ColorMandelbrot.java.html

/* Plots the size-by-size region of the Mandelbrot set, 
   centered on (xc,yc)

   The Mandelbrot set lies in the Complex grid completely 
   within a  circle with radius 2.

   Start by scanning every point in that rectangular area. 
   Each point represents a Complex number (x + yi). 
   Iterate that complex number:
       f(z) = z2 + C
   where z is a complex variable and C is a complex constant. 
   
   Now you iterate it starting from z = 0, i.e. you compute 
   z1 = f(0), z2 = f(z1), z3 = f(z2) and so on. The set of those 
   constants C for which the sequence 
   z1, z2, z3, ... is bounded, i.e. it does not go to infinity, 
   is the  Mandelbrot set (the black set in the figure on the 
   Wikipedia page).

   To visualize the Mandelbrot set, we define an evenly spaced 
   n-by-n pixel grid within a specified square and draw a black pixel 
   if the corresponding point is in the Mandelbrot set and a white 
   pixel  if it is not. 

   For each complex number, Mandelbrot.java computes up to 255 terms 
   in its sequence. If the magnitude ever exceeds 2, then we can 
   conclude that the complex number is not in the set (because it 
   is known that the sequence will surely diverge). 

   Otherwise, we conclude that the complex number is in the set 
   (knowing that our conclusion might be wrong on occasion). 

   Uses Complex.java and mandel.txt

   Usage:
     > compile Mandelbrot.java
     > run Mandelbrot xc yc size
   e.g.
     > run Mandelbrot -0.5 0 2
     > run Mandelbrot 0.10259 -0.641 0.0086
 
*/

import java.io.*;
import java.awt.*;
import java.util.*;


public class Mandelbrot
{
  private static final String COLOR_FNM = "mandel.txt";

  private static final double MAX_MAGNITUDE = 2.0;   // C
  private static final int MAX_ITERS = 255;
  private static final int NUM_PIXELS = 512;


  public static void main(String[] args)
  {
    if (args.length != 3) {
      System.out.println("Usage: java Mandelbrot <xc> <yc> <size>");
      return;
    }
    double xc   = Double.parseDouble(args[0]);
    double yc   = Double.parseDouble(args[1]);
    double size = Double.parseDouble(args[2]);

    Color[] colors = new Color[MAX_ITERS+1];
    boolean isLoaded = loadColors(COLOR_FNM, colors);

    StdDraw.setCanvasSize(512, 512);
    StdDraw.setScale(0, NUM_PIXELS);

    for (int i = 0; i < NUM_PIXELS; i++) {
      for (int j = 0; j < NUM_PIXELS; j++) {
        double x0 = xc - size/2 + size*i/NUM_PIXELS;
        double y0 = yc - size/2 + size*j/NUM_PIXELS;
        Complex z0 = new Complex(x0, y0);  // uses Common Maths

        int idx = mandCount(z0);
        Color color;
        if (isLoaded)
          color = colors[idx];
        else {
          int gray = MAX_ITERS - idx;
          color = new Color(gray, gray, gray);
        }
        StdDraw.setPenColor(color);
        StdDraw.point(i, NUM_PIXELS-1-j);
      }
    }
    System.out.println("Drawing finished");
  } /* main */


  private static boolean loadColors(String fnm, Color[] colors)
  {
    boolean isLoaded = false;
    try {
      Scanner scanner = new Scanner(new File(fnm));
      int i = 0;
      int r, g, b;
      while(scanner.hasNextInt()) {
         r = scanner.nextInt();
         g = scanner.nextInt();
         b = scanner.nextInt();
         colors[i++] = new Color(r,g,b);
      }
      isLoaded = true;
    }
    catch(IOException e)
    {  System.out.println(e);  }

    return isLoaded;
  }  // end of loadColors()


  private static int mandCount(Complex z0)
  /* return number of iterations to check if 
     c = a + ib is in Mandelbrot set
  */
  { Complex z = z0;
    for (int i = 0; i < MAX_ITERS; i++) {
      if (z.abs() > MAX_MAGNITUDE) 
        return i;
      z = z.times(z).plus(z0);
    }
    return MAX_ITERS;
  } /* mandCount */


}  // end of Mandelbrot class
