Фрактал(2-ая версия программы)

Материал из Department of Theoretical and Applied Mechanics
Перейти к: навигация, поиск

Программа позволяет строить фрактальные и простые структуры при заданных начальных условиях.
Первая версия программы: http://tm.spbstu.ru/Фрактал

Принцип работы

В отличие от первой программы, данная программа требует только задания коэффициентов a11,a12,a21,a22. Дальше происходит следующее:
1. Единичный квадрат разбивается сеткой 100x100 пикселей.

2. Программа прогоняет каждую точку этого квадрата, считая координаты точки равными координатам узла соответствующего квадрата сетки, по следующему алгоритму:

а) Единичный квадрат разбивается сеткой 30x30 пикселей, i-ой точке квадрата с сеткой 100x100 сопоставляется точка на квадрате с сеткой 30x30 пикселей.
б) Программа производит 450 итераций расчета координат новых точек, ставя им в соответствие "квадраты" сетки 30x30 пикселей.
в) Подсчитывается площадь, занятая "закрашенными" квадратами 30x30 пикселей. "Закрашенным" квадрат считается, если вычисленная точка попадает в этот квадрат.
г) Если закрашено менее 20 процентов единичного квадрата, делается вывод, что данная точка является частью регулярной области - крупного эллипса, если закрашено более 20 процентов - считается, что это нерегулярная область, которая в большей степени прорисовывает фрактал и является наиболее интересной. Во втором случае точка с данными координатами подсвечивается на экране.
Таким образом программа "отсеивает" регулярные области, оставляя наиболее интересные для рассмотрения.

Код программы

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