I want to generate a PNG photo of the Mandelbrot set using Java, the output should be easily found on a google images search.
The set is defined as the following sequence:
z_n+1 = z_n^2 + c
where c
and z
are complex numbers, and z
always has a modulus smaller than 2.
I started by defining a class for complex numbers, which also contains the basic complex operations needed.
public class ComplexNumber {
private double real;
private double imaginary;
public ComplexNumber(double real, double imaginary) {
this.real = real;
this.imaginary = imaginary;
}
public ComplexNumber add(ComplexNumber z1, ComplexNumber z2) {
ComplexNumber sum = new ComplexNumber(0, 0);
sum.real = z1.real + z2.real;
sum.imaginary = z1.imaginary + z2.imaginary;
return sum;
}
public ComplexNumber square(ComplexNumber z) {
ComplexNumber squared = new ComplexNumber(0, 0);
squared.real = Math.pow(z.real, 2) - Math.pow(z.imaginary, 2);
squared.imaginary = 2 * z.real * z.imaginary;
return squared;
}
public double abs() {
double absolute = Math.sqrt(Math.pow(this.real, 2) + Math.pow(this.imaginary, 2));
return absolute;
}
}
I have then defined the Mandelbrot class which gets a number of a complex numbers c (based on pixels) check if these numbers are in the mandelbrot set using the mandelbrot method, and tranfers the output of this method to a color to be displayed.
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Mandelbrot {
public static int mandelbrot(ComplexNumber c, ComplexNumber z, int i, int n) {
if (i < n) {
if (c.abs() > 2.0) {
return i;
} else
return 0;
}
return mandelbrot(c, z.square(z).add(z, c), i, n);
}
// Create the Mandelbrot image, fill it and save it as PNG file.
public static void createMandelbrotImage(int tileSize, int maxRecurse) throws IOException {
int height = 2 * tileSize;
int width = 3 * tileSize;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
ComplexNumber z0 = new ComplexNumber(0, 0);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// Construct a complex number from the pixel coordinates
float xPos = (x + 0.5f - 2 * tileSize) / tileSize;
float yPos = (y + 0.5f - tileSize) / tileSize;
ComplexNumber c = new ComplexNumber(xPos, yPos);
// Check the Mandelbrot condition for this complex number
int mb = mandelbrot(c, z0, 0, maxRecurse);
// Translate the result to number in a reasonable range and use it as color.
double mbl = mb > 0 ? Math.log(mb) / Math.log(maxRecurse) : 0;
image.setRGB(x, y, (int) (mbl * 255));
}
}
// Save the image as PNG
String OS = System.getProperty("os.name").toLowerCase(); // different for win and unix
String filePath = System.getProperty("user.dir") + (OS.indexOf("win") >= 0 ? "\\" : "/") + "mandelbrot.png";
System.out.println("Writing mandelbrot image to: " + filePath);
ImageIO.write(image, "png", new File(filePath));
}
public static void main(String[] args) throws IOException {
createMandelbrotImage(500, 2 ^ 24);
}
}
The problem is that this code always outputs a black empty image, and I don't seem to find the error.
It looks like your recursive mandelbrot function has an incorrect termination condition.
You want the mandelbrot function to return, when either
Also, you are never incrementing i.
So the updated function would look something like:
public static int mandelbrot(ComplexNumber c, ComplexNumber z, int i, int n) {
if (i >= n) {
// mandelbrot function does not diverge after n iterations.
// Returning -1 as a magic value to indicate that the point c is in the mandelbrot set.
// Values may already be outside of the mandelbrot set in the 0th iteration, so returning -1 makes more sense.
return -1;
} else if (z.abs() >= 2.0) {
// mandelbrot function is diverging after i iterations.
return i;
} else {
// recursively call mandelbrot function with an updated z and an incremented i.
return mandelbrot(c, z.squared().add(c), i + 1, n);
}
}
Finally, if you choose to return -1 for a point inside the mandelbrot set, you have to update your color computation to set these points to black.
int mb = mandelbrot(c, z0, 0, maxRecurse);
if (mb == -1) {
image.setRGB(x, y, 0);
} else {
// set the color of your image as usual
}