package com.thealgorithms.others; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; /** * The Mandelbrot set is the set of complex numbers "c" for which the series * "z_(n+1) = z_n * z_n + c" does not diverge, i.e. remains bounded. Thus, a * complex number "c" is a member of the Mandelbrot set if, when starting with * "z_0 = 0" and applying the iteration repeatedly, the absolute value of "z_n" * remains bounded for all "n > 0". Complex numbers can be written as "a + b*i": * "a" is the real component, usually drawn on the x-axis, and "b*i" is the * imaginary component, usually drawn on the y-axis. Most visualizations of the * Mandelbrot set use a color-coding to indicate after how many steps in the * series the numbers outside the set cross the divergence threshold. Images of * the Mandelbrot set exhibit an elaborate and infinitely complicated boundary * that reveals progressively ever-finer recursive detail at increasing * magnifications, making the boundary of the Mandelbrot set a fractal curve. * (description adapted from https://en.wikipedia.org/wiki/Mandelbrot_set ) (see * also https://en.wikipedia.org/wiki/Plotting_algorithms_for_the_Mandelbrot_set * ) */ public class Mandelbrot { public static void main(String[] args) { // Test black and white BufferedImage blackAndWhiteImage = getImage( 800, 600, -0.6, 0, 3.2, 50, false ); // Pixel outside the Mandelbrot set should be white. assert blackAndWhiteImage.getRGB(0, 0) == new Color(255, 255, 255).getRGB(); // Pixel inside the Mandelbrot set should be black. assert blackAndWhiteImage.getRGB(400, 300) == new Color(0, 0, 0).getRGB(); // Test color-coding BufferedImage coloredImage = getImage(800, 600, -0.6, 0, 3.2, 50, true); // Pixel distant to the Mandelbrot set should be red. assert coloredImage.getRGB(0, 0) == new Color(255, 0, 0).getRGB(); // Pixel inside the Mandelbrot set should be black. assert coloredImage.getRGB(400, 300) == new Color(0, 0, 0).getRGB(); // Save image try { ImageIO.write(coloredImage, "png", new File("Mandelbrot.png")); } catch (IOException e) { e.printStackTrace(); } } /** * Method to generate the image of the Mandelbrot set. Two types of * coordinates are used: image-coordinates that refer to the pixels and * figure-coordinates that refer to the complex numbers inside and outside * the Mandelbrot set. The figure-coordinates in the arguments of this * method determine which section of the Mandelbrot set is viewed. The main * area of the Mandelbrot set is roughly between "-1.5 < x < 0.5" and "-1 < * y < 1" in the figure-coordinates. * * @param imageWidth The width of the rendered image. * @param imageHeight The height of the rendered image. * @param figureCenterX The x-coordinate of the center of the figure. * @param figureCenterY The y-coordinate of the center of the figure. * @param figureWidth The width of the figure. * @param maxStep Maximum number of steps to check for divergent behavior. * @param useDistanceColorCoding Render in color or black and white. * @return The image of the rendered Mandelbrot set. */ public static BufferedImage getImage( int imageWidth, int imageHeight, double figureCenterX, double figureCenterY, double figureWidth, int maxStep, boolean useDistanceColorCoding ) { if (imageWidth <= 0) { throw new IllegalArgumentException( "imageWidth should be greater than zero" ); } if (imageHeight <= 0) { throw new IllegalArgumentException( "imageHeight should be greater than zero" ); } if (maxStep <= 0) { throw new IllegalArgumentException( "maxStep should be greater than zero" ); } BufferedImage image = new BufferedImage( imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB ); double figureHeight = figureWidth / imageWidth * imageHeight; // loop through the image-coordinates for (int imageX = 0; imageX < imageWidth; imageX++) { for (int imageY = 0; imageY < imageHeight; imageY++) { // determine the figure-coordinates based on the image-coordinates double figureX = figureCenterX + ((double) imageX / imageWidth - 0.5) * figureWidth; double figureY = figureCenterY + ((double) imageY / imageHeight - 0.5) * figureHeight; double distance = getDistance(figureX, figureY, maxStep); // color the corresponding pixel based on the selected coloring-function image.setRGB( imageX, imageY, useDistanceColorCoding ? colorCodedColorMap(distance).getRGB() : blackAndWhiteColorMap(distance).getRGB() ); } } return image; } /** * Black and white color-coding that ignores the relative distance. The * Mandelbrot set is black, everything else is white. * * @param distance Distance until divergence threshold * @return The color corresponding to the distance. */ private static Color blackAndWhiteColorMap(double distance) { return distance >= 1 ? new Color(0, 0, 0) : new Color(255, 255, 255); } /** * Color-coding taking the relative distance into account. The Mandelbrot * set is black. * * @param distance Distance until divergence threshold. * @return The color corresponding to the distance. */ private static Color colorCodedColorMap(double distance) { if (distance >= 1) { return new Color(0, 0, 0); } else { // simplified transformation of HSV to RGB // distance determines hue double hue = 360 * distance; double saturation = 1; double val = 255; int hi = (int) (Math.floor(hue / 60)) % 6; double f = hue / 60 - Math.floor(hue / 60); int v = (int) val; int p = 0; int q = (int) (val * (1 - f * saturation)); int t = (int) (val * (1 - (1 - f) * saturation)); switch (hi) { case 0: return new Color(v, t, p); case 1: return new Color(q, v, p); case 2: return new Color(p, v, t); case 3: return new Color(p, q, v); case 4: return new Color(t, p, v); default: return new Color(v, p, q); } } } /** * Return the relative distance (ratio of steps taken to maxStep) after * which the complex number constituted by this x-y-pair diverges. Members * of the Mandelbrot set do not diverge so their distance is 1. * * @param figureX The x-coordinate within the figure. * @param figureX The y-coordinate within the figure. * @param maxStep Maximum number of steps to check for divergent behavior. * @return The relative distance as the ratio of steps taken to maxStep. */ private static double getDistance( double figureX, double figureY, int maxStep ) { double a = figureX; double b = figureY; int currentStep = 0; for (int step = 0; step < maxStep; step++) { currentStep = step; double aNew = a * a - b * b + figureX; b = 2 * a * b + figureY; a = aNew; // divergence happens for all complex number with an absolute value // greater than 4 (= divergence threshold) if (a * a + b * b > 4) { break; } } return (double) currentStep / (maxStep - 1); } }