Фрактал
Программа позволяет строить фрактальные и простые структуры при заданных начальных условиях.
Содержание
Начальные условия и принцип работы
В системе координат Oxy дан единичный квадрат, который отображается на экран в масштабе 1000:1
Пользователю предлагается задать коэффициенты рекурсивной функции вычисления новых координат и координаты "x" и "y" начальной точки, количество итераций, которое произведет программа и способ вычисления новых точек. Начальная точка задается кликом левой кнопки мыши по холсту.
Программа получает на вход "x"(0<x<1) и "y"(0<y<1) и строит N точек, координаты которых вычисляются по формулам:
\begin{equation}
\begin{cases}
x_{k} = F(a_{11}*x_{k-1} + a_{12}*y_{k-1})\\
y_{k} = F(a_{21}*x_{k} + a_{22}*y_{k-1})
\end{cases}
\end{equation}
где - функция дробной части. Сразу можно сказать, что все точки, вычисленные по этим формулам, попадут в единичный квадрат (вследствие использования функции дробной части).
Направление исследований
Используя функцию
1. Регулярной будем считать область, которая состоит из малого количества отдельных элементов (например: два больших эллипса).
2. Нерегулярной будем считать область, которая состоит из большого количества малых элементов (например: множество малых эллипсов в промежутках между регулярными областями).
Ниже изображен процесс вычисления точек и их отображения в случае нерегулярной и регулярной области при заданных коэффициентах (эксперимент 1):
\begin{equation} a_{11} = 1, a_{12} = 1, a_{21} = -0.9, a_{22} = 1.\end{equation}
В данных примерах использовались начальные условия:
1. \begin{equation} x_{0} = 0.613, y_{0} = 0.582 \end{equation} Результат: регулярная область фрактала.
2. \begin{equation} x_{0} = 0.46, y_{0} = 0.63\end{equation} Результат: нерегулярная область фрактала.
Синим цветом обозначены точки, вычисленные по рекуррентным формулам без использования функции .
Красным цветом обозначены точки, вычисленные по рекуррентным формулам с использованием функции (формулы даны выше). Данная на этой странице программа вычисляет и отображает лишь эти точки.
Данные примеры призваны показать, что паттерн получаемого фрактала подобен кривой второго порядка, которую образуют точки, вычисленные по рекуррентным формулам без использования функции дробной части .
Пример работы программы
Зададим такие же коэффициенты, как в примерах выше (эксперимент №1 в списке программы):
\begin{equation} a_{11} = 1, a_{12} = 1, a_{21} = -0.9, a_{22} = 1.\end{equation}
Получив несколько начальных точек, программа построит такую картину при данных коэффициентах (картина отзеркалена относительно оси Ox для одинаковой направленности осей):
Другие примечательные наборы начальных условий можно посмотреть, выбрав номер эксперимента.
Задание коэффициентов и начальных точек
Коэффициенты \begin{equation}a_{11},a_{12},a_{21},a_{22}\end{equation} задаются с помощью полей ввода:
Начальные точки задаются с помощью клика по холсту или с помощью полей ввода:
Два режима работы программы
Данная программа предусматривает два режима работы:
1) Режим задания начальных данных (стоит по умолчанию). Кликом мыши по холсту добавляем начальные данные.
2) Режим "ZOOM'а". Включается нажатием на соответствующий "checkbox". Позволяет подробнее рассмотреть уже полученный рисунок.
Чтобы программа лучше прорисовала картину в режиме "ZOOM", необходимо задать большее количество точек в поле задания количества итераций, используя при этом кнопку "Обновить рисунок"
Другая версия программы
http://tm.spbstu.ru/Фрактал(2-ая_версия_программы)
Код программы
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>