Фрактал
Материал из Department of Theoretical and Applied Mechanics
Программа позволяет строить фрактальные и простые структуры при заданных начальных условиях: координат "x" и "y" исходной точки, от которой будут высчитываться координаты остальных, и коэффициентах, участвующих в расчетах. Или же расчет новых точек можно задать с помощью задания угла поворота исходной
Код программы
Код программы на языке 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 = 100;
8 var scale2 = 30;
9 var a_11; var a_12; var a_21; var a_22;
10 var numb1; var numb2; var decim;
11 var interv;
12 var way;
13 var clear;
14 var start_draw = document.getElementById('to_start');
15 var move = false;
16 var z = 1;
17 var z2 = 1;
18 // начальные условия
19 a_11 = 1;
20 a_12 = 1;
21 a_21 = 1;
22 a_22 = 1;
23 var angle = 0;
24 var x_min = 0; var y_min = 0;
25 var x_max = 1; var y_max = 1;
26 var x_move; var y_move;
27 var x_oldmin = 0;
28 var x_oldmax = scale;
29 var y_oldmin = 0;
30 var y_oldmax = scale;
31 var intermid;
32 var imageData = ctx.createImageData(w,h);
33 var SECCANV = []; // массив пикселей маленького канваса
34 var square; // площадь при конкретных начальных условиях
35 var SQ = []; // массив площадей нерегулярных областей
36 var RGB = []
37 var numbclr;
38
39 for (d = 0; d<24; d++) {
40 RGB.push(Math.floor(Math.random()*256));
41 }
42
43 // заполняем холст непрозрачными белыми пикселями
44 for (i = 0; i<100; i++) {
45 for (j = 0; j<100; j++) {
46 index = parseInt((i*w + j)*4);
47 imageData.data[index+0] = 255;
48 imageData.data[index+1] = 255;
49 imageData.data[index+2] = 255;
50 imageData.data[index+3] = 255;
51 }
52 }
53 ctx.putImageData(imageData,0,0);
54 start_draw.onclick = function () {
55 zoom = document.getElementById('zoom_check');
56 if (!zoom.checked) {
57 clearcanv();
58 square = 0;
59 SQ = [];
60 if (angle != 0) {
61 a_11 = Math.cos(angle);
62 a_22 = a_11;
63 a_12 = Math.sin(angle);
64 a_21 = -a_12;
65 document.getElementById('a11').value = a_11;
66 document.getElementById('a12').value = a_12;
67 document.getElementById('a21').value = a_21;
68 document.getElementById('a22').value = a_22;
69 }
70 checking(x_min,y_min,x_max,y_max);
71 } else {
72 alert("Выключите режим зума");
73 }
74 }
75
76 a11.onchange = function() {
77 a_11 = parseFloat(document.getElementById('a11').value);
78 document.getElementById('angle_rad').value = 0;
79 document.getElementById('num').value = 0;
80 angle = 0;
81 }
82 a12.onchange = function() {
83 a_12 = parseFloat(document.getElementById('a12').value);
84 document.getElementById('angle_rad').value = 0;
85 document.getElementById('num').value = 0;
86 angle = 0;
87 }
88 a21.onchange = function() {
89 a_21 = parseFloat(document.getElementById('a21').value);
90 document.getElementById('angle_rad').value = 0;
91 document.getElementById('num').value = 0;
92 angle = 0;
93 }
94 a22.onchange = function() {
95 a_22 = parseFloat(document.getElementById('a22').value);
96 document.getElementById('angle_rad').value = 0;
97 document.getElementById('num').value = 0;
98 angle = 0;
99 }
100
101 angle_rad.onchange = function() {
102 angle = parseFloat(document.getElementById('angle_rad').value);
103 document.getElementById('num').value = 0;
104 }
105
106 cnv.onmousedown = function() {
107 var zoom = document.getElementById('zoom_check');
108 if (zoom.checked) {
109 var rect = cnv.getBoundingClientRect();
110 z2 = x_max - x_min;
111 x_oldmin = x_min*scale;
112 y_oldmin = y_min*scale;
113 x_oldmax = x_max*scale;
114 y_oldmax = y_max*scale;
115 x_min = (event.clientX - rect.left)*z2 + x_oldmin;
116 y_min = (event.clientY - rect.top)*z2 + y_oldmin;
117 x_relativemin = event.clientX - rect.left;
118 y_relativemin = event.clientY - rect.top;
119 move = true;
120 }
121 }
122
123 cnv.onmousemove = function () {
124 if (move) {
125 rect = cnv.getBoundingClientRect();
126 y_move = (event.clientY - rect.top);
127 x_move = (y_move-y_relativemin) + x_relativemin;
128 ctx.beginPath();
129 ctx.arc(x_move,y_move,1,0,2*Math.PI);
130 ctx.fillStyle = 'green';
131 ctx.fill();
132 }
133 }
134
135 cnv.onmouseup = function () {
136 zoom = document.getElementById('zoom_check');
137 if (zoom.checked) {
138 x_relativemax = x_move;
139 y_relativemax = y_move;
140 y_max = y_move*z2 + y_oldmin;
141 x_max = x_move*z2 + x_oldmin;
142 x_min = x_min/scale;
143 y_min = y_min/scale;
144 x_max = x_max/scale;
145 y_max = y_max/scale;
146 if (x_min > x_max) {
147 intermid = x_min;
148 x_min = x_max;
149 x_max = intermid;
150 }
151 if (y_min > y_max) {
152 intermid = y_min;
153 y_min = y_max;
154 y_max = intermid;
155 }
156 z = z*scale/(x_relativemax - x_relativemin);
157 clearcanv ();
158 SECCANV = [];
159 SQ = [];
160 square = 0;
161 move = false;
162 checking(x_min,y_min,x_max,y_max);
163 }
164 }
165
166 function Func (numb) {
167 decim = parseFloat(numb) - Math.floor(numb);
168 return(decim);
169 }
170
171 function coord() {
172 way = document.getElementsByName('ways');
173 if (way[0].checked == true) {
174 numb1 = a_11*x+a_12*y;
175 numb2 = a_21*x+a_22*y;
176 x = Func(numb1);
177 y = Func(numb2);
178 }
179 if (way[1].checked == true) {
180 numb1 = a_11*x+a_12*y;
181 x = Func(numb1);
182 numb2 = a_21*x+a_22*y;
183 y = Func(numb2);
184 }
185 }
186
187 // функция отчистки канваса
188 function clearcanv () {
189 for (i = 0; i<scale; i++) {
190 for (j = 0; j<scale; j++) {
191 index = parseInt((i*w + j)*4);
192 imageData.data[index+0] = 255;
193 imageData.data[index+1] = 255;
194 imageData.data[index+2] = 255;
195 }
196 }
197 ctx.putImageData(imageData,0,0);
198 }
199
200 function checking (xmin,ymin,xmax,ymax) {
201 for (i = 0;i<scale; i++) {
202 for (j = 0;j<scale; j++) {
203 SECCANV = [];
204 square = 0;
205 x = xmin + j*(xmax - xmin)/scale;
206 y = ymin + i*(ymax - ymin)/scale;
207 index = Math.floor(x*scale2)*scale2 + Math.floor(y*scale2);
208 draw_check = control(index);
209 if (draw_check == 1) {
210 index = parseInt((i*w + j)*4);
211 if (numbclr == -1) {
212 numbclr = SQ.length;
213 SQ.push(square);
214 }
215 if (numbclr>7) {
216 numbclr = (numbclr - 1)%8;
217 }
218 imageData.data[index+0] = RGB[numbclr*3];
219 imageData.data[index+1] = RGB[numbclr*3+1];
220 imageData.data[index+2] = RGB[numbclr*3+2];
221 }
222 }
223 }
224 ctx.putImageData(imageData,0,0);
225 }
226
227 function control(ind) {
228 numbclr = -1;
229 SECCANV[ind] = 1;
230 square += 1;
231 for (k = 0; k<600; k++) {
232 coord();
233 idx = Math.floor((x-x_min)*scale2)*scale2 + Math.floor((y-y_min)*scale2);
234 if ((x>=x_min)&&(x<=x_max)&&(y>=y_min)&&(y<=y_max)&&(SECCANV[idx] != 1)) { SECCANV[idx] = 1; square+= 1;}
235 }
236 if (square >= 180) {
237 if (SQ == []) {
238 SQ.push(square);
239 numbclr = 0;
240 } else { for (m = 0; m<SQ.length; m++) {
241 if (square == SQ[m]) { numbclr = m; break;}
242 }
243 }
244 return(1);
245 } else { return(0); }
246 }
247
248
249 function set_exp(N_exp) {
250 var k = Number(N_exp);
251 clearcanv ();
252 SQ = [];
253 if (N_exp == 1) { document.getElementsByName('ways')[1].checked = true; angle = 0; a_11 = 1; a_12 = 0.5; a_21 = -0.5; a_22 = 1; }
254 if (N_exp == 2) { document.getElementsByName('ways')[0].checked = true; angle = 0; a_11 = 1; a_12 = 0.01; a_21 = 0.01; a_22 = -1; }
255 if (N_exp == 3) { document.getElementsByName('ways')[0].checked = true; angle = 0; a_11 = 1; a_12 = 0.32; a_21 = 0.32; a_22 = -1; }
256 if (N_exp == 4) { document.getElementsByName('ways')[0].checked = true; angle = 0; a_11 = 0.9; a_12 = 0.1; a_21 = -0.1; a_22 = 1.2; }
257 if (N_exp == 5) { document.getElementsByName('ways')[1].checked = true; angle = 3; a_11 = Math.cos(angle); a_12 = Math.sin(angle); a_21 = -a_12; a_22 = a_11; }
258 if (N_exp == 6) { document.getElementsByName('ways')[0].checked = true; angle = 0; a_11 = 1; a_12 = 1.5; a_21 = 0.01; a_22 = -1; }
259 if (N_exp == 7) { document.getElementsByName('ways')[0].checked = true; angle = 0; a_11 = 1; a_12 = 0.1296; a_21 = -0.1296; a_22 = 1; }
260 if (N_exp == 8) { document.getElementsByName('ways')[0].checked = true; angle = 0; a_11 = -0.05; a_12 = -0.95; a_21 = 1.1; a_22 = 0.65; }
261 if (N_exp) {
262
263 a11.value = a_11; angle_rad.value = angle;
264 a12.value = a_12;
265 a21.value = a_21;
266 a22.value = a_22;
267 }
268 }
269
270 num.onchange = function() { x_min = 0; y_min = 0; x_max = 1; y_max = 1; set_exp(document.getElementById('num').value); checking(x_min,y_min,x_max,y_max);}
271
272 }
html - файл:
1 <html>
2 <head>
3 <meta charset="UTF-8">
4 <title> Fractals </title>
5 <script src = 'Fractals25.js'>
6 </script>
7 </head>
8 <body>
9 <p align = 'left'><canvas id = 'cnv' width = 100 height = 100 style='border: 1px solid black;'></canvas></p>
10 <b>(*) Задайте коэффициенты (в графе угла должен стоять "0"):</b>
11 <label><input type='text' id='a11' value='1' ><b>A_11</b></label>
12 <label><input type='text' id='a12' value='1' ><b>A_12</b></label>
13 <br><b>(*) Включить очистку холста после клика? </b>
14 <label><input type = 'radio' name = 'clear_rect' value = 'yes'><b>Да</b></label>
15 <label><input type = 'radio' name = 'clear_rect' value = 'no' checked><b>Нет</b></label>
16     <label><input type='text' id='a21' value='1' ><b>A_21</b></label>
17 <label><input type='text' id='a22' value='1' ><b>A_22</b></label>
18 </br>
19 <br><b> Или меняйте коэффициенты с помощью ползунков:</b>
20     <label><b>Режим <I>ZOOM'а</I><input type = 'checkbox' id = 'zoom_check'></b></label>
21 <br><b> Выберите номер эксперимента:</b>
22 <input type='number' size='1' id = 'num' min='1' max='8' value='0' step='1'>
23 <br>
24 <b>Способ вычисления новых точек:</b>
25 <input type = 'radio' name='ways' value = 'old' checked> <b>1-ый</b>
26 <input type = 'radio' name='ways' value = 'new'><b> 2-ой</b>
27 <input type = 'button' style="width:200px;height:40px" id = 'to_start' value = 'Запуск '></b></br>
28 <br>
29 <b>Рисование с помощью поворота точки на заданный угол</b>
30 <label><input type='text' id='angle_rad' value ='0'><b> Угол поворота (в <I> радианах</I>)</b></label>
31 </body>
32 </html>