Фракталы в иррациональных числах. Часть 2

Часть 0: Фракталы в простых числах.
Часть 1: Фракталы в иррациональных числах.

onoh68svrcuwkca6o4vvqi29rfk.png

В статье присутствуют Gif и контрастные картинки. У эпилептиков может случиться эпилептический припадок.

В предыдущей статье мы рассмотрели алгоритм визуализации двоичных последовательностей. Давайте вспомним.

Берем двоичную последовательность. В качестве примера несколько первых бит фрактальной последовательности, рассмотренной в предыдущей статье:

$Q_n=\lfloor n\sqrt{2} \rfloor \; (\textrm{mod} \; 2); \quad n=0,1,2,…$

0100110110010011001001101100

Рисуем квадратное клеточное поле. Расставляем биты у верхней границы. Расстояние между битами — две клетки:

3vxtubpa5pomw81boqfeys7h-0s.png

Для каждого бита рисуем по диагонали пунктирную траекторию (через клетку). Для нулей первый штрих рисуем вправо:

8uak3c2kcfvcipk4vez3rnqmkci.png

Для единиц — влево:

qybwwns59duc_rhivpwajv1xr28.png

Нарисовали траекторию для каждого бита. Получили «бильярдный» паттерн:

oldfp-9y_uyfuxkpv1ufmk-o_ls.png

Идентичный паттерн (без дефекта по диагонали — последовательность бесконечная, мы же ее визуализировали как конечную последовательность) можно получить другим способом. Инвертируем каждый четный бит в последовательности:

0001100011000110011100111001

Далее для каждого бита рисуем вертикальные пунктирные линии:

xctnpbo1piptywhkpj8mtiiq480.png

Расставляем биты слева, рисуем горизонтальные линии:

zekd-jjhpkuwu8yugibhct7xepo.png

Совмещаем:

j_k1yukqogpg9l6wiepor6-ivv4.png

После написания первой статьи, оставались нерешенными два вопроса:

1. Можно ли нарисовать фрактальный паттерн для иррациональных чисел. Можно. Вопрос решили в предыдущей статье. На картинке выше — часть фрактального паттерна для $\sqrt{2}$. Если выделить одну из кривых на этом паттерне:

pgyio36r05qaz3py1dro1ocs4og.png

Получим известную фрактальную кривую — «Fibonacci word fractal».

2. Второй вопрос — можно ли написать алгоритм, закрашивающий паттерн:

ycbjvbgxtnhnfb_ycyhi4umqrek.png

Решением второго вопроса займемся в этой статье. Раскрашивать паттерны будем с помощью ткацкого станка, работу которого сымитируем с помощью JavaScript.

pklrymtwgqpysiq03i1rqxbhvgi.png

На схеме выше — самый простой станок. Он состоит из двух рамок, через которые протянуты нити. Рамки соединены с педалями. При нажатии на одну из педалей, одна из рамок поднимается. Нити, протянутые через эту рамку поднимаются и в получившийся зазор между нитями протягивается поперечная нить. Если четные и нечетные нити протянуть через разные рамки — получается переплетение в шахматном порядке:

vaopldjhktcok_wr00x9p1ilsqm.png

В более сложных станках используется от четырех и больше рамок:

rulstvjmhsxbtke5fvzdl3fhfxe.jpeg
Ashford 4 Shaft Table Loom

Для того, чтобы не запутаться, какую педаль нажимать — составляют схему.

b_fjsw7z4hncysaxpfraihwc6t0.png

В верхней правой части схемы отмечено, через какие рамки проходят нити (схема для ткацкого станка на 8 рамок).
В левом верхнем углу — какие педали зажимать одновременно (каждая педаль связана только со своей рамкой).
В левой нижней части — в каком порядке зажимать педали.
В правой нижней части — какое переплетение мы получим. Если протягивать белую нить через черные — получим монохромный узор.

Сходу «въехать» в принцип может показаться немного затруднительным. На картинке ниже показано, как формируется ткацкий узор:

9ade8fkvfs8gr4khrnsvxnqsw1k.png

Напишем скрипт. Протягивать нити через рамки будем с помощью одномерного массива array2. В одномерный массив array1 запишем очередность зажатия педалей. В array3 (бинарный массив 8×8) запишем, какие педали зажимать одновременно.

q_qrej_i1bqhy9rp-tzjrhkxsl0.png

  for(var i=0;i

Скрипт (работает в Google Chrome).

С помощью нашего импровизированного ткацкого станка мы можем нарисовать самые разнообразные узоры:

hi-8ukwkgz9mkjr3msne7cvs1-8.png

Но так исторически сложилось, что у среднестатистического человека не больше двух ног. Поэтому удобно одновременно зажимать не больше двух педалей. Один из самых популярных шаблонов для ткацкого станка выглядит следующим образом:

zsh0fa1qkdfxoc7wr0iptdw7jim.png

Для 4-х рамок. И его модификация для 8-ми рамок:

v2immeiq-qmwznj9muhxt-skjzi.png

Неожиданно, узоры (или фрагмент узоров) сделанные с помощью этого шаблона, похожи на наши «бильярдные» паттерны. Кроме того, эти узоры получаются закрашенными:

opn7t2e-l_ya_3tjbij1vmqopba.png

Можно научиться подбирать «бильярдные» паттерны для ткацкого станка. Пример:

dliyva3ad-ovjxirqklonlwofq8.png

В начале статьи мы уже видели фрагмент этого паттерна.

Закончим с ткацкими станками и напишем скрипт для визуализации двоичных последовательностей. От одного из массивов можем избавиться — паттерн симметричен по диагонали. Как заполнить оставшийся массив? Элементарно:

txvsvavbel6numycjbyblelgxhe.png

Берем последовательность для $\sqrt{2}$. Создаем массив. В нулевой элемент массива записываем нулевой бит последовательности. Поочередно берем каждый бит последовательности. Если n-й бит = 1 — записываем в массив a[n]=a[n-1]+1. Если бит = 0 — записываем a[n]=a[n-1]-1

$Q_n=\lfloor n\sqrt{x} \rfloor \; (\textrm{mod} \; 2); \quad n=0,1,2,…\\ a_n=\begin{cases}a_{n-1}+1, Q_n=1;\\a_{n-1}-1, Q_n=0\end{cases}$

tcfdyh0bubujzir3a5azmiir6pg.png

  var a=[0];
        for(var i=1;i

Проверяем:

  for(var i=0;i

vmke-s7o5kjgmamfjgbicohx7pu.png

Фактически мы уже получили элементарный фрактал, но продолжим.

Далее разберемся с матрицей:

2jcynct9lxb-kmcukhiawaiy6wo.png

Суммируем $x$ и $y$. Делим по модулю на 4. Если получившийся результат = 0 или 1 — записываем в матрицу true. Для 2 и 3 записываем false. Можем обойтись без матрицы (заранее неизвестно, какие максимальные и минимальные значения принимает a[n]). Суммируем a[x] и a[y]. К получившейся сумме добавляем некоторое число $C$ (чтобы избавиться от тех случаев, когда сумма — отрицательное число). Делим по модулю на 4. Для значений 0 и 1 закрашиваем пиксель с координатами $x$ и $y$.

Окончательный алгоритм занимает всего несколько строк:

  var a=[0];
        for(var i=1;i

Визуализируем наши фрактальные последовательности.

$Q_n=\lfloor n\sqrt{2} \rfloor \; (\textrm{mod} \; 2); \quad n=0,1,2,…$

vlhcqf75d2uvz-dzf_gq-ekjire.png

Можно легко модифицировать скрипт для того, чтобы получить RGB-изображение:

                  q=(a[x]+a[y]+512)%4;
                        /*if(q==0 || q==1) context.fillRect(x, y, 1, 1);*/
                        if(q==0) context.fillStyle = 'rgb(255,0,0)';
                        if(q==1) context.fillStyle = 'rgb(0,255,0)';
                        if(q==2) context.fillStyle = 'rgb(0,0,255)';
                        if(q==3) context.fillStyle = 'rgb(0,0,0)';
                        context.fillRect(x, y, 1, 1);

n5xayhratfrrzopogtfpfv0ps8o.png

Выше мы к сумме a[x]+a[y] прибавляли некоторое число $C$. Если не прибавлять это число — минимальное значение суммы = -8, максимальное = 8 (для $x$ и $y$ от 0 до 750). Если убрать $C$ — в некоторых случаях сумма получается отрицательной и не кратной 4-м и для этих случаев пиксель не закрашивается (остается черным):

                  q=(a[x]+a[y])%4;
                        if(q==0 || q==1) context.fillRect(x, y, 1, 1);

qrq2awxzsudevbd0ebegetlc14q.png

Можно представить это так, будто часть фрактала находится ниже некоторой мнимой границы (ниже этой границы закрашиваются только отрицательные значения кратные 4-м: -4, -8, -12, …).

Можем посмотреть, где находится эта граница:

                  if(a[x]+a[y]>=0) context.fillRect(x, y, 1, 1);

t3g9nkjqukrgtev-mxxnoy0hcb4.png

Вместо деления по модулю, можем сравнить сумму с некоторым определенным значением и тем самым закрасить только один «слой» фрактала. В качестве примера возьмем среднее между минимальным и максимальным значением:

                  q=(a[x]+a[y]);
                        if(q==0) context.fillRect(x, y, 1, 1);

6dlqbhtynhvmqms1qbs6x4wxlzk.png

Если не понятно
rnjj5xr5zkuqgokn9jqjso-nf94.png

Изменяя значения от минимального до максимального, можем посмотреть как меняются «слои» в динамике:

3koqr9dr0zchs0nzp-5mk-gebic.gif

Если не понятно
Настоятельно не рекомендую открывать спойлер, если у вас эпилепсия
h0l_07baubuh8ooiqjeot4bawvu.gif

Кроме того, мы можем «в лоб» сравнить a[x] с a[y] и тоже получить фрактальный паттерн:

if(a[x]==a[y]) context.fillRect(x, y, 1, 1);

shpquxpwl0od4hqt29mss5ionfc.png

Следующая последовательность:

$Q_n=\lfloor n(\sqrt{2}+1) \rfloor \; (\textrm{mod} \; 2); \quad n=0,1,2,…$

Фрактал:

pi9o-92eevg-2qdzi9v5-yzpu1e.png

RGB:

90xejpi_ilozo36ollvbuffahkq.png

Средний слой:

_gpvh3lipfwaasma3ga0xs3-v3g.png

В динамике:

d3d5z80a0o6e3zl0jnad3a5c_uk.gif

$Q_n=\lfloor n\sqrt{3} \rfloor \; (\textrm{mod} \; 2); \quad n=0,1,2,…$

Фрактал:

mmzk_frqkevqofu12zyidj7jhdo.png

RGB:

zhjn-f2cynkm7roudinj4pmzsho.png

Средний слой:

azrloiumcpjfvfzayridhkkmrti.png

В динамике:

nl8zxwcclmggf-g8zetw2kbfn_g.gif

$Q_n=\lfloor n(\sqrt{3}+1) \rfloor \; (\textrm{mod} \; 2); \quad n=0,1,2,…$

Фрактал:

9dpoaefqvluq1ho55to_okwtffg.png

RGB:

p6brqte98ioj_wywqowvticifes.png

Средний слой:

psnm7unaxs59initknhehiew_kk.png

В динамике:

tkrbmpnq0zrs8d7snknoabrx_00.gif

$Q_n=\lfloor n\sqrt{5} \rfloor \; (\textrm{mod} \; 2); \quad n=0,1,2,…$

Фрактал:

c9h62ho7fl-ubfnuwr6dndjwwj4.png

RGB:

zpyvuxtzzuxhoij46yljq5fdnko.png

Средний слой:

mtqexfbg86g7zijebdctaxqclv4.png

В динамике:

nt_su6tiim6grklbsgjrypvmhee.gif

Ну и наш любимый фрактал (часть этого паттерна можно нарисовать с помощью бильярда, с размерами сторон равными числам Фибоначчи):

$Q_n=\lfloor n(\sqrt{5}+1) \rfloor \; (\textrm{mod} \; 2); \quad n=0,1,2,…$

Фрактал:

ocaovlmgdleylvm8ctff0wbmgsk.png

RGB:

8n_b-x71vncy_e6nqa6lzeaatmk.png

Средний слой:

2xmnxpok5j-npsfrkrvfkrrhp0s.png

В динамике:

yg4tsgl97nd6xz34xlgyw0cl8ck.gif

Еще одна последовательность в завершение:

$Q_n=\lfloor n^{2}\sqrt{2} \rfloor \; (\textrm{mod} \; 2); \quad n=0,1,2,…$

Паттерн:

vprziztepwojya_kx2hk6dzvywk.png

RGB:

mpxmptnaygi8fbqzg2d9fq0_xgm.png

Средний слой:

zuxugjchcpv0rdjkkp7asuyndhi.png

В динамике:

cnm5emimypr3_up5qgwrditsids.gif

Другие квадратные корни можно вбить в скрипт. (Можно вбивать дробные значения).
Во втором скрипте можно вбить последовательность вручную.
Еще один скрипт для бильярдов. Координаты мышки — размеры бильярда. Паттерн в левой части формируется из последовательности, полученной с помощью остатков от деления (подробности в предыдущей статье). В правой части — четность $\lfloor n\frac{y}{x}\rfloor$.

© Habrahabr.ru