Визуальное представление множества Мандельброта

Я хочу сгенерировать PNG-фотографию набора Мандельброта с помощью Java, результат должен быть легко найден в поиске изображений Google.

Набор определяется как следующая последовательность:

z_n+1 = z_n^2 + c

где c и z — комплексные числа, а z всегда имеет модуль меньше 2.

Я начал с определения класса комплексных чисел, который также содержит основные необходимые сложные операции.

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;
    }
}

Затем я определил класс Мандельброта, который получает ряд комплексных чисел c (на основе пикселей), проверяет, входят ли эти числа в набор Мандельброта, используя метод Мандельброта, и переводит результат этого метода в цвет для отображения.

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);

    }
}

Проблема в том, что этот код всегда выводит черное пустое изображение, и я, кажется, не нахожу ошибку.


person anisgh    schedule 23.06.2019    source источник
comment
Во время отладки вы видите значения, которые, по вашему мнению, должны быть?   -  person Dave Newton    schedule 23.06.2019
comment
Вы начинаете с черного пустого изображения или рисуете черное пустое изображение?   -  person nicomp    schedule 23.06.2019
comment
Я не уверен, какие значения правильные, но я не вижу ничего похожего на правильное.   -  person anisgh    schedule 23.06.2019
comment
Я начинаю с черного пустого изображения и рисую на нем пиксели.   -  person anisgh    schedule 23.06.2019
comment
z0 всегда содержит 0+0i. Это было вашим намерением?   -  person VGR    schedule 23.06.2019
comment
@VGR Установка z0 на 0+0i вполне допустима. Если вы установите z0 равным c, все вычисления будут выполняться всего на одну итерацию вперед: z0 = c → z1 = c² + c или z0 = 0 → z1 = 0² + c → z2 = c² + c.   -  person Palle    schedule 23.06.2019


Ответы (1)


Похоже, что ваша рекурсивная функция Мандельброта имеет неправильное условие завершения.

Вы хотите, чтобы функция Мандельброта возвращалась, когда либо

  • абсолютное значение z превышает 2 или
  • достигается максимальная глубина рекурсии.

Кроме того, вы никогда не увеличиваете i.

Таким образом, обновленная функция будет выглядеть примерно так:

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);
    }
}

Наконец, если вы решите вернуть -1 для точки внутри множества Мандельброта, вам придется обновить вычисление цвета, чтобы сделать эти точки черными.

int mb = mandelbrot(c, z0, 0, maxRecurse);

if (mb == -1) {
    image.setRGB(x, y, 0);
} else {
    // set the color of your image as usual
}
person Palle    schedule 23.06.2019