Дві реалізації системи ітеріруемих функцій
Система ітеріруемих функцій (СІФ, Iterated functions system) - це засіб отримання фрактальних структур.
Найбільш проста СІФ складається з афінних перетворень на площині. (Нагадаємо, що аффінниє перетворення координат - це в загальному випадку суперпозиція масштабування, повороту, паралельного перенесення і дзеркального відображення.)
У загальній вигляді Афінний перетворення на площині задається наступною системою рівнянь:
X '= A * X + B * Y + E
Y '= C * X + D * Y + F
Число систем рівнянь, які використовуються для отримання фрактальної структури, не менше двох. Так для отримання фрактальної решітки (Lattice, рис. 1) беруться наступні чотири системи:
(1, ймовірність вибору 0.25)
X '= 0.3 * X - 0.3 * Y + 1
Y '= 0.3 * X + 0.3 * Y + 1
(2, ймовірність вибору 0.25)
X '= 0.3 * X - 0.3 * Y + 1
Y '= 0.3 * X + 0.3 * Y - 1
(3, ймовірність вибору 0.25)
X '= 0.3 * X - 0.3 * Y - 1
Y '= 0.3 * X + 0.3 * Y + 1
(4, ймовірність вибору 0.25)
X '= 0.3 * X - 0.3 * Y - 1
Y '= 0.3 * X + 0.3 * Y - 1
Мал. 1. Фрактальна решітка (побудована як растровий образ)
Кожна система називається СІФ-перетворенням.
У СІФ застосовуються стискають аффінниє перетворення, тобто такі, в яких коефіцієнт масштабування менше одиниці.
Алгоритм побудови СІФ-фрактала:
- Знайти і зафарбувати початкову точку (X, Y) зображення (алгоритм пошуку початкової точки наведено нижче).
- Вибрати, використовуючи відомі ймовірності вибору, одне з СИФ-перетворень, знайти координати (X ', Y') нової точки зображення і зафарбувати знайдену точку.
- Прийняти X = X 'і Y = Y'.
- Повторити п.п. 2 і 3 алгоритму заданий число раз.
В якості початкової можна брати будь-яку належить зображенню точку. Наведений нижче алгоритм пошуку початкової точки забезпечує її вибір в так званому аттракторе. тобто в області, що належить зображенню фрактала. Усі наступні точки, знайдені за вищенаведеним алгоритмом побудови СІФ-фрактала, блукають в області аттрактора, що не переміщаючись в області, які не належать зображенню.
Алгоритм пошуку початкової точки:
- Взяти довільну точку (X, Y) на площині.
- Вибрати, використовуючи відомі ймовірності вибору, одне з СИФ-перетворень і знайти координати (X ', Y') наступної точки.
- Прийняти X = X 'і Y = Y'.
- Повторити п.п. 2 і 3 алгоритму заданий число раз (наприклад, 100).
- Взяти в якості початкової точки останню крапку.
Розглядаючи кожне СІФ-перетворення в окремо, можна помітити, що незалежно від положення початкової точки після кількох ітерацій точка перестає рухатися. Точка зупинки називається нерухомою точкою.
Нерухома точка кожного перетворення входить до складу аттрактора. Тому за початкову точку при побудові фрактала можна взяти нерухому точку, наприклад, першого перетворення.
СІФ можна уявити більш компактно у вигляді такої таблиці:
В останньому стовпці для кожного СІФ-перетворення вказується ймовірність його вибору при пошуку черговий точки зображення фрактала.
У прикладі ці ймовірності рівні, що, втім, не характерно.
Наведений нижче код забезпечує висновок показаної на рис. 1 фрактальної решітки.
global ifs, xP, yP, ifsCnt
global xI, yI, xA, yA
-- Обчислює координати чергової точки зображення фрактала
-- Параметри x і y передаються по посиланню
fn affine col x y = (
t = x * col [1] + y * col [2] + col [5]
y = x * col [3] + y * col [4] + col [6]
x = t
)
-- Знаходить початкову точку зображення
fn sPoint = (
-- Беремо першу СІФ-перетворення
col = for k = 1 to 6 collect ifs [k]
-- Після 100 ітерацій xP і yP - це координати початкової точки
for k = 1 to 100 do affine col xP yP
)
-- Вибирає, використовуючи датчик випадкових чисел і ймовірності вибору,
-- СІФ-перетворення для обчислення координат черговий точки зображення
fn findK12 k11 k22 = (
-- Отримуємо випадкове число з діапазону 0.0 - 1.0
r = random 0.0 1.0
p = 0.0
-- j2 - число рядків в таблиці СІФ-перетворень
j2 = ifsCnt / 7
j3 = j2 - 1
for j = 1 to j3 do (
p + = ifs [7 * j]
if r <= p then (j2 = j; exit)
)
-- Індекси початку і кінця вибраного рядка таблиці СІФ-перетворень
k11 = 7 * (j2 - 1) + 1
k22 = k11 + 5
)
-- Знаходить над ділянкою фрактала і встановлює видовий порт в цих межах
-- Далі ці межі використовуються для масштабування зображення
-- і перерахунку координат його поточної точки
fn fConv nPAll = (
local k1, k2
xA = yA = -1e3
xI = yI = 1e3
sPoint ()
for k = 1 to nPAll do (
findK12 k1 k2
col = for m = k1 to k2 collect ifs [m]
affine col xP yP
xA = amax # (xP, xA); yA = amax # (yP, yA)
xI = amin # (xP, xI); yI = amin # (yP, yI)
)
viewport.ZoomToBounds false [xI, 0, yI] [xA, 0, yA]
)
-- Формує фрактальное зображення з nPAll точок
fn showFrctB = (
-- Масив чотирьох СІФ-преоразованій, які задають фрактальную грати
-- Відображає таблицю СІФ-преоразованій
ifs = # (0.3, -0.3, 0.3, 0.3, 1, 1, 0.25,
0.3, -0.3, 0.3, 0.3, 1, -1, 0.25,
0.3, -0.3, 0.3, 0.3, -1, 1, 0.25,
0.3, -0.3, 0.3, 0.3, -1, -1, 0.25)
ifsCnt = ifs.Count
-- nPAll - число точок в зображенні фрактала
nPAll = 10000
xP = yP = 1.0
fConv nPAll
bSz = 200
-- Створюємо растровий образ розміру 200 * 200 пікселів
btmp = bitmap bSz bSz color: white
-- Коефіцієнти для перерахунку координат точки зображення
-- Зображення вписується в заданий растровий образ
c = 0.8
cx = c * bSz / (xA - xI)
cy = c * bSz / (yA - yI)
d = 0.5 * (1.0 - c) * bSz
clr = color 0 0 255
k1 = k2 = 0
-- Отримуємо nPAll точок зображення
-- і фіксуємо їх у вигляді синіх пікселів растрового образу btmp
-- Початок координат растрового образа в його лівому верхньому кутку
for k = 1 to nPAll do (
-- Вибираємо СІФ-перетворення
findK12 k1 k2
col = for m = k1 to k2 collect ifs [m]
-- Знаходимо координати чергової точки зображення
affine col xP yP
xb = d + cx * (xP - xI)
yb = bSz - (d + cy * (yP - yI))
setPixels btmp [xb, yb] # (clr)
)
-- Показуємо результат (див. Рис. 1)
display btmp
)
showFrctB ()
Запуск програми виконується в 3ds Max в наступному порядку:
Для отримання іншого зображення досить визначити масив ifs іншими відповідними даними. Ці дані можна взяти з коду, наведеного в нижерасположенной розділі "Колекція Particle Flow-фракталів". Так, якщо масив ifs визначити даними 8-го малюнка
ifs = # (0.824074, 0.281482, -0.212346, 0.864198, -1.882290, -0.110607, 0.787473,
0.088272, 0.520988, -0.463889, -0.377778, 0.785360, 8.095795, 0.212527)
то програма створить растровий образ фрактального дракона (рис. 2).
Мал. 2. Після заміни масиву ifs
При формуванні СІФ-фрактала з частинок Particle Flow виникають додаткові можливості по управлінню зображенням, обумовлені наявними в Particle Flow ресурсами.
Нижче слід код, що генерує СІФ-решітку з хрестоподібних частинок (рис. 3).
Мал. 3. Фрактальна решітка (побудована з частинок)
На відміну від попереднього варіанту висновок, що виконується в proceed-обробнику оператора script_Operator системи частинок Particle Flow, направляється в видове вікно. При цьому визначається позиція тільки що народжених частинок. Позиція старих частинок залишається незмінною.
Код, як і в разі реєстрового способу, заснований на вищенаведених алгоритмах побудови СІФ-зображення.
global ifs, nPPrev, xP, yP, ifsCnt
-- підготовка сцени
function tSttngs = (
delete $ *
viewport.SetLayout # layout_4
viewport.ActiveViewport = 2
viewport.SetType #view_front
viewport.SetGridVisibility 2 false
sliderTime = 0f
animationRange = interval 0f 50f
timeConfiguration.RealTimePlayback = false
timeConfiguration.PlaybackLoop = false
)
global ifs, xP, yP, ifsCnt
global xI, yI, xA, yA
-- Обчислює координати чергової точки зображення фрактала
-- Параметри x і y передаються по посиланню
fn affine col x y = (
t = x * col [1] + y * col [2] + col [5]
y = x * col [3] + y * col [4] + col [6]
x = t
)
-- Знаходить початкову точку зображення
fn sPoint = (
-- Беремо першу СІФ-перетворення
col = for k = 1 to 6 collect ifs [k]
-- Після 100 ітерацій xP і yP - це координати початкової точки
for k = 1 to 100 do affine col xP yP
)
-- Вибирає, використовуючи датчик випадкових чисел і ймовірності вибору,
-- СІФ-перетворення для обчислення координат черговий точки зображення
fn findK12 k11 k22 = (
-- Отримуємо випадкове число з діапазону 0.0 - 1.0
r = random 0.0 1.0
p = 0.0
-- j2 - число рядків в таблиці СІФ-перетворень
j2 = ifsCnt / 7
j3 = j2 - 1
for j = 1 to j3 do (
p + = ifs [7 * j]
if r <= p then (j2 = j; exit)
)
-- Індекси початку і кінця вибраного рядка таблиці СІФ-перетворень
k11 = 7 * (j2 - 1) + 1
k22 = k11 + 5
)
-- Знаходить над ділянкою фрактала і встановлює видовий порт в цих межах
-- Далі ці межі використовуються для масштабування зображення
-- і перерахунку координат його поточної точки
fn fConv nPAll = (
local k1, k2
xA = yA = -1e3
xI = yI = 1e3
sPoint ()
for k = 1 to nPAll do (
findK12 k1 k2
col = for m = k1 to k2 collect ifs [m]
affine col xP yP
xA = amax # (xP, xA); yA = amax # (yP, yA)
xI = amin # (xP, xI); yI = amin # (yP, yI)
)
viewport.ZoomToBounds false [xI, 0, yI] [xA, 0, yA]
)
fn showFrct = (
-- Масив чотирьох СІФ-преоразованій, що задає фрактальную грати
-- Відображає таблицю СІФ-преоразованій
ifs = # (0.3, -0.3, 0.3, 0.3, 1, 1, 0.25,
0.3, -0.3, 0.3, 0.3, 1, -1, 0.25,
0.3, -0.3, 0.3, 0.3, -1, 1, 0.25,
0.3, -0.3, 0.3, 0.3, -1, -1, 0.25)
ifsCnt = ifs.Count
-- nPAll - число точок в зображенні фрактала
local nPAll = 10000, emS = 0.8 * 160 * 50
xP = yP = 1.0
fConv nPAll
nPPrev = 1
-- Створюємо джерело частинок з операторами народження (Birth)
-- і відображення (DisplayParticles) частинок
-- Також джерело частинок має оператор script_Operator,
-- забезпечує знаходження координат новонароджених частинок
pF = PF_Source enable_Particles: true emitter_Type: 0 \
quantity_Viewport: 100 show_Logo: off show_Emitter: off
particleFlow.BeginEdit ()
opBth = birth emit_Start: 0 emit_Stop: emS amount: nPAll
-- Відображаємо в видовому порте хрестоподібну частку (type = 2)
opDP = displayParticles color: blue type: 2
opSO = script_Operator proceed_Script: "
-- Канали передачі даних
on channelsUsed pCont do (
pCont.UseTime = true
pCont.UsePosition = true
)
on proceed pCont do (
k1 = k2 = 0
nP = pCont.NumParticles ()
-- Параметр nPPrev введений для скорочення перебору
for k = nPPrev to nP do (
pCont.ParticleIndex = k
-- Беремо тільки нові частинки
if pCont.ParticleNew do (
-- Вибираємо СІФ-перетворення
findK12 k1 k2
col = for m = k1 to k2 collect ifs [m]
-- Знаходимо координати частинки (черговий точки зображення)
affine col xP yP
pCont.ParticlePosition = [xP, 0, yP]
)
)
nPPrev = nP
) "
evn = event ()
particleFlow.EndEdit ()
evn.AppendAction opBth
evn.AppendAction opDP
evn.AppendAction opSO
pF.AppendInitialActionList evn
playAnimation ()
)
-- готуємо сцену
tSttngs ()
-- будуємо зображення
showFrct ()
Додамо тепер в сцену бомбу, яка вибухає на 10-му кадрі, і вибух триває 25 кадрів:
pb = PBomb symmetry: 0 chaos: 10 start_Time: 10f lasts_For: 25f strength: 0.1
Для її обліку додамо в джерело частинок наступний оператор Force:
opFrc = force force_Space_Warps: # (pb) influence: 25
Наступний рядок коду помістимо перед методом AppendInitialActionList:
Спостережуваний результат наведемо на рис. 4.
Мал. 4. Решітка з бомбою (40-й кадр анімації)
Наведений нижче код будує фрактальні об'єкти на основі системи ітеріруемих функцій (СІФ), а також фрактальні множини Мандельброта і Жюліа (рис. 5 і 6).
Мал. 5. Безліч Мандельброта
Мал. 6. Безліч Жюліа
Мал. 7. Керуючий діалог
На рис. 8 наведені два побудованих з частинок СІФ-фрактала.
Мал. 8. СІФ-фрактали Flake і Arrow
Число варіантів реалізації СІФ-зображення не обмежується наведеними. Крім того, в деяких випадках можна управляти порядком виведення точок зображення, попередньо записавши їх координати в масив. Далі масив можна впорядкувати, наприклад, по Y-координату і виконати послідовний висновок відсортованих точок. Такий прийом, зокрема, вжито в роботі "Пори року. Осінь" конкурсу "Жива картина" для відображення зростаючого дерева.