Система итерированных функций (СИФ) - это совокупность аффинных преобразований над точкой, которая после некоторого чиса итераций достигает аттрактора и будет затем перемещаться, не покидая его.
Отображение точки, находящейся на аттракторе, после каждого преобразования даст картинку фрактала (рис. 1).
Рис. 1. Папоротник из 10'000 точек (окружностей)
В работе приводятся алгоритм и программа на C# пострения 2d-СИФ. Тип проекта - Windows Form Application.
Множество выведенных точек представит результирующий фрактал.
Вывод точек, принадлежащих СИФ-фракталу, выполняется в графическаю область формы – объект System.Windows.Forms.PictureBox.
PictureBox можно вставить в форму, например, найдя PictureBox в списке Toolbox (поле Search Toolbox).
В проекте область графического вывода имеет имя pictureBoxIFS.
Для графического вывода создаются следующие объекты:
Точки отображаются в виде окружностей.
Визуализация образа выполняется в результате определения свойства Image объекта pictureBoxIFS:
pictureBoxIFS.Image = IFSImage;
Код построения СИФ-фрактала:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplicationIFS
{
public partial class FormIFS : Form
{
// Образ для отображения СИФ
public Image IFSImage;
// Графический объект для образа IFSImage
public Graphics IFSGraphics;
// Текущий координаты образа (СИФ-фрактала)
public double x, y;
// Габариты образа в мировой системе координат
public double minX, maxX, minY, maxY;
// Число выводимых точек
public int nm = 10000;
// Число строк в СИФ
public int nCol = 4;
// Датчик случайных чисел
public Random rand = new Random();
//
public FormIFS()
{
InitializeComponent();
int w = pictureBoxIFS.Width, h = pictureBoxIFS.Height;
IFSImage = new Bitmap(w, h);
IFSGraphics = Graphics.FromImage(IFSImage);
// Цвет фона
IFSGraphics.FillRectangle(Brushes.Ivory, 0, 0, w, h); // Or IFSImage.Width, IFSImage.Height
pictureBoxIFS.Image = IFSImage;
}
private int findK(double[] col)
{
// r - число из диапазона [0.0, 1.0], возвращаемое датчиком случайных чисел
double p = 0.0, r = rand.NextDouble();
int j;
// Выбираем случайным образом очередное преобразование СИФ
for (j = 0; j < nCol; j++)
{
p += col[j];
if(r <= p) break;
}
return j;
}
// Аффинные преобразования координат
private void affine(double[] ifs)
{
double x2 = x * ifs[0] + y * ifs[1] + ifs[4];
y = x * ifs[2] + y * ifs[3] + ifs[5];
x = x2;
}
// Копирование массива
private void copyArray(int n, double[,] ifsA, int i, double[] ifsB)
{
for (int j = 0; j < n; j++) ifsB[j] = ifsA[i, j];
}
// Находит простым перебором minX, minY, maxX, maxY - соответственно
// минимальные и максимальные мировые координаты точки изображения
private void fconv(double[,] ifs1_4)
{
double[] ifs = {0, 0, 0, 0, 0, 0}, col = {0, 0, 0, 0};
maxX = -1.0e10; minX = 1.0e10;
maxY = -1.0e10; minY = 1.0e10;
// Ищем начальную точку, используя первое уравнение СИФ
copyArray(6, ifs1_4, 0, ifs);
// Копируем вероятности выбора преобразования в массив col
for (int i2 = 0; i2 < nCol; i2++) col[i2] = ifs1_4[i2, 6];
// Полностью воспроизводим цикл генерации изображения
for(int i = 0; i < nm; i++)
{
int k = findK(col);
// Копируем текущее преобразование в массив ifs и затем вычисляем новые координаты точки
copyArray(6, ifs1_4, k, ifs);
affine(ifs);
// Корректируем наши представления о максимальных и минимальных координатах образа
maxX = Math.Max(x, maxX); minX = Math.Min(x, minX);
maxY = Math.Max(y, maxY); minY = Math.Min(y, minY);
}
}
// Вывод образа (выводится nm точек)
private void render(double[,] ifs1_4)
{
int w = pictureBoxIFS.Width, h = pictureBoxIFS.Height;
int d = 50;
double[] ifs = { 0, 0, 0, 0, 0, 0 }, col = { 0, 0, 0, 0 };
double wX = maxX - minX;
double hY = maxY - minY;
// Копируем вероятности выбора преобразования в массив col
for (int i2 = 0; i2 < nCol; i2++) col[i2] = ifs1_4[i2, 6];
// Цикл генерации изображения
for (int i = 0; i < nm; i++)
{
int k = findK(col);
// Копируем текущее преобразование в массив ifs и затем вычисляем новые координаты точки
copyArray(6, ifs1_4, k, ifs);
affine(ifs);
// Преобразование мировых координат в координаты видового порта
// Начало координат видового порта в нижнем левом углу окна вывода
double xP = (x - minX) / wX;
double yP = (y - minY) / hY;
int iX = Convert.ToInt16(d / 2 + xP * (w - d));
int iY = Convert.ToInt16(h - d / 2 - yP * (h - d));
// For some case
if (iX < 0 || iX > w || iY < 0 || iY > h) continue;
// Используем координаты видового порта
IFSGraphics.FillEllipse(Brushes.Orchid, iX, iY, 4, 4);
}
pictureBoxIFS.Image = IFSImage;
}
private void buttonGo_Click(object sender, EventArgs e)
{
// Массив, задающий СИФ
// Curl
//double[,] ifs1_4 = {{0.04, 0.22, 0.31, -0.03, 0.63, -1.74, 0.13},
// {-0.02, 0.00, -0.32, 0.26, -0.17, -1.35, 0.01},
// {0.79, 0.06, -0.03, 0.73, -0.02, 1.03, 0.74},
// {-0.03, -0.30, 0.35, -0.04, -0.68, -0.94, 0.12}};
// Fern
double[,] ifs1_4 = {{0.0, 0.0, 0.0, 0.16, 0.0, 0.0, 0.01},
{0.85, 0.04, -0.04, 0.85, 0.0,1.6, 0.85},
{0.2, -0.26, 0.23, 0.22, 0.0, 1.6, 0.07},
{-0.15, 0.28, 0.26, 0.24, 0.0, 0.44, 0.07}};
fconv(ifs1_4);
render(ifs1_4);
}
}
}
Больше иформации о фракталах можно получить, например, на 100byte.ru/stdntswrks/fr/fr.html.