Фрактал — различия между версиями
(→Два режима работы программы) |
|||
(не показано 68 промежуточных версий 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> | + | <br>Программа получает начальную точку с координатами "x"(0<x<1) и "y"(0<y<1) и строит N точек, координаты которых вычисляются по формулам: |
− | Программа получает | + | <br> |
+ | \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} | ||
+ | <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>, то формулы будут эквиваленты системе дифференциальных уравнений, описывающих отображение точек плоскости на себя с течением времени ([https://ru.wikipedia.org/wiki/Отображение_Пуанкаре отображение Пуанкаре]). То есть, мы получим динамическую систему с дискретным временем. | ||
+ | \begin{cases} | ||
+ | \frac{dx}{dt} = b_{11}x + b_{12}y\\ | ||
+ | \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} | ||
+ | <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}} | ||
+ | {{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/edinich-1.png| width= 387 | height = 218}} | ||
+ | <br>Результат: регулярная область фрактала. | ||
+ | <br>2. Анимация №2 | ||
+ | <br><math>x_{0} = 0.46, y_{0} = 0.63</math> | ||
+ | <br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/nereg_obl2.gif| width= 450 | height = 369}} | ||
+ | <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> | + | <br><b><i>Вывод 2</i></b>: паттерн получаемого фрактала подобен кривой второго порядка, которую образуют точки, вычисленные по рекуррентным формулам без использования функции дробной части <math>F</math>. Зная как связаны коэффициенты рекуррентных формул с коэффициентами соответствующей системы дифференциальных уравнений, можно узнать тип особой точки и вид паттерна фрактала (эллипс, гипербола, спираль..). |
− | < | ||
− | < | ||
− | < | ||
− | |||
− | |||
− | |||
==Пример работы программы== | ==Пример работы программы== | ||
− | <br> | + | Зададим такие же коэффициенты, как в примерах выше (эксперимент №1 в списке программы): |
− | + | <br>\begin{equation} a_{11} = 1, a_{12} = 1, a_{21} = -0.9, a_{22} = 1.\end{equation} | |
<br>Получив несколько начальных точек, программа построит такую картину при данных коэффициентах: | <br>Получив несколько начальных точек, программа построит такую картину при данных коэффициентах: | ||
− | <br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/ | + | <br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/Ellips2.jpg| width= 212 | height = 209}} |
− | <br> | + | <br>Для просмотра других примечательных наборов начальных условий следует выбрать номер эксперимента в списке программы. |
− | == | + | ==Инструментарий программы== |
− | Коэффициенты | + | Для дальнейшего использования результатов программы в докладах/исследованиях/научных работах и повторного воспроизведения интересных результатов, программа отображает начальные значения "x" и "y", введенные пользователем последним кликом по холсту, рядом с информацией о рассматриваемой области: |
− | <br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/ | + | <br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/obla.png| width= 805 | height = 29}} |
− | <br>или | + | <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/ | + | <br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/koeffs.png| width= 197 | height = 45}} |
− | <br> | + | <br>Начальные точки задаются с помощью клика по холсту или с помощью полей ввода: |
− | + | <br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/n.y2.png| width= 660 | height = 25}} | |
− | {{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/ | + | <br>Количество расчетов по рекуррентным формулам для каждой начальной точки: |
− | == | + | <br>{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/fotos/iters.png| width= 346 | height = 25}} |
− | <br>< | + | <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>2) Режим "ZOOM'а". Включается нажатием на соответствующий "checkbox", или с помощью численного задания области рассмотрения. Позволяет подробнее рассмотреть полученный рисунок. | ||
+ | <br>Чтобы программа лучше прорисовала картину в режиме "ZOOM", необходимо задать большее количество точек в поле задания количества итераций, используя при этом кнопку "Обновить рисунок" | ||
+ | {{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/Fractals25_kopia1_03_21.html | width =1500 | height = 1250| border = 0}} | ||
+ | |||
==Код программы== | ==Код программы== | ||
<div class="mw-collapsible mw-collapsed"> | <div class="mw-collapsible mw-collapsed"> | ||
Строка 43: | Строка 82: | ||
var numb1; var numb2; var decim; | var numb1; var numb2; var decim; | ||
var interv; | var interv; | ||
− | |||
var clear; | var clear; | ||
var butt = document.getElementById('downloadimg'); | var butt = document.getElementById('downloadimg'); | ||
Строка 61: | Строка 99: | ||
a_22 = 1; | a_22 = 1; | ||
var N = 200000; | var N = 200000; | ||
− | |||
var x_min = 0; var y_min = 0; | var x_min = 0; var y_min = 0; | ||
var x_max = 1; var y_max = 1; | var x_max = 1; var y_max = 1; | ||
Строка 69: | Строка 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); | ||
Строка 74: | Строка 115: | ||
var upd = false; | var upd = false; | ||
− | // заполняем холст непрозрачными белыми пикселями | + | 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++) { | ||
Строка 99: | Строка 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); | ||
− | |||
document.getElementById('num').value = 0; | document.getElementById('num').value = 0; | ||
angle = 0; | angle = 0; | ||
Строка 108: | Строка 190: | ||
a12.onchange = function() { | a12.onchange = function() { | ||
a_12 = parseFloat(document.getElementById('a12').value); | a_12 = parseFloat(document.getElementById('a12').value); | ||
− | |||
document.getElementById('num').value = 0; | document.getElementById('num').value = 0; | ||
angle = 0; | angle = 0; | ||
Строка 114: | Строка 195: | ||
a21.onchange = function() { | a21.onchange = function() { | ||
a_21 = parseFloat(document.getElementById('a21').value); | a_21 = parseFloat(document.getElementById('a21').value); | ||
− | |||
document.getElementById('num').value = 0; | document.getElementById('num').value = 0; | ||
angle = 0; | angle = 0; | ||
Строка 120: | Строка 200: | ||
a22.onchange = function() { | a22.onchange = function() { | ||
a_22 = parseFloat(document.getElementById('a22').value); | a_22 = parseFloat(document.getElementById('a22').value); | ||
− | |||
document.getElementById('num').value = 0; | document.getElementById('num').value = 0; | ||
angle = 0; | angle = 0; | ||
} | } | ||
− | + | ||
− | |||
− | |||
− | |||
− | |||
− | |||
cnv.onmousedown = function() { | cnv.onmousedown = function() { | ||
var zoom = document.getElementById('zoom_check'); | var zoom = document.getElementById('zoom_check'); | ||
if (!zoom.checked) { | if (!zoom.checked) { | ||
var rect = cnv.getBoundingClientRect(); | var rect = cnv.getBoundingClientRect(); | ||
− | |||
if (z != 1) { | if (z != 1) { | ||
z2 = x_max - x_min; | z2 = x_max - x_min; | ||
Строка 150: | Строка 223: | ||
} else { | } else { | ||
clearcanv (); | clearcanv (); | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
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); | ||
− | |||
− | |||
− | |||
− | |||
} | } | ||
X.push(x); | X.push(x); | ||
Строка 169: | Строка 232: | ||
RGB.push(g); | RGB.push(g); | ||
RGB.push(b); | RGB.push(b); | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
control(); | control(); | ||
} else { | } else { | ||
Строка 236: | Строка 288: | ||
} | } | ||
z = z*scale/(x_relativemax - x_relativemin); | z = z*scale/(x_relativemax - x_relativemin); | ||
− | some_span.innerHTML = "Увеличение в "+z.toFixed( | + | some_span.innerHTML = "Увеличение в "+z.toFixed(1)+" раз"; |
clearcanv (); | clearcanv (); | ||
move = false; | move = false; | ||
control(); | control(); | ||
} | } | ||
+ | |||
} | } | ||
Строка 249: | Строка 302: | ||
function coord() { | function coord() { | ||
− | + | numb1 = a_11*x+a_12*y; | |
− | + | x = Func(numb1); | |
− | + | numb2 = a_21*x+a_22*y; | |
− | + | y = Func(numb2); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
Строка 292: | Строка 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]); | ||
Строка 302: | Строка 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(); | ||
Строка 308: | Строка 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; | ||
} | } | ||
Строка 320: | Строка 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) { | + | 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.push(0.31); Y.push(0.32); a_11 = 1; a_12 = 0.5; a_21 = -0.5; a_22 = 1; } | |
− | if (N_exp == | + | 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.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 == | ||
− | |||
− | |||
− | if (N_exp == | ||
if (N_exp) { | if (N_exp) { | ||
− | a11.value = a_11 | + | a11.value = a_11; |
− | a12.value = a_12 | + | 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); | ||
} | } | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
num.onchange = function() { set_exp(document.getElementById('num').value); control();} | num.onchange = function() { set_exp(document.getElementById('num').value); control();} | ||
Строка 354: | Строка 401: | ||
<meta charset="UTF-8"> | <meta charset="UTF-8"> | ||
<title> Fractals </title> | <title> Fractals </title> | ||
− | <script src = ' | + | <script src = 'Fractals25_kopia24_01_21.js'> |
</script> | </script> | ||
</head> | </head> | ||
<body> | <body> | ||
− | <p align = 'left'><canvas id = 'cnv' width = | + | <p align = 'left'><canvas id = 'cnv' width = 1000 height = 1000 style='border: 1px solid black;'></canvas></p> |
− | <b>( | + | <span id=some_span></span> |
− | <label><input type='text' id='a11' value='1' ><b>A_11</b></label> | + | <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> |
− | <label><input type='text' id='a12' value='1' ><b>A_12</b></label> | + | <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> | ||
+ |               <label><input type='text' style = "width:50px;height:15px" id='a11' value='1' ><b>A_11</b></label> | ||
+ |  <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> | ||
− | + |  <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> | ||
− | |||
    <label><b>Режим <I>ZOOM'а</I><input type = 'checkbox' id = 'zoom_check'></b></label> |     <label><b>Режим <I>ZOOM'а</I><input type = 'checkbox' id = 'zoom_check'></b></label> | ||
+ |     <label><input type='text' id='number_it' value ='200000'><b>   Количество итераций</b></label> | ||
<br><b> Выберите номер эксперимента:</b> | <br><b> Выберите номер эксперимента:</b> | ||
− | <input type='number' size='1' id = 'num' min='1' max=' | + | <input type='number' size='1' id = 'num' min='1' max='4' value='0' step='1'> |
− | <br> | + | <br><b> <input type='button' id='downloadimg' value='Сохранить рисунок'> |
− | <b> | + | <input type = 'button' style="width:200px;height:40px" id = 'refresh' value = 'Обновить рисунок'></b></br> |
− | <input type = ' | ||
− | |||
− | <input type = 'button' style="width:200px;height:40px" id = ' | ||
− | |||
− | |||
− | |||
</body> | </body> | ||
</html> | </html> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
</div> | </div> |
Текущая версия на 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}
Сразу можно сказать, что все точки, вычисленные по этим формулам, попадут в единичный квадрат (вследствие использования функции дробной части).
Направление исследований[править]
Если убрать функцию отображение Пуанкаре). То есть, мы получим динамическую систему с дискретным временем. \begin{cases} \frac{dx}{dt} = b_{11}x + b_{12}y\\ \frac{dy}{dt} = b_{21}x + b_{22}y \end{cases}
, то формулы будут эквиваленты системе дифференциальных уравнений, описывающих отображение точек плоскости на себя с течением времени (
Используя функцию , программа строит регулярные и нерегулярные области:
1. Регулярной будем называть область, состоящую из малого количества отдельных элементов (например: два больших эллипса).
2. Нерегулярной будем называть область, состоящую из большого количества малых элементов (например: множество малых эллипсов в промежутках между регулярными областями).
Ниже изображен процесс вычисления точек и их отображения в случае нерегулярной и регулярной области при одних и тех же коэффициентах (эксперимент 1):
\begin{equation} a_{11} = 1, a_{12} = 1, a_{21} = -0.9, a_{22} = 1.\end{equation}
1. Анимация №1
Результат: регулярная область фрактала.
2. Анимация №2
Результат: нерегулярная область фрактала.
Синим цветом обозначены точки, вычисленные по рекуррентным формулам без использования функции .
Красным цветом обозначены точки, вычисленные по рекуррентным формулам с использованием функции (формулы даны выше). Программа вычисляет и отображает лишь эти точки.
Вывод 1: в зависимости от выбора начальной точки мы получаем дополняющие друг друга области одного фрактала, соответствующего заданным коэффициентам. Интерес состоит в том, чтобы выделять нерегулярные(большие) области фрактала, отсеивая регулярные так, чтобы не зависеть от "ZOOM'а".
Примечание. Один из алгоритмов отыскания нерегулярных областей осуществлен в данной программе: http://tm.spbstu.ru/Фрактал(2-ая_версия_программы).
Вывод 2: паттерн получаемого фрактала подобен кривой второго порядка, которую образуют точки, вычисленные по рекуррентным формулам без использования функции дробной части . Зная как связаны коэффициенты рекуррентных формул с коэффициентами соответствующей системы дифференциальных уравнений, можно узнать тип особой точки и вид паттерна фрактала (эллипс, гипербола, спираль..).
Пример работы программы[править]
Зададим такие же коэффициенты, как в примерах выше (эксперимент №1 в списке программы):
\begin{equation} a_{11} = 1, a_{12} = 1, a_{21} = -0.9, a_{22} = 1.\end{equation}
Получив несколько начальных точек, программа построит такую картину при данных коэффициентах:
Для просмотра других примечательных наборов начальных условий следует выбрать номер эксперимента в списке программы.
Инструментарий программы[править]
Для дальнейшего использования результатов программы в докладах/исследованиях/научных работах и повторного воспроизведения интересных результатов, программа отображает начальные значения "x" и "y", введенные пользователем последним кликом по холсту, рядом с информацией о рассматриваемой области:
Начальные точки задаются с помощью клика по холсту или с помощью полей ввода:
Количество расчетов по рекуррентным формулам для каждой начальной точки:
Чтобы посмотреть заложенные в программу примечательные наборы начальных данных, следует выбрать номер эксперимента:
Чтобы скачать полученный рисунок, обновить рисунок с учетом изменения количества итераций, или отчистить холст, следует воспользоваться следующими кнопками:
Два режима работы программы[править]
Данная программа предусматривает два режима работы:
1) Режим задания начальных данных (стоит по умолчанию). Кликом мыши по холсту добавляем начальные данные.
2) Режим "ZOOM'а". Включается нажатием на соответствующий "checkbox", или с помощью численного задания области рассмотрения. Позволяет подробнее рассмотреть полученный рисунок.
Чтобы программа лучше прорисовала картину в режиме "ZOOM", необходимо задать большее количество точек в поле задания количества итераций, используя при этом кнопку "Обновить рисунок"
Код программы[править]
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 }
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               <label><input type='text' style = "width:50px;height:15px" id='a11' value='1' ><b>A_11</b></label>
15  <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  <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     <label><b>Режим <I>ZOOM'а</I><input type = 'checkbox' id = 'zoom_check'></b></label>
23     <label><input type='text' id='number_it' value ='200000'><b>   Количество итераций</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>