Фрактал — различия между версиями

Материал из Department of Theoretical and Applied Mechanics
Перейти к: навигация, поиск
(Направление исследований)
(Два режима работы программы)
 
(не показано 36 промежуточных версий 3 участников)
Строка 1: Строка 1:
Программа позволяет строить фрактальные и простые структуры при заданных начальных условиях.
+
Программа позволяет строить фрактальные и простые структуры при заданных начальных условиях c помощью дробно-линейного <i><b>[https://ru.wikipedia.org/wiki/Отображение_Пуанкаре отображения Пуанкаре]</b></i>.
 
==Начальные условия и принцип работы==
 
==Начальные условия и принцип работы==
 
В системе координат Oxy дан единичный квадрат, который отображается на экран в масштабе 1000:1
 
В системе координат Oxy дан единичный квадрат, который отображается на экран в масштабе 1000:1
 
<br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/coordinat2.jpg| width= 382 | height = 362}}
 
<br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/coordinat2.jpg| width= 382 | height = 362}}
<br>Пользователю предлагается задать коэффициенты рекурсивной функции вычисления новых координат и координаты "x" и "y" начальной точки, количество итераций, которое произведет программа и способ вычисления новых точек. Начальная точка задается кликом левой кнопки мыши по холсту.
+
<br>Программа получает начальную точку с координатами "x"(0<x<1) и "y"(0<y<1) и строит N точек, координаты которых вычисляются по формулам:
Программа получает на вход "x"(0<x<1) и "y"(0<y<1) и строит N точек, координаты которых вычисляются по формулам:
 
 
<br>
 
<br>
 
\begin{equation}
 
\begin{equation}
 
\begin{cases}
 
\begin{cases}
x_{k} = F(a_{11}*x_{k-1} + a_{12}*y_{k-1})\\
+
x_{k+1} = F(a_{11}x_{k} + a_{12}y_{k})\\
y_{k} = F(a_{21}*x_{k} + a_{22}*y_{k-1})
+
y_{k+1} = F(a_{21}x_{k+1} + a_{22}y_{k})
 
\end{cases}
 
\end{cases}
 
\end{equation}
 
\end{equation}
<br>где <math>F</math> - функция<i>  [https://ru.wikipedia.org/wiki/Дробная_часть дробной части]</i>. Сразу можно сказать, что все точки, вычисленные по этим формулам, попадут в единичный квадрат (вследствие использования функции дробной части).
+
<div align = "left">где <math> a_{11}, a_{12}, a_{21}, a_{22} </math> - константы, <math>F</math> - функция<i>  [https://ru.wikipedia.org/wiki/Дробная_часть дробной части]</i>.</div>
 +
Сразу можно сказать, что все точки, вычисленные по этим формулам, попадут в единичный квадрат (вследствие использования функции дробной части).
 
==Направление исследований==
 
==Направление исследований==
Используя функцию <math>F</math>, программа строит <i><b>регулярные</b></i> и <i><b>нерегулярные</b></i> области:
+
Если убрать функцию <math>F</math>, то формулы будут эквиваленты системе дифференциальных уравнений, описывающих отображение точек плоскости на себя с течением времени ([https://ru.wikipedia.org/wiki/Отображение_Пуанкаре отображение Пуанкаре]). То есть, мы получим динамическую систему с дискретным временем.
<br>1. <i><b>Регулярной</b></i> будем считать область, которая состоит из малого количества отдельных элементов (например: два больших эллипса).
+
\begin{cases}
<br>2. <i><b>Нерегулярной</b></i> будем считать область, которая состоит из большого количества малых элементов (например: множество малых эллипсов в промежутках между регулярными областями).
+
\frac{dx}{dt} = b_{11}x + b_{12}y\\
<br>Ниже изображен процесс вычисления точек и их отображения в случае нерегулярной и регулярной области при заданных коэффициентах (эксперимент 1):
+
\frac{dy}{dt} = b_{21}x + b_{22}y
 +
\end{cases}
 +
<div align = "left">где <math> b_{11}, b_{12}, b_{21}, b_{22} </math> - константы.</div>
 +
<div align = "center"><br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/interpritate.png| width= 364 | height = 377}}</div>
 +
<br>Используя функцию <math>F</math>, программа строит <i><b>регулярные</b></i> и <i><b>нерегулярные</b></i> области:
 +
<br>1. <i><b>Регулярной</b></i> будем называть область, состоящую из малого количества отдельных элементов (например: два больших эллипса).
 +
<br>2. <i><b>Нерегулярной</b></i> будем называть область, состоящую из большого количества малых элементов (например: множество малых эллипсов в промежутках между регулярными областями).
 +
<br>Ниже изображен процесс вычисления точек и их отображения в случае нерегулярной и регулярной области при одних и тех же коэффициентах (эксперимент 1):
 
\begin{equation}  a_{11} = 1, a_{12} = 1, a_{21} = -0.9, a_{22} = 1.\end{equation}
 
\begin{equation}  a_{11} = 1, a_{12} = 1, a_{21} = -0.9, a_{22} = 1.\end{equation}
 +
<br>1. Анимация №1
 +
<br><math> x_{0} = 0.613, y_{0} = 0.582</math>
 
<br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/reg_obl-1.gif| width= 454 | height = 369}}
 
<br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/reg_obl-1.gif| width= 454 | height = 369}}
{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/nereg_obl2.gif| width= 450 | height = 369}}
+
{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/edinich-1.png| width= 387 | height = 218}}
<br>В данных примерах использовались начальные условия: <br>1. \begin{equation}  x_{0} = 0.613, y_{0} = 0.582 \end{equation} Результат: регулярная область фрактала.
+
<br>Результат: регулярная область фрактала.
<br>2. \begin{equation}  x_{0} = 0.46, y_{0} = 0.63\end{equation} Результат: нерегулярная область фрактала.
+
<br>2. Анимация №2
<br><i>Синим</i> цветом обозначены точки, вычисленные по рекуррентным формулам <u>без</u> использования функции <math>F</math>.  
+
<br><math>x_{0} = 0.46, y_{0} = 0.63</math>
<br><i>Красным</i> цветом обозначены точки, вычисленные по рекуррентным формулам <u>с</u> использованием функции <math>F</math> (формулы даны выше). Данная на этой странице программа вычисляет и отображает лишь эти точки.
+
<br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/nereg_obl2.gif| width= 450 | height = 369}}
<br> Данные примеры призваны показать, что паттерн получаемого фрактала подобен кривой второго порядка, которую образуют точки, вычисленные по рекуррентным формулам без использования функции дробной части <math>F</math>.
+
<br>Результат: нерегулярная область фрактала.
 +
<font color = "blue"><br><i>Синим</i></font> цветом обозначены точки, вычисленные по рекуррентным формулам <u>без</u> использования функции <math>F</math>.  
 +
<font color = "red"><br><i>Красным</i></font> цветом обозначены точки, вычисленные по рекуррентным формулам <u>с</u> использованием функции <math>F</math> (формулы даны выше). Программа вычисляет и отображает лишь эти точки.
  
 +
<br><b><i>Вывод 1</i></b>: в зависимости от выбора начальной точки мы получаем дополняющие друг друга области одного фрактала, соответствующего заданным коэффициентам. Интерес состоит в том, чтобы выделять нерегулярные(большие) области фрактала, отсеивая регулярные так, чтобы не зависеть от "ZOOM'а".
 +
<br><b><i>Примечание</i></b>. Один из алгоритмов отыскания нерегулярных областей осуществлен в данной программе: <b>http://tm.spbstu.ru/Фрактал(2-ая_версия_программы)</b>.
 +
 +
<br><b><i>Вывод 2</i></b>: паттерн получаемого фрактала подобен кривой второго порядка, которую образуют точки, вычисленные по рекуррентным формулам без использования функции дробной части <math>F</math>. Зная как связаны коэффициенты рекуррентных формул с коэффициентами соответствующей системы дифференциальных уравнений, можно узнать тип особой точки и вид паттерна фрактала (эллипс, гипербола, спираль..).
 
==Пример работы программы==
 
==Пример работы программы==
 
Зададим такие же коэффициенты, как в примерах выше (эксперимент №1 в списке программы):
 
Зададим такие же коэффициенты, как в примерах выше (эксперимент №1 в списке программы):
 
<br>\begin{equation}  a_{11} = 1, a_{12} = 1, a_{21} = -0.9, a_{22} = 1.\end{equation}
 
<br>\begin{equation}  a_{11} = 1, a_{12} = 1, a_{21} = -0.9, a_{22} = 1.\end{equation}
<br>Получив несколько начальных точек, программа построит такую картину при данных коэффициентах (картина отзеркалена относительно оси Ox для одинаковой направленности осей):
+
<br>Получив несколько начальных точек, программа построит такую картину при данных коэффициентах:
 
<br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/Ellips2.jpg| width= 212 | height = 209}}
 
<br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/Ellips2.jpg| width= 212 | height = 209}}
<br>Другие примечательные наборы начальных условий можно посмотреть, выбрав номер эксперимента.
+
<br>Для просмотра других примечательных наборов начальных условий следует выбрать номер эксперимента в списке программы.
==Задание коэффициентов==
+
==Инструментарий программы==
Коэффициенты \begin{equation}a_{11},a_{12},a_{21},a_{22}\end{equation} можно задать с помощью полей ввода:
+
Для дальнейшего использования результатов программы в докладах/исследованиях/научных работах и повторного воспроизведения интересных результатов, программа отображает начальные значения "x" и "y",  введенные пользователем последним кликом по холсту, рядом с информацией о рассматриваемой области:
<br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/koeff.png| width= 487 | height = 61}}
+
<br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/obla.png| width= 805 | height = 29}}
 +
<br><div align ="left">Коэффициенты <math>a_{11},a_{12},a_{21},a_{22}</math> задаются с помощью полей ввода:</div>
 +
<br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/koeffs.png| width= 197 | height = 45}}
 +
<br>Начальные точки задаются с помощью клика по холсту или с помощью полей ввода:
 +
<br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/n.y2.png| width= 660 | height = 25}}
 +
<br>Количество расчетов по рекуррентным формулам для каждой начальной точки:
 +
<br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/iters.png| width= 346 | height = 25}}
 +
<br>Чтобы посмотреть заложенные в программу примечательные наборы начальных данных, следует выбрать номер эксперимента:
 +
<br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/expire.png| width= 299 | height = 25}}
 +
<br>Чтобы скачать полученный рисунок, обновить рисунок с учетом изменения количества итераций, или отчистить холст, следует воспользоваться следующими кнопками:
 +
<br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/buttons.png| width= 472 | height = 43}}
 
==Два режима работы программы==
 
==Два режима работы программы==
 
Данная программа предусматривает два режима работы:
 
Данная программа предусматривает два режима работы:
 
<br>1) Режим задания начальных данных (стоит по умолчанию). Кликом мыши по холсту добавляем начальные данные.
 
<br>1) Режим задания начальных данных (стоит по умолчанию). Кликом мыши по холсту добавляем начальные данные.
<br>2) Режим "ZOOM'а". Включается нажатием на соответствующий "checkbox". Позволяет подробнее рассмотреть уже полученный рисунок.
+
<br>2) Режим "ZOOM'а". Включается нажатием на соответствующий "checkbox", или с помощью численного задания области рассмотрения. Позволяет подробнее рассмотреть полученный рисунок.
 
<br>Чтобы программа лучше прорисовала картину в режиме "ZOOM", необходимо задать большее количество точек в поле задания количества итераций, используя при этом кнопку "Обновить рисунок"
 
<br>Чтобы программа лучше прорисовала картину в режиме "ZOOM", необходимо задать большее количество точек в поле задания количества итераций, используя при этом кнопку "Обновить рисунок"
{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/Fractals25_kopia21_01_21.html | width =1500 | height = 1228| border = 0}}
+
{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/Fractals25_kopia1_03_21.html | width =1500 | height = 1250| border = 0}}
  
==Другая версия программы==
 
<br><b>http://tm.spbstu.ru/Фрактал(2-ая_версия_программы)
 
 
==Код программы==
 
==Код программы==
 
<div class="mw-collapsible mw-collapsed">
 
<div class="mw-collapsible mw-collapsed">
Строка 83: Строка 106:
 
var y_oldmin = 0;
 
var y_oldmin = 0;
 
var y_oldmax = scale;
 
var y_oldmax = scale;
 +
var x_relativemin = 0;
 +
var x_relativemax = scale;
 +
var y_relativemin = 0;
 +
var y_relativemax = scale;
 
var intermid;
 
var intermid;
 
var imageData = ctx.createImageData(w,h);
 
var imageData = ctx.createImageData(w,h);
 
var imageData2;
 
var imageData2;
 
var upd = false;
 
var upd = false;
x_minim.innerHTML = x_min.toFixed(2);
 
    y_minim.innerHTML = y_min.toFixed(2);
 
x_maxim.innerHTML = x_max.toFixed(2);
 
y_maxim.innerHTML = y_max.toFixed(2);
 
 
 
// заполняем холст непрозрачными белыми пикселями
+
x_minim.onchange = function () {
 +
x_min = parseFloat(document.getElementById('x_minim').value);
 +
z = 1/(x_max - x_min);
 +
z2 = 1;
 +
y_max = y_min + x_max - x_min;
 +
x_relativemin = 0;
 +
x_relativemax = scale;
 +
y_relativemin = 0;
 +
y_relativemax = scale;
 +
}
 +
x_maxim.onchange = function () {
 +
x_max = parseFloat(document.getElementById('x_maxim').value);
 +
z = 1/(x_max - x_min);
 +
z2 = 1;
 +
y_max = y_min + x_max - x_min;
 +
x_relativemin = 0;
 +
x_relativemax = scale;
 +
y_relativemin = 0;
 +
y_relativemax = scale;
 +
}
 +
y_minim.onchange = function () {
 +
y_min = parseFloat(document.getElementById('y_minim').value);
 +
z = 1/(x_max - x_min);
 +
z2 = 1;
 +
y_max = y_min + x_max - x_min;
 +
x_relativemin = 0;
 +
x_relativemax = scale;
 +
y_relativemin = 0;
 +
y_relativemax = scale;
 +
}
 +
 +
// заполняем холст непрозрачными белыми пикселями для ускорения последующего рисования
 
for (i = 0; i<1000; i++) {
 
for (i = 0; i<1000; i++) {
 
for (j = 0; j<1000; j++) {
 
for (j = 0; j<1000; j++) {
Строка 117: Строка 171:
 
document.body.removeChild(link);
 
document.body.removeChild(link);
 
}
 
}
update.onclick = function () { clearcanv(); upd = true; control(); }
+
update.onclick = function () { clearcanv(); upd = true;
 +
if ((document.getElementById('x_o') != 0 )||(document.getElementById('y_o') != 0)){
 +
r = Math.floor(Math.random()*256);
 +
g = Math.floor(Math.random()*256);
 +
b = Math.floor(Math.random()*256);
 +
RGB.push(r);
 +
RGB.push(g);
 +
RGB.push(b);
 +
X.push(document.getElementById('x_o').value); Y.push(document.getElementById('y_o').value);
 +
}
 +
control();
 +
}
 
a11.onchange = function() {
 
a11.onchange = function() {
 
a_11 = parseFloat(document.getElementById('a11').value);
 
a_11 = parseFloat(document.getElementById('a11').value);
Строка 143: Строка 208:
 
if (!zoom.checked) {
 
if (!zoom.checked) {
 
var rect = cnv.getBoundingClientRect();
 
var rect = cnv.getBoundingClientRect();
console.log((event.clientX - rect.left)/scale,(event.clientY - rect.top)/scale);
 
 
if (z != 1) {
 
if (z != 1) {
 
z2 = x_max - x_min;
 
z2 = x_max - x_min;
Строка 159: Строка 223:
 
} else {
 
} else {
 
clearcanv ();
 
clearcanv ();
some_span.innerHTML = "";
 
z = 1;
 
z2 = 1;
 
RGB = [];
 
X = [];
 
Y = [];
 
 
r = Math.floor(Math.random()*256);
 
r = Math.floor(Math.random()*256);
 
g = Math.floor(Math.random()*256);
 
g = Math.floor(Math.random()*256);
 
b = Math.floor(Math.random()*256);
 
b = Math.floor(Math.random()*256);
ctx.beginPath();
 
ctx.arc(x*scale,y*scale,3,0,2*Math.PI);
 
ctx.strokeStyle = 'blue';
 
ctx.stroke();
 
 
}
 
}
 
X.push(x);
 
X.push(x);
Строка 234: Строка 288:
 
}
 
}
 
z = z*scale/(x_relativemax - x_relativemin);
 
z = z*scale/(x_relativemax - x_relativemin);
some_span.innerHTML = "Увеличение в "+z.toFixed(2)+" раз";
+
some_span.innerHTML = "Увеличение в "+z.toFixed(1)+" раз";
 
clearcanv ();
 
clearcanv ();
 
move = false;
 
move = false;
 
control();
 
control();
 
}
 
}
x_minim.innerHTML = x_min.toFixed(2);
+
 
y_minim.innerHTML = y_min.toFixed(2);
 
x_maxim.innerHTML = x_max.toFixed(2);
 
y_maxim.innerHTML = y_max.toFixed(2);
 
 
}
 
}
  
Строка 285: Строка 336:
 
x = X[m];
 
x = X[m];
 
y = Y[m];
 
y = Y[m];
 +
x_s.innerHTML = x; y_s.innerHTML = y;
 
r = Number(RGB[m*3]);
 
r = Number(RGB[m*3]);
 
g = Number(RGB[m*3+1]);
 
g = Number(RGB[m*3+1]);
Строка 295: Строка 347:
 
}
 
}
 
} else {
 
} else {
 +
x_s.innerHTML = x; y_s.innerHTML = y;
 
for (j = 0;j<=N; j++){
 
for (j = 0;j<=N; j++){
 
coord();
 
coord();
Строка 301: Строка 354:
 
}
 
}
 
ctx.putImageData(imageData,0,0);
 
ctx.putImageData(imageData,0,0);
+
document.getElementById('x_minim').value = x_min;
 +
document.getElementById('y_minim').value = y_min;
 +
document.getElementById('x_maxim').value = x_max;
 
}
 
}
  
Строка 313: Строка 368:
 
z2 = 1;
 
z2 = 1;
 
x_min = 0; y_min = 0; x_max = 1; y_max = 1; x_oldmin = 0; y_oldmin = 0; x_oldmax = scale; y_oldmax = scale;
 
x_min = 0; y_min = 0; x_max = 1; y_max = 1; x_oldmin = 0; y_oldmin = 0; x_oldmax = scale; y_oldmax = scale;
if (N_exp == 1) {x = 0.31; y = 0.32;  a_11 = 1; a_12 = 0.5;     a_21 = -0.5; a_22 = 1; }
+
if (N_exp == 1) {X.push(0.46); Y.push(0.63); X.push(0.613); Y.push(0.582); a_11 = 1; a_12 = 1;     a_21 = -0.9; a_22 = 1; }  
if (N_exp == 2) {x = 0.46; y = 0.63; a_11 = 1; a_12 = 1;     a_21 = -0.9; a_22 = 1; }  
+
if (N_exp == 2) {X.push(0.31); Y.push(0.32); a_11 = 1; a_12 = 0.5;     a_21 = -0.5; a_22 = 1; }
if (N_exp == 3) {x = 1/4; y = 1/4; a_11 = 1;     a_12 = 0.01; a_21 = 0.01; a_22 = -1; } 
+
if (N_exp == 3) {X.push(0.69); Y.push(0.23); a_11 = 1;  a_12 = 0.1296;     a_21 = -0.1296; a_22 = 1; }
if (N_exp == 4) {x = 1/2; y = 1/2; a_11 = 1;     a_12 = 0.32; a_21 = 0.32; a_22 = -1; }
+
if (N_exp == 4) {X.push(0.15); Y.push(0.63); a_11 = -0.9899924966004454;  a_12 = 0.1411200080598672;     a_21 = -0.1411200080598672; a_22 = -0.9899924966004454; }
if (N_exp == 5) {x = 1/2; y = 1/2; a_11 = 0.9;  a_12 = 0.1;     a_21 = -0.1; a_22 = 1.2; }
 
if (N_exp == 6) {x = 1/4; y = 1/4; a_11 = Math.cos(angle); a_12 = Math.sin(angle); a_21 = -a_12; a_22 = a_11; }
 
if (N_exp == 7) {x = 1/2; y = 1/2; a_11 = 1;  a_12 = 1.5;     a_21 = 0.01; a_22 = -1; }
 
if (N_exp == 8) {x = 1/2; y = 1/2; a_11 = 1;  a_12 = 0.1296;     a_21 = -0.1296; a_22 = 1; }
 
if (N_exp == 9) {x = 1/4; y = 1/4; a_11 = -0.05;  a_12 = -0.95;   a_21 = 1.1; a_22 = 0.65; }
 
 
if (N_exp) {
 
if (N_exp) {
 
 
 
a11.value = a_11;
 
a11.value = a_11;
a12.value = a_12;    X.push(x); Y.push(y);
+
a12.value = a_12;  
 
a21.value = a_21;   
 
a21.value = a_21;   
 
a22.value = a_22;
 
a22.value = a_22;
 +
upd = true;
 +
}
 +
numberof = X.length;
 +
for (m=0; m<numberof; m++) {
 +
r = Math.floor(Math.random()*256);
 +
g = Math.floor(Math.random()*256);
 +
b = Math.floor(Math.random()*256);
 +
RGB.push(r);
 +
RGB.push(g);
 +
RGB.push(b);
 
}
 
}
r = Math.floor(Math.random()*256);
 
g = Math.floor(Math.random()*256);
 
b = Math.floor(Math.random()*256);
 
RGB.push(r);
 
RGB.push(g);
 
RGB.push(b);
 
 
}
 
}
 
num.onchange = function() { set_exp(document.getElementById('num').value); control();}
 
num.onchange = function() { set_exp(document.getElementById('num').value); control();}
Строка 347: Строка 401:
 
<meta charset="UTF-8">
 
<meta charset="UTF-8">
 
<title> Fractals </title>
 
<title> Fractals </title>
<script src = 'Fractals25_kopia17_11_20.js'>
+
<script src = 'Fractals25_kopia24_01_21.js'>
 
  </script>
 
  </script>
 
</head>
 
</head>
Строка 353: Строка 407:
 
<p align = 'left'><canvas id = 'cnv' width = 1000 height = 1000 style='border: 1px solid black;'></canvas></p>
 
<p align = 'left'><canvas id = 'cnv' width = 1000 height = 1000 style='border: 1px solid black;'></canvas></p>
 
<span id=some_span></span>
 
<span id=some_span></span>
<br><b>Рассматриваемая область: x_min = <span id =x_minim></span> , y_min = <span id =y_minim></span>, x_max = <span id=x_maxim></span>, y_max = <span id=y_maxim></span>
+
<br><b>Рассматриваемая область: x_min = <input type = 'text' id = 'x_minim' style = "width:70px;height:10px" value ='0'>, x_max = <input type = 'text' style = "width:70px;height:10px" id = 'x_maxim' value ='1'>, y_min = <input type = 'text' style = "width:70px;height:10px" id = 'y_minim' value = '0'>  x_0 = <span id='x_s'></span>, y_0 = <span id='y_s'></span>
 +
<br><b>Задайте начальную точку численно (затем: Обновить рисунок): x_0 = <input type = 'text' id = 'x_o' style = "width:70px;height:10px" value = '0'>, y_0 = <input type = 'text' id = 'y_o' style = "width:70px;height:10px" value = '0'>
 
<br><b>(*) Задайте коэффициенты:</b>
 
<br><b>(*) Задайте коэффициенты:</b>
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&hairsp;<label><input type='text' id='a11' value='1' ><b>A_11</b></label>  
+
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&hairsp;<label><input type='text' style = "width:50px;height:15px"  id='a11' value='1' ><b>A_11</b></label>  
<label><input type='text' id='a12' value='1' ><b>A_12</b></label>
+
&hairsp;<label><input type='text' style = "width:50px;height:15px" id='a12' value='1' ><b>A_12</b></label>
 
<br><b>(*) Включить очистку холста после клика? </b>
 
<br><b>(*) Включить очистку холста после клика? </b>
 
<label><input type = 'radio' name = 'clear_rect' value = 'yes'><b>Да</b></label>
 
<label><input type = 'radio' name = 'clear_rect' value = 'yes'><b>Да</b></label>
 
<label><input type = 'radio' name = 'clear_rect' value = 'no' checked><b>Нет</b></label>
 
<label><input type = 'radio' name = 'clear_rect' value = 'no' checked><b>Нет</b></label>
&emsp;&emsp;&hairsp;&hairsp;<label><input type='text' id='a21' value='1' ><b>A_21</b></label>
+
&hairsp;<label><input type='text' style = "width:50px;height:15px"  id='a21' value='1' ><b>A_21</b></label>
<label><input type='text' id='a22' value='1' ><b>A_22</b></label>
+
<label><input type='text' style = "width:50px;height:15px"  id='a22' value='1' ><b>A_22</b></label>
 
</br>
 
</br>
 
&emsp;&emsp;&hairsp;&hairsp;<label><b>Режим <I>ZOOM'а</I><input type = 'checkbox' id = 'zoom_check'></b></label>
 
&emsp;&emsp;&hairsp;&hairsp;<label><b>Режим <I>ZOOM'а</I><input type = 'checkbox' id = 'zoom_check'></b></label>
 
&emsp;&emsp;&hairsp;&hairsp;<label><input type='text' id='number_it' value ='200000'><b>&hairsp;&hairsp;&hairsp;Количество итераций</b></label>
 
&emsp;&emsp;&hairsp;&hairsp;<label><input type='text' id='number_it' value ='200000'><b>&hairsp;&hairsp;&hairsp;Количество итераций</b></label>
 
<br><b> Выберите номер эксперимента:</b>
 
<br><b> Выберите номер эксперимента:</b>
<input type='number' size='1' id = 'num' min='1' max='9' value='0' step='1'>
+
<input type='number' size='1' id = 'num' min='1' max='4' value='0' step='1'>
 
<br><b> <input type='button' id='downloadimg'  value='Сохранить рисунок'>
 
<br><b> <input type='button' id='downloadimg'  value='Сохранить рисунок'>
 
<input type = 'button' style="width:200px;height:40px" id = 'refresh' value = 'Обновить рисунок'></b></br>
 
<input type = 'button' style="width:200px;height:40px" id = 'refresh' value = 'Обновить рисунок'></b></br>

Текущая версия на 22:36, 1 марта 2021

Программа позволяет строить фрактальные и простые структуры при заданных начальных условиях c помощью дробно-линейного отображения Пуанкаре.

Начальные условия и принцип работы[править]

В системе координат Oxy дан единичный квадрат, который отображается на экран в масштабе 1000:1

Программа получает начальную точку с координатами "x"(0<x<1) и "y"(0<y<1) и строит N точек, координаты которых вычисляются по формулам:
\begin{equation} \begin{cases} x_{k+1} = F(a_{11}x_{k} + a_{12}y_{k})\\ y_{k+1} = F(a_{21}x_{k+1} + a_{22}y_{k}) \end{cases} \end{equation}

где [math] a_{11}, a_{12}, a_{21}, a_{22} [/math] - константы, [math]F[/math] - функция дробной части.

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

Направление исследований[править]

Если убрать функцию [math]F[/math], то формулы будут эквиваленты системе дифференциальных уравнений, описывающих отображение точек плоскости на себя с течением времени (отображение Пуанкаре). То есть, мы получим динамическую систему с дискретным временем. \begin{cases} \frac{dx}{dt} = b_{11}x + b_{12}y\\ \frac{dy}{dt} = b_{21}x + b_{22}y \end{cases}

где [math] b_{11}, b_{12}, b_{21}, b_{22} [/math] - константы.


Используя функцию [math]F[/math], программа строит регулярные и нерегулярные области:
1. Регулярной будем называть область, состоящую из малого количества отдельных элементов (например: два больших эллипса).
2. Нерегулярной будем называть область, состоящую из большого количества малых элементов (например: множество малых эллипсов в промежутках между регулярными областями).
Ниже изображен процесс вычисления точек и их отображения в случае нерегулярной и регулярной области при одних и тех же коэффициентах (эксперимент 1): \begin{equation} a_{11} = 1, a_{12} = 1, a_{21} = -0.9, a_{22} = 1.\end{equation}
1. Анимация №1
[math] x_{0} = 0.613, y_{0} = 0.582[/math]

Результат: регулярная область фрактала.
2. Анимация №2
[math]x_{0} = 0.46, y_{0} = 0.63[/math]

Результат: нерегулярная область фрактала.
Синим
цветом обозначены точки, вычисленные по рекуррентным формулам без использования функции [math]F[/math].
Красным
цветом обозначены точки, вычисленные по рекуррентным формулам с использованием функции [math]F[/math] (формулы даны выше). Программа вычисляет и отображает лишь эти точки.


Вывод 1: в зависимости от выбора начальной точки мы получаем дополняющие друг друга области одного фрактала, соответствующего заданным коэффициентам. Интерес состоит в том, чтобы выделять нерегулярные(большие) области фрактала, отсеивая регулярные так, чтобы не зависеть от "ZOOM'а".
Примечание. Один из алгоритмов отыскания нерегулярных областей осуществлен в данной программе: http://tm.spbstu.ru/Фрактал(2-ая_версия_программы).


Вывод 2: паттерн получаемого фрактала подобен кривой второго порядка, которую образуют точки, вычисленные по рекуррентным формулам без использования функции дробной части [math]F[/math]. Зная как связаны коэффициенты рекуррентных формул с коэффициентами соответствующей системы дифференциальных уравнений, можно узнать тип особой точки и вид паттерна фрактала (эллипс, гипербола, спираль..).

Пример работы программы[править]

Зададим такие же коэффициенты, как в примерах выше (эксперимент №1 в списке программы):
\begin{equation} a_{11} = 1, a_{12} = 1, a_{21} = -0.9, a_{22} = 1.\end{equation}
Получив несколько начальных точек, программа построит такую картину при данных коэффициентах:

Для просмотра других примечательных наборов начальных условий следует выбрать номер эксперимента в списке программы.

Инструментарий программы[править]

Для дальнейшего использования результатов программы в докладах/исследованиях/научных работах и повторного воспроизведения интересных результатов, программа отображает начальные значения "x" и "y", введенные пользователем последним кликом по холсту, рядом с информацией о рассматриваемой области:


Коэффициенты [math]a_{11},a_{12},a_{21},a_{22}[/math] задаются с помощью полей ввода:



Начальные точки задаются с помощью клика по холсту или с помощью полей ввода:

Количество расчетов по рекуррентным формулам для каждой начальной точки:

Чтобы посмотреть заложенные в программу примечательные наборы начальных данных, следует выбрать номер эксперимента:

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

Два режима работы программы[править]

Данная программа предусматривает два режима работы:
1) Режим задания начальных данных (стоит по умолчанию). Кликом мыши по холсту добавляем начальные данные.
2) Режим "ZOOM'а". Включается нажатием на соответствующий "checkbox", или с помощью численного задания области рассмотрения. Позволяет подробнее рассмотреть полученный рисунок.
Чтобы программа лучше прорисовала картину в режиме "ZOOM", необходимо задать большее количество точек в поле задания количества итераций, используя при этом кнопку "Обновить рисунок"

Код программы[править]

Код программы на языке JavaScript (разработчик Богдан Борисенков):
  1 window.addEventListener('load',main,false);
  2 function main () {
  3 	var x; var y;
  4 	var ctx = cnv.getContext('2d');
  5 	var h = cnv.height;
  6 	var w = cnv.width;
  7 	var scale = 1000;
  8 	var a_11; var a_12; var a_21; var a_22;
  9 	var numb1; var numb2; var decim;
 10 	var interv;
 11 	var clear;
 12 	var butt = document.getElementById('downloadimg');
 13 	var update = document.getElementById('refresh');
 14 	X = []; // массив начальных иксов
 15 	Y = []; // массив начальных игриков
 16 	var move = false;
 17 	var numberof;
 18 	var z = 1;
 19 	var RGB = [];
 20 	var z2 = 1;
 21 	var iterations = document.getElementById('number_it');
 22 	// начальные условия 
 23 	a_11 = 1;
 24 	a_12 = 1;
 25 	a_21 = 1;
 26 	a_22 = 1;
 27 	var N = 200000;
 28 	var x_min = 0; var y_min = 0;
 29 	var x_max = 1; var y_max = 1;
 30 	var x_move; var y_move;
 31 	var x_oldmin = 0;
 32 	var x_oldmax = scale;
 33 	var y_oldmin = 0;
 34 	var y_oldmax = scale;
 35 	var x_relativemin = 0;
 36 	var x_relativemax = scale;
 37 	var y_relativemin = 0;
 38 	var y_relativemax = scale;
 39 	var intermid;
 40 	var imageData = ctx.createImageData(w,h);
 41 	var imageData2;
 42 	var upd = false;
 43 	
 44 	x_minim.onchange = function () {
 45 		x_min = parseFloat(document.getElementById('x_minim').value);
 46 		z = 1/(x_max - x_min);
 47 		z2 = 1;
 48 		y_max = y_min + x_max - x_min;
 49 		x_relativemin = 0;
 50 		x_relativemax = scale;
 51 		y_relativemin = 0;
 52 		y_relativemax = scale;
 53 	}
 54 	x_maxim.onchange = function () {
 55 		x_max = parseFloat(document.getElementById('x_maxim').value);
 56 		z = 1/(x_max - x_min);
 57 		z2 = 1;
 58 		y_max = y_min + x_max - x_min;
 59 		x_relativemin = 0;
 60 		x_relativemax = scale;
 61 		y_relativemin = 0;
 62 		y_relativemax = scale;
 63 	}
 64 	y_minim.onchange = function () {
 65 		y_min = parseFloat(document.getElementById('y_minim').value);
 66 		z = 1/(x_max - x_min);
 67 		z2 = 1;
 68 		y_max = y_min + x_max - x_min;
 69 		x_relativemin = 0;
 70 		x_relativemax = scale;
 71 		y_relativemin = 0;
 72 		y_relativemax = scale;
 73 	}
 74 		
 75 	// заполняем холст непрозрачными белыми пикселями для ускорения последующего рисования
 76 	for (i = 0; i<1000; i++) {
 77 			for (j = 0; j<1000; j++) {
 78 				index = parseInt((i*w + j)*4);
 79 				imageData.data[index+0] = 255;
 80 				imageData.data[index+1] = 255;
 81 				imageData.data[index+2] = 255;
 82 				imageData.data[index+3] = 255;
 83 			}
 84 		}
 85 	ctx.putImageData(imageData,0,0);
 86 
 87 	iterations.onchange = function () {
 88 		N = document.getElementById('number_it').value;
 89 	}
 90 
 91 	butt.onclick = function () {
 92 	var dataURL = cnv.toDataURL("image/jpeg");
 93 	var link = document.createElement("a");
 94 	document.body.appendChild(link); 
 95 	link.href = dataURL;
 96 	link.download = "my-image-name.jpg";
 97 	link.click();
 98 	document.body.removeChild(link);
 99 	}
100 	update.onclick = function () { clearcanv(); upd = true;
101 	if ((document.getElementById('x_o') != 0 )||(document.getElementById('y_o') != 0)){
102 			r = Math.floor(Math.random()*256);
103 			g = Math.floor(Math.random()*256);
104 			b = Math.floor(Math.random()*256);
105 			RGB.push(r);
106 			RGB.push(g);
107 			RGB.push(b);
108 	X.push(document.getElementById('x_o').value); Y.push(document.getElementById('y_o').value);
109 	}
110 	control();
111 	}
112 	a11.onchange = function() {
113 		a_11 = parseFloat(document.getElementById('a11').value);
114 		document.getElementById('num').value = 0;
115 		angle = 0;
116 	}
117 	a12.onchange = function() {
118 		a_12 = parseFloat(document.getElementById('a12').value);
119 		document.getElementById('num').value = 0;
120 		angle = 0;
121 	}
122 	a21.onchange = function() {
123 		a_21 = parseFloat(document.getElementById('a21').value);
124 		document.getElementById('num').value = 0;
125 		angle = 0;
126 	}
127 	a22.onchange = function() {
128 		a_22 = parseFloat(document.getElementById('a22').value);
129 		document.getElementById('num').value = 0;
130 		angle = 0;
131 	}
132 
133 	cnv.onmousedown = function() {
134 		var zoom = document.getElementById('zoom_check');
135 		if (!zoom.checked) {
136 		var rect = cnv.getBoundingClientRect();
137 		if (z != 1) {
138 			z2 = x_max - x_min;
139 			x = x_min + (event.clientX - rect.left)*z2/scale;
140 			y = y_min + (event.clientY - rect.top)*z2/scale;
141 		} else {
142 			x = (event.clientX - rect.left)/scale;
143 			y = (event.clientY - rect.top)/scale;
144 		}
145 		clear = document.getElementsByName('clear_rect');
146 		if (clear[1].checked == true) {
147 			r = Math.floor(Math.random()*256);
148 			g = Math.floor(Math.random()*256);
149 			b = Math.floor(Math.random()*256);
150 		} else {
151 		clearcanv ();
152 		r = Math.floor(Math.random()*256);
153 		g = Math.floor(Math.random()*256);
154 		b = Math.floor(Math.random()*256);
155 		}
156 		X.push(x);
157 		Y.push(y);
158 		RGB.push(r);
159 		RGB.push(g);
160 		RGB.push(b);
161 		control();
162 		} else { 
163 		var rect = cnv.getBoundingClientRect();
164 		z2 = x_max - x_min;
165 		x_oldmin = x_min*scale;
166 		y_oldmin = y_min*scale;
167 		x_oldmax = x_max*scale;
168 		y_oldmax = y_max*scale;
169 		x_min = (event.clientX - rect.left)*z2 + x_oldmin;
170 		y_min = (event.clientY - rect.top)*z2 + y_oldmin;
171 		x_relativemin = event.clientX - rect.left;
172 		y_relativemin = event.clientY - rect.top;
173 		ctx.beginPath();
174 		ctx.rect(event.clientX - rect.left,event.clientY - rect.top,1,1);
175 		ctx.fillStyle = 'blue';
176 		ctx.fill();
177 		move = true;
178 		imageData2 = ctx.getImageData(0,0,w,h);
179 		}
180 		
181 	}
182 
183 	cnv.onmousemove = function () {
184 		if (move) {
185 		ctx.putImageData(imageData2,0,0);
186 		var rect = cnv.getBoundingClientRect();
187 		y_move = (event.clientY - rect.top);
188 		x_move = (y_move-y_relativemin) + x_relativemin;
189 		ctx.beginPath();
190 		ctx.rect(x_relativemin,y_relativemin,x_move-x_relativemin,y_move-y_relativemin);
191 		ctx.stroke();
192 		}
193 	}
194 	
195 	cnv.onmouseup = function () {
196 		zoom = document.getElementById('zoom_check');
197 		if (zoom.checked) { 
198 		x_relativemax = x_move;
199 		y_relativemax = y_move;
200 			y_max = y_move*z2 + y_oldmin;
201 			x_max = x_move*z2 + x_oldmin;
202 			x_min = x_min/scale;
203 			y_min = y_min/scale;
204 			x_max = x_max/scale;
205 			y_max = y_max/scale;
206 			if (x_min > x_max) {
207 				intermid = x_min;
208 				x_min = x_max;
209 				x_max = intermid;
210 			}
211 			if (y_min > y_max) { 
212 				intermid = y_min;
213 				y_min = y_max;
214 				y_max = intermid;
215 			}
216 			z = z*scale/(x_relativemax - x_relativemin);
217 			some_span.innerHTML = "Увеличение в "+z.toFixed(1)+" раз";
218 			clearcanv ();
219 			move = false;
220 			control();
221 		}
222 
223 	}
224 
225 	function Func (numb) {
226 		decim = parseFloat(numb) - Math.floor(numb);
227 		return(decim);
228 	}
229 	
230 	function coord() {
231 		numb1 = a_11*x+a_12*y;
232 		x = Func(numb1);
233 		numb2 = a_21*x+a_22*y;
234 		y = Func(numb2);
235 	}
236 
237 	function draw() { 
238 		if ((x>=x_min)&&(x<=x_max)&&(y>=y_min)&&(y<=y_max)) {
239 				index = (Math.floor((y-y_min)*z*scale)*w + Math.floor((x-x_min)*z*scale))*4;
240 				imageData.data[index+0] = r;
241 				imageData.data[index+1] = g;
242 				imageData.data[index+2] = b;
243 			}
244 	}
245 	// функция отчистки канваса 
246 	function clearcanv () {
247 		for (i = 0; i<1000; i++) {
248 			for (j = 0; j<1000; j++) {
249 				index = parseInt((i*w + j)*4);
250 				imageData.data[index+0] = 255;
251 				imageData.data[index+1] = 255;
252 				imageData.data[index+2] = 255;
253 			}
254 		}
255 		ctx.putImageData(imageData,0,0);
256 	}
257 	
258 	function control () {
259 		zoom = document.getElementById('zoom_check');
260 		if ((zoom.checked)||(upd == true)) {
261 			numberof = X.length;
262 			for (m = 0; m<numberof; m++) {
263 				x = X[m];
264 				y = Y[m];
265 				x_s.innerHTML = x; y_s.innerHTML = y;
266 				r = Number(RGB[m*3]);
267 				g = Number(RGB[m*3+1]);
268 				b = Number(RGB[m*3+2]);
269 				for (j = 0;j<=N; j++){
270 				coord();
271 				draw();
272 				}
273 				upd = false;
274 			}
275 		} else {
276 			x_s.innerHTML = x; y_s.innerHTML = y;
277 			for (j = 0;j<=N; j++){
278 				coord();
279 				draw();
280 				}
281 		}
282 		ctx.putImageData(imageData,0,0);
283 		document.getElementById('x_minim').value = x_min;
284 		document.getElementById('y_minim').value = y_min;
285 		document.getElementById('x_maxim').value = x_max;
286 	}
287 
288 	function set_exp(N_exp) {
289 		var k = Number(N_exp);
290 		clearcanv ();
291 		X = [];
292 		Y = [];
293 		RGB = [];
294 		z = 1;
295 		z2 = 1;
296 		x_min = 0; y_min = 0; x_max = 1; y_max = 1; x_oldmin = 0; y_oldmin = 0; x_oldmax = scale; y_oldmax = scale;
297 		if (N_exp == 1) {X.push(0.46); Y.push(0.63); X.push(0.613); Y.push(0.582); a_11 = 1; 	a_12 = 1;	    a_21 = -0.9;	a_22 = 1; } 
298 		if (N_exp == 2) {X.push(0.31); Y.push(0.32);  a_11 = 1; 	a_12 = 0.5;	    a_21 = -0.5;	a_22 = 1; }
299 		if (N_exp == 3) {X.push(0.69); Y.push(0.23); a_11 = 1;   a_12 = 0.1296;	    a_21 = -0.1296;	a_22 = 1; }  
300 		if (N_exp == 4) {X.push(0.15); Y.push(0.63); a_11 = -0.9899924966004454;   a_12 = 0.1411200080598672;	    a_21 = -0.1411200080598672;	a_22 = -0.9899924966004454; }  
301 		if (N_exp) {
302 			
303 			a11.value = a_11;
304 			a12.value = a_12; 
305 			a21.value = a_21;   
306 			a22.value = a_22;	
307 			upd = true;
308 		}
309 		numberof = X.length;
310 		for (m=0; m<numberof; m++) {
311 			r = Math.floor(Math.random()*256);
312 			g = Math.floor(Math.random()*256);
313 			b = Math.floor(Math.random()*256);
314 			RGB.push(r);
315 			RGB.push(g);
316 			RGB.push(b);
317 		}
318 	}	
319 	num.onchange = function() { set_exp(document.getElementById('num').value); control();}
320 }
html - файл:
 1 <html>
 2 <head>
 3 <meta charset="UTF-8">
 4 <title> Fractals </title>
 5 <script src = 'Fractals25_kopia24_01_21.js'>
 6  </script>
 7 </head>
 8 <body>
 9 <p align = 'left'><canvas id = 'cnv' width = 1000 height = 1000 style='border: 1px solid black;'></canvas></p>
10 <span id=some_span></span>
11 <br><b>Рассматриваемая область: x_min = <input type = 'text' id = 'x_minim' style = "width:70px;height:10px" value ='0'>, x_max = <input type = 'text' style = "width:70px;height:10px" id = 'x_maxim' value ='1'>, y_min = <input type = 'text' style = "width:70px;height:10px" id = 'y_minim' value = '0'>  x_0 = <span id='x_s'></span>, y_0 = <span id='y_s'></span>
12 <br><b>Задайте начальную точку численно (затем: Обновить рисунок): x_0 = <input type = 'text' id = 'x_o' style = "width:70px;height:10px" value = '0'>, y_0 = <input type = 'text' id = 'y_o' style = "width:70px;height:10px" value = '0'>
13 <br><b>(*) Задайте коэффициенты:</b>
14 &emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&hairsp;<label><input type='text' style = "width:50px;height:15px"  id='a11' value='1' ><b>A_11</b></label> 
15 &hairsp;<label><input type='text' style = "width:50px;height:15px" id='a12' value='1' ><b>A_12</b></label>
16 <br><b>(*) Включить очистку холста после клика? </b>
17 <label><input type = 'radio' name = 'clear_rect' value = 'yes'><b>Да</b></label>
18 <label><input type = 'radio' name = 'clear_rect' value = 'no' checked><b>Нет</b></label>
19 &hairsp;<label><input type='text' style = "width:50px;height:15px"  id='a21' value='1' ><b>A_21</b></label>
20 <label><input type='text' style = "width:50px;height:15px"  id='a22' value='1' ><b>A_22</b></label>
21 </br>
22 &emsp;&emsp;&hairsp;&hairsp;<label><b>Режим <I>ZOOM'а</I><input type = 'checkbox' id = 'zoom_check'></b></label>
23 &emsp;&emsp;&hairsp;&hairsp;<label><input type='text' id='number_it' value ='200000'><b>&hairsp;&hairsp;&hairsp;Количество итераций</b></label>
24 <br><b> Выберите номер эксперимента:</b>
25 <input type='number' size='1' id = 'num' min='1' max='4' value='0' step='1'>
26 <br><b> <input type='button' id='downloadimg'  value='Сохранить рисунок'>
27 <input type = 'button' style="width:200px;height:40px" id = 'refresh' value = 'Обновить рисунок'></b></br>
28 </body>
29 </html>