Множество Мандельброта

Среди нелинейных фракталов один выделяется особняком — это фрактал, который называется фракталом Мандельброта и представляет собой отображение некоторого множества комплексных точек на плоскости.

Алгоритм построения множества таких точек достаточно прост: берется простейшее итерационное уравнение в комплексных числах с возведением некоторого стартового числа в квадрат и прибавлением константы. Но поскольку, это целое множество точек, каждый раз в ходе итераций по уравнению, константа изменяется в интервале [-2.0 + 2.0i; 2.0 + 2.0i]  — и каждый раз проверяется не уходит ли точка из прямоугольной области 2 * 2: для чего проверяется, меньше ли модуль полученного значения чем 2 (если стартовое значение после некоторого количества итераций дает модуль больше 2, то значит точка с соответствующими координатами не принадлежит множеству Мандельброта и скорее всего траектория этой точки уйдет в бесконечность).

Собственно, наша задача проста — необходимо провести итерации по вот такому уравнению:

zn = (z0 * z0) + c;

где zn - результат очередной итерации, z0 - начальная точка (0.0 + 0.0i), с - константа

и отобразить некоторые точки.

В итоге, получается:

import dgui.all;
import std.complex;

// отрисовка отдельных точек
void drawPoint(Canvas c, int x, int y) {
  Pen p = new Pen(Color(0, 0, 0), 1, PenStyle.solid);
  c.drawLine(p, x, y, x + 1, y + 1);
};


void drawMandelbrotSet(Canvas canv, float step)
{
  for (float i = -2.0; i < 2.0; i += step)
  {
    for (float j = -2.0; j < 2.0; j += step)
    {
      bool isMandelbrotPoint = true;
      auto c = complex(i,j);
      auto z0 = complex(0.0, 0.0);
      for (ubyte k = 0; k < 255; k++)       {         auto zn = (z0 * z0) + c;         if (abs(zn) > 2)
        {
           isMandelbrotPoint = false;
           break;
        }
        z0 = zn;
      }
      if (isMandelbrotPoint)
      {
        auto X = cast(int) (150 - 200 * i);
        auto Y = cast(int) (250 - 200 * j);
        drawPoint(canv, X, Y);
      }
    }
  }
}

class MainForm : Form
{
    public this()
    {
        this.text = "";
        this.size = Size(500, 550);
        this.startPosition = FormStartPosition.centerScreen;
    };

    protected override void onPaint(PaintEventArgs e)
    {

        Canvas c = e.canvas;
        drawMandelbrotSet(c, 0.005);

        super.onPaint(e);
    }
};


int main(string[] args)
{
    return Application.run(new MainForm());
}

Как оно работает: создаем приложение DGui, после чего перегружаем, как обычно, функцию onPaint, подставляя в нее вызов drawMandelbrotSet(c, 0.005), где 0.005 — это приращение для каждого из циклов, кроме цикла с итерациями по самой формуле. Переменная isMandelbrotPoint обозначает принадлежность точки к множеству Мандельброта и установлена в начале в true, так как предполагается изначально, что точка принадлежит множеству, а значение этой переменной изменяется лишь в том случае, если в самом внутреннем цикле модуль комплексного числа превысит число 2 (т.е. в том случае, если точка выйдет в бесконечность).

Одним из не очевидных моментов может быть подключение std.complex, части стандартной библиотеки, которая содержит структуру complex и функцию abs (модуль комплексного числа). Дело в том, что стандартными средствами D, несмотря на нативную поддержку комплексных чисел, нельзя построить комплексное число, используя в качестве аргументов значения действительной и мнимой части, кроме того, эта библиотека содержит еще и уйму полезных предопределенных функций и перегруженных операторов (например, сложение и умножение).

Ну и в конце концов, после компиляции получаем вот такую безрадостную картинку, чем-то напоминающую филейную часть тела:

Добавить комментарий