Поперечные волны в струне — различия между версиями
Материал из Department of Theoretical and Applied Mechanics
(не показано 15 промежуточных версий 2 участников) | |||
Строка 1: | Строка 1: | ||
− | [[Виртуальная лаборатория]] > [[ | + | [[Виртуальная лаборатория]] > [[Поперечные волны в струне]] <HR> |
[[Файл:1449683138190745365.gif|thumb|600px|right|Движение струны, со скоростью 1200 кадров в секунду]] | [[Файл:1449683138190745365.gif|thumb|600px|right|Движение струны, со скоростью 1200 кадров в секунду]] | ||
Строка 10: | Строка 10: | ||
Разработка программы моделирующая колебания струны | Разработка программы моделирующая колебания струны | ||
− | + | ===Математическая модель=== | |
− | === | + | <math> m\begin{pmatrix} {\ddot x_i} \\ {\ddot y_i} \end{pmatrix}= -k (|\vec{r}_{i,i-1}|-l_0)\frac{\vec{r}_{i,i-1}}{|\vec{r}_{i,i-1}|} - B (\begin{pmatrix} {\dot x_i} \\ {\dot y_i} \end{pmatrix}-\begin{pmatrix} {\dot x_{i-1}} \\ {\dot y_{i-1}} \end{pmatrix}) </math><br /> |
− | <math> m \ddot r | + | <math>\vec{r}_{i,i-1} = \begin{pmatrix} {x_i} \\ {y_i} \end{pmatrix}-\begin{pmatrix} {x_{i-1}} \\ {y_{i-1}} \end{pmatrix} </math><br /> |
− | r = | + | <math>l_0</math>-начальная длина одной пружины <br/> |
m - масса одной частицы<br /> | m - масса одной частицы<br /> | ||
k - жесткость пружины<br /> | k - жесткость пружины<br /> | ||
B - вязкость | B - вязкость | ||
− | + | ||
+ | ===Интерфейс программы=== | ||
+ | Оба конца закреплены. Возможно задавать колебания, оттягивая один из элементов. По нажатию кнопки "Sin", левая граница движется по закону синуса. При повторном нажатии, левая граница останавливается. Кнопка "Reset" устанавливает систему в начальное положение. Ползунки:<br/> | ||
+ | g - сила тяжести<br/> | ||
+ | B - вязкость<br/> | ||
+ | ν - частота колебания левой границы (работает только при "Sin")<br/> | ||
+ | A - амплитуда колебания левой границы (работает только при "Sin")<br/> | ||
===Результаты=== | ===Результаты=== | ||
Строка 26: | Строка 32: | ||
[[Медиа:OscSpring.rar|Скачать архив]] | [[Медиа:OscSpring.rar|Скачать архив]] | ||
+ | <br /> | ||
+ | <br /> | ||
+ | <div class="mw-collapsible mw-collapsed" style="width:100%" > | ||
+ | '''Текст программы на языке JavaScript (разработчик [[Богданов Дмитрий]]):''' <div class="mw-collapsible-content"> | ||
+ | Файл '''"Test.js"''' | ||
+ | <syntaxhighlight lang="javascript" line start="1" enclose="div"> | ||
+ | function Main_Spring(canvas, slider_g, text_g, slider_nu, text_nu, slider_A, text_A, sinbutton) { | ||
+ | var canvas, ctx, w, h, world, lineBody, lineBody1, mouseConstraint, s, s1; // переменные: канвас, содержимое канваса, ширина и высота канваса, создание "мира" p2, парвая и левая "стена", закрепление мыши, пружины для связи со стенами | ||
+ | var scaleX = 50, scaleY = -50; //масштаб | ||
+ | var circleBody2 = new Array(); //массив шариков | ||
+ | var circleShape2 = new Array(); //массив форм шариков | ||
+ | var ss = new Array();//массив пружин | ||
+ | var num = 100; //общее кол-во частиц | ||
+ | var k = 250; // жесткость пружин | ||
+ | var B = 4; // вязкость | ||
+ | var R = 0.05; //радиус шаров | ||
+ | var dx = 0.01; // начальная длина пружин | ||
+ | var g = 0; // сила тяжести | ||
+ | var dtt = 0; // время для колебаний по sin | ||
+ | var LA = 2; // смещение по вертикали для sin | ||
+ | var dt = 0.03; // "скорость" для sin | ||
+ | var sw = 0; // переключатель для кнопок | ||
+ | |||
+ | // Инициализируем канвал и действия маши | ||
+ | canvas = document.getElementById("myCanvas"); | ||
+ | w = canvas.width; | ||
+ | h = canvas.height; | ||
+ | ctx = canvas.getContext("2d"); | ||
+ | ctx.lineWidth = 0.05; | ||
+ | canvas.addEventListener("mousedown", doMouseDown, false); | ||
+ | canvas.addEventListener("mousemove", doMouseMove, false); | ||
+ | canvas.addEventListener("mouseup", doMouseUp, false); | ||
+ | |||
+ | // Ползунки и текстовые поля | ||
+ | this.setSlider_g = function(new_g){g = new_g; world.gravity[1] = -g;}; | ||
+ | this.setSlider_nu = function(new_nu){dt = new_nu/10;}; | ||
+ | this.setSlider_A = function(new_A){LA = new_A*4;}; | ||
+ | this.setSlider_B = function(new_B){B = new_B*12; s.damping = B; s1.damping = B; | ||
+ | for (var i = 0; i < num-1; i++){ss[i].damping = B;}; | ||
+ | for (var j = 0; j < num; j++){circleBody2[j].damping=B/24;};}; | ||
+ | |||
+ | slider_g.min = 0; slider_g.max = 1; | ||
+ | slider_g.step = 0.10; | ||
+ | slider_g.value = g; | ||
+ | text_g.value = g.toFixed(1); | ||
+ | |||
+ | slider_A.min = 0; slider_A.max = 1; | ||
+ | slider_A.step = 0.10; | ||
+ | slider_A.value = LA/4; | ||
+ | text_A.value = (LA/4).toFixed(1); | ||
+ | |||
+ | |||
+ | slider_B.min = 0; slider_B.max = 1; | ||
+ | slider_B.step = 0.10; | ||
+ | slider_B.value = B/12; | ||
+ | text_B.value = (B/12).toFixed(1); | ||
+ | |||
+ | slider_nu.min = 0; slider_nu.max = 1; | ||
+ | slider_nu.step = 0.10; | ||
+ | slider_nu.value = dt*10; // начальное значение ползунка должно задаваться после min и max | ||
+ | text_nu.value = (dt*10).toFixed(1); | ||
+ | |||
+ | init(); | ||
+ | animate(); | ||
+ | |||
+ | // Функция "переключения" кнопок | ||
+ | this.sw = function(a) | ||
+ | { | ||
+ | if (a==-1) sw = a; | ||
+ | else | ||
+ | sw += a; | ||
+ | } | ||
+ | |||
+ | // Функция движения левой границы по Sin | ||
+ | function FSin() | ||
+ | { | ||
+ | sinbutton.value = "Стоп"; | ||
+ | sw = 1; | ||
+ | dtt+=dt; | ||
+ | s.localAnchorB[0] = 4-LA * (Math.sin(dtt)/2); | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | function Stop() | ||
+ | { | ||
+ | sw = 0; | ||
+ | sinbutton.value = "Sin"; | ||
+ | } | ||
+ | |||
+ | // Функция сброса | ||
+ | function Reset() | ||
+ | { | ||
+ | if (sinbutton.value != "Sin") sinbutton.value = "Sin"; | ||
+ | dtt = 0; | ||
+ | sw = 0; | ||
+ | world.clear(); | ||
+ | init(); | ||
+ | |||
+ | } | ||
+ | |||
+ | // Функция создания всех объектов | ||
+ | function init(){ | ||
+ | |||
+ | // Создание мира p2 | ||
+ | world = new p2.World(); | ||
+ | world.gravity[1] = -g; | ||
+ | world.solver.iterations = 10; | ||
+ | world.solver.frictionIterations = 0; | ||
+ | |||
+ | // Создаем левую границу | ||
+ | lineShape = new p2.Line({ length: 6 }); | ||
+ | lineBody = new p2.Body({ | ||
+ | position: [-6,-4], | ||
+ | angle: Math.PI/2 | ||
+ | }); | ||
+ | lineBody.addShape(lineShape, [0,0], Math.PI ); | ||
+ | world.addBody(lineBody); | ||
+ | |||
+ | // Создаем правую границу | ||
+ | lineShape1 = new p2.Line({ length: 6 }); | ||
+ | lineBody1 = new p2.Body({ | ||
+ | position: [6,-4], | ||
+ | angle: Math.PI/2 | ||
+ | }); | ||
+ | lineBody1.addShape(lineShape1, [0,0], Math.PI ); | ||
+ | world.addBody(lineBody1); | ||
+ | |||
+ | // Создаем все шарики | ||
+ | for (var i = 0; i < num; i++) | ||
+ | { | ||
+ | circleShape2[i] = new p2.Circle({ radius: R }); | ||
+ | circleBody2[i] = new p2.Body({ mass:0.5, position:[(-6 + (12*(i+1)/(num+1))) ,0] , angularDamping:0, damping:B/24}); | ||
+ | circleBody2[i].addShape(circleShape2[i]); | ||
+ | world.addBody(circleBody2[i]); | ||
+ | }; | ||
+ | |||
+ | //Создаем пружину для связи с левой границей | ||
+ | s = new p2.LinearSpring(circleBody2[0], lineBody, { | ||
+ | restLength : dx, | ||
+ | stiffness : k, | ||
+ | damping : B, | ||
+ | localAnchorB : [4,0], | ||
+ | }); | ||
+ | world.addSpring(s); | ||
+ | |||
+ | // Создаем пружину для связи с правой границей | ||
+ | s1 = new p2.LinearSpring(circleBody2[num-1], lineBody1, { | ||
+ | restLength : dx, | ||
+ | stiffness : k, | ||
+ | damping : B, | ||
+ | localAnchorB : [4,0], | ||
+ | }); | ||
+ | world.addSpring(s1); | ||
+ | |||
+ | // Создаем пружины для связи шариков вместе | ||
+ | for (var i = 0; i < num-1; i++) | ||
+ | { | ||
+ | ss[i] = new p2.LinearSpring(circleBody2[i], circleBody2[i+1], { | ||
+ | restLength : dx, | ||
+ | stiffness : k, | ||
+ | damping : B, | ||
+ | localAnchorA : [0,0], | ||
+ | localAnchorB : [0,0], | ||
+ | }); | ||
+ | world.addSpring(ss[i]); | ||
+ | }; | ||
+ | |||
+ | //Отключаем взаимодействие между пружинами и между шариками | ||
+ | for (var i = 0; i < num-1; i++) | ||
+ | { | ||
+ | for (var j = i; j < num-1; j++) | ||
+ | { | ||
+ | world.disableBodyCollision(ss[i], ss[j]); | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | for (var i = 0; i < num; i++) | ||
+ | { | ||
+ | for (var j = i; j < num; j++) | ||
+ | { | ||
+ | world.disableBodyCollision(circleBody2[i], circleBody2[j]); | ||
+ | world.disableBodyCollision(circleBody2[i], lineBody1); | ||
+ | world.disableBodyCollision(circleBody2[i], lineBody); | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | // Создаем объект для мыши | ||
+ | mouseBody = new p2.Body(); | ||
+ | world.addBody(mouseBody); | ||
+ | |||
+ | } | ||
+ | |||
+ | // Функция нажатия мыши вниз | ||
+ | function doMouseDown(event){ | ||
+ | var position = getPhysicsCoord(event); | ||
+ | circleBody2.forEach(function(item, i, circleBody2) | ||
+ | { | ||
+ | var hitBodies = world.hitTest(position, [item]); | ||
+ | if(hitBodies.length){ | ||
+ | mouseBody.position[0] = position[0]; | ||
+ | mouseBody.position[1] = position[1]; | ||
+ | mouseConstraint = new p2.LockConstraint(mouseBody, item); | ||
+ | world.addConstraint(mouseConstraint); | ||
+ | } | ||
+ | }); | ||
+ | } | ||
+ | |||
+ | // Функция перемещения мыши | ||
+ | function doMouseMove(event){ | ||
+ | var position = getPhysicsCoord(event); | ||
+ | mouseBody.position[0] = position[0]; | ||
+ | mouseBody.position[1] = position[1]; | ||
+ | } | ||
+ | |||
+ | // Функция отпуская клавиши мыши | ||
+ | function doMouseUp(event){ | ||
+ | world.removeConstraint(mouseConstraint); | ||
+ | } | ||
+ | |||
+ | // Перевод координат мыши в текущие координаты | ||
+ | function getPhysicsCoord(mouseEvent){ | ||
+ | var rect = canvas.getBoundingClientRect(); | ||
+ | var x = mouseEvent.clientX - rect.left; | ||
+ | var y = mouseEvent.clientY - rect.top; | ||
+ | x = (x - w / 2) / scaleX; | ||
+ | y = (y - h / 2) / scaleY; | ||
+ | |||
+ | return [x, y]; | ||
+ | } | ||
+ | |||
+ | // Функция рисования всех шаров | ||
+ | function drawAllCircle(){ | ||
+ | for (var i = 0; i < num; i++) | ||
+ | { | ||
+ | ctx.beginPath(); | ||
+ | var x1 = circleBody2[i].position[0], | ||
+ | y1 = circleBody2[i].position[1], | ||
+ | radius1 = circleShape2[i].radius; | ||
+ | ctx.arc(x1,y1,radius1,0,2*Math.PI); | ||
+ | ctx.fill(); | ||
+ | ctx.stroke(); | ||
+ | } | ||
+ | ctx.strokeStyle = "black"; | ||
+ | } | ||
+ | |||
+ | // Рисуем пол | ||
+ | function drawPlane(){ | ||
+ | ctx.moveTo(-w, -4); | ||
+ | ctx.lineTo( w, -4); | ||
+ | ctx.strokeStyle = "black"; | ||
+ | ctx.stroke(); | ||
+ | } | ||
+ | |||
+ | // Рисуем правую стену | ||
+ | function drawRL(){ | ||
+ | ctx.beginPath(); | ||
+ | var x = lineBody.position[0], | ||
+ | y = lineBody.position[1]; | ||
+ | ctx.moveTo(x, -y); | ||
+ | ctx.lineTo(x, y); | ||
+ | ctx.strokeStyle = "black"; | ||
+ | ctx.stroke(); | ||
+ | } | ||
+ | |||
+ | |||
+ | // Рисуем левую стену | ||
+ | function drawLL(){ | ||
+ | ctx.beginPath(); | ||
+ | var x = lineBody1.position[0], | ||
+ | y = lineBody1.position[1]; | ||
+ | ctx.moveTo(x, -y); | ||
+ | ctx.lineTo(x, y); | ||
+ | ctx.strokeStyle = "black"; | ||
+ | ctx.stroke(); | ||
+ | } | ||
+ | |||
+ | // Рисуем все пружины | ||
+ | function drawAllSpring(){ | ||
+ | for (var i = 0; i < num-1; i++) | ||
+ | { | ||
+ | ctx.beginPath(); | ||
+ | var x = circleBody2[i].position[0], | ||
+ | y = circleBody2[i].position[1]; | ||
+ | var x1 = circleBody2[i+1].position[0], | ||
+ | y1 = circleBody2[i+1].position[1]; | ||
+ | ctx.moveTo(x, y); | ||
+ | ctx.lineTo(x1, y1); | ||
+ | ctx.strokeStyle = "black"; | ||
+ | ctx.stroke(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Рисуем пружину для связи первого шарика со стеной | ||
+ | function draw1S(){ | ||
+ | ctx.beginPath(); | ||
+ | var x = circleBody2[0].position[0], | ||
+ | y = circleBody2[0].position[1]; | ||
+ | ctx.moveTo(-6, (s.localAnchorB[0]-4)); | ||
+ | ctx.lineTo(x, y); | ||
+ | ctx.strokeStyle = "black"; | ||
+ | ctx.stroke(); | ||
+ | } | ||
+ | |||
+ | // Рисуем пружину для связи последнего шарика со стеной | ||
+ | function draw2S(){ | ||
+ | ctx.beginPath(); | ||
+ | var x = circleBody2[num-1].position[0], | ||
+ | y = circleBody2[num-1].position[1]; | ||
+ | ctx.moveTo(6, 0); | ||
+ | ctx.lineTo(x, y); | ||
+ | ctx.strokeStyle = "black"; | ||
+ | ctx.stroke(); | ||
+ | } | ||
+ | |||
+ | function render(){ | ||
+ | ctx.clearRect(0,0,w,h); | ||
+ | ctx.save(); | ||
+ | ctx.translate(w/2, h/2); // Переводим начало в центр | ||
+ | ctx.scale(50, -50); //Зумируем канвас | ||
+ | // Рисуем все тела на канвасе | ||
+ | drawAllCircle(); | ||
+ | drawRL(); | ||
+ | drawLL(); | ||
+ | drawPlane(); | ||
+ | drawAllSpring(); | ||
+ | draw1S(); | ||
+ | draw2S(); | ||
+ | ctx.restore(); | ||
+ | } | ||
+ | |||
+ | function animate(){ | ||
+ | requestAnimationFrame(animate); | ||
+ | if (sw == 1) FSin(); | ||
+ | if (sw == 2) Stop(); | ||
+ | if (sw == -1) Reset(); | ||
+ | world.step(1/60); | ||
+ | render(); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | </div> | ||
+ | </div> | ||
+ | |||
+ | == Ссылки == | ||
+ | *[https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D1%83%D0%B6%D0%B8%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B0%D1%8F%D1%82%D0%BD%D0%B8%D0%BA Пружинный маятник] | ||
+ | *[[Курсовые работы по ВМДС: 2015-2016]] | ||
+ | *[[Введение в механику дискретных сред]] | ||
+ | * [[VirtLab| Виртуальная лаборатория]] |
Текущая версия на 00:05, 13 января 2016
Виртуальная лаборатория > Поперечные волны в струнеСодержание
Курсовой проект по механике дискретных сред[править]
- разработчик Богданов Дмитрий
- руководитель Кузькин Виталий
Цель проекта[править]
Разработка программы моделирующая колебания струны
Математическая модель[править]
-начальная длина одной пружины
m - масса одной частицы
k - жесткость пружины
B - вязкость
Интерфейс программы[править]
Оба конца закреплены. Возможно задавать колебания, оттягивая один из элементов. По нажатию кнопки "Sin", левая граница движется по закону синуса. При повторном нажатии, левая граница останавливается. Кнопка "Reset" устанавливает систему в начальное положение. Ползунки:
g - сила тяжести
B - вязкость
ν - частота колебания левой границы (работает только при "Sin")
A - амплитуда колебания левой границы (работает только при "Sin")
Результаты[править]
Текст программы на языке JavaScript (разработчик Богданов Дмитрий):
Файл "Test.js"
1 function Main_Spring(canvas, slider_g, text_g, slider_nu, text_nu, slider_A, text_A, sinbutton) {
2 var canvas, ctx, w, h, world, lineBody, lineBody1, mouseConstraint, s, s1; // переменные: канвас, содержимое канваса, ширина и высота канваса, создание "мира" p2, парвая и левая "стена", закрепление мыши, пружины для связи со стенами
3 var scaleX = 50, scaleY = -50; //масштаб
4 var circleBody2 = new Array(); //массив шариков
5 var circleShape2 = new Array(); //массив форм шариков
6 var ss = new Array();//массив пружин
7 var num = 100; //общее кол-во частиц
8 var k = 250; // жесткость пружин
9 var B = 4; // вязкость
10 var R = 0.05; //радиус шаров
11 var dx = 0.01; // начальная длина пружин
12 var g = 0; // сила тяжести
13 var dtt = 0; // время для колебаний по sin
14 var LA = 2; // смещение по вертикали для sin
15 var dt = 0.03; // "скорость" для sin
16 var sw = 0; // переключатель для кнопок
17
18 // Инициализируем канвал и действия маши
19 canvas = document.getElementById("myCanvas");
20 w = canvas.width;
21 h = canvas.height;
22 ctx = canvas.getContext("2d");
23 ctx.lineWidth = 0.05;
24 canvas.addEventListener("mousedown", doMouseDown, false);
25 canvas.addEventListener("mousemove", doMouseMove, false);
26 canvas.addEventListener("mouseup", doMouseUp, false);
27
28 // Ползунки и текстовые поля
29 this.setSlider_g = function(new_g){g = new_g; world.gravity[1] = -g;};
30 this.setSlider_nu = function(new_nu){dt = new_nu/10;};
31 this.setSlider_A = function(new_A){LA = new_A*4;};
32 this.setSlider_B = function(new_B){B = new_B*12; s.damping = B; s1.damping = B;
33 for (var i = 0; i < num-1; i++){ss[i].damping = B;};
34 for (var j = 0; j < num; j++){circleBody2[j].damping=B/24;};};
35
36 slider_g.min = 0; slider_g.max = 1;
37 slider_g.step = 0.10;
38 slider_g.value = g;
39 text_g.value = g.toFixed(1);
40
41 slider_A.min = 0; slider_A.max = 1;
42 slider_A.step = 0.10;
43 slider_A.value = LA/4;
44 text_A.value = (LA/4).toFixed(1);
45
46
47 slider_B.min = 0; slider_B.max = 1;
48 slider_B.step = 0.10;
49 slider_B.value = B/12;
50 text_B.value = (B/12).toFixed(1);
51
52 slider_nu.min = 0; slider_nu.max = 1;
53 slider_nu.step = 0.10;
54 slider_nu.value = dt*10; // начальное значение ползунка должно задаваться после min и max
55 text_nu.value = (dt*10).toFixed(1);
56
57 init();
58 animate();
59
60 // Функция "переключения" кнопок
61 this.sw = function(a)
62 {
63 if (a==-1) sw = a;
64 else
65 sw += a;
66 }
67
68 // Функция движения левой границы по Sin
69 function FSin()
70 {
71 sinbutton.value = "Стоп";
72 sw = 1;
73 dtt+=dt;
74 s.localAnchorB[0] = 4-LA * (Math.sin(dtt)/2);
75 return 0;
76 }
77
78 function Stop()
79 {
80 sw = 0;
81 sinbutton.value = "Sin";
82 }
83
84 // Функция сброса
85 function Reset()
86 {
87 if (sinbutton.value != "Sin") sinbutton.value = "Sin";
88 dtt = 0;
89 sw = 0;
90 world.clear();
91 init();
92
93 }
94
95 // Функция создания всех объектов
96 function init(){
97
98 // Создание мира p2
99 world = new p2.World();
100 world.gravity[1] = -g;
101 world.solver.iterations = 10;
102 world.solver.frictionIterations = 0;
103
104 // Создаем левую границу
105 lineShape = new p2.Line({ length: 6 });
106 lineBody = new p2.Body({
107 position: [-6,-4],
108 angle: Math.PI/2
109 });
110 lineBody.addShape(lineShape, [0,0], Math.PI );
111 world.addBody(lineBody);
112
113 // Создаем правую границу
114 lineShape1 = new p2.Line({ length: 6 });
115 lineBody1 = new p2.Body({
116 position: [6,-4],
117 angle: Math.PI/2
118 });
119 lineBody1.addShape(lineShape1, [0,0], Math.PI );
120 world.addBody(lineBody1);
121
122 // Создаем все шарики
123 for (var i = 0; i < num; i++)
124 {
125 circleShape2[i] = new p2.Circle({ radius: R });
126 circleBody2[i] = new p2.Body({ mass:0.5, position:[(-6 + (12*(i+1)/(num+1))) ,0] , angularDamping:0, damping:B/24});
127 circleBody2[i].addShape(circleShape2[i]);
128 world.addBody(circleBody2[i]);
129 };
130
131 //Создаем пружину для связи с левой границей
132 s = new p2.LinearSpring(circleBody2[0], lineBody, {
133 restLength : dx,
134 stiffness : k,
135 damping : B,
136 localAnchorB : [4,0],
137 });
138 world.addSpring(s);
139
140 // Создаем пружину для связи с правой границей
141 s1 = new p2.LinearSpring(circleBody2[num-1], lineBody1, {
142 restLength : dx,
143 stiffness : k,
144 damping : B,
145 localAnchorB : [4,0],
146 });
147 world.addSpring(s1);
148
149 // Создаем пружины для связи шариков вместе
150 for (var i = 0; i < num-1; i++)
151 {
152 ss[i] = new p2.LinearSpring(circleBody2[i], circleBody2[i+1], {
153 restLength : dx,
154 stiffness : k,
155 damping : B,
156 localAnchorA : [0,0],
157 localAnchorB : [0,0],
158 });
159 world.addSpring(ss[i]);
160 };
161
162 //Отключаем взаимодействие между пружинами и между шариками
163 for (var i = 0; i < num-1; i++)
164 {
165 for (var j = i; j < num-1; j++)
166 {
167 world.disableBodyCollision(ss[i], ss[j]);
168 }
169 };
170
171 for (var i = 0; i < num; i++)
172 {
173 for (var j = i; j < num; j++)
174 {
175 world.disableBodyCollision(circleBody2[i], circleBody2[j]);
176 world.disableBodyCollision(circleBody2[i], lineBody1);
177 world.disableBodyCollision(circleBody2[i], lineBody);
178 }
179 };
180
181 // Создаем объект для мыши
182 mouseBody = new p2.Body();
183 world.addBody(mouseBody);
184
185 }
186
187 // Функция нажатия мыши вниз
188 function doMouseDown(event){
189 var position = getPhysicsCoord(event);
190 circleBody2.forEach(function(item, i, circleBody2)
191 {
192 var hitBodies = world.hitTest(position, [item]);
193 if(hitBodies.length){
194 mouseBody.position[0] = position[0];
195 mouseBody.position[1] = position[1];
196 mouseConstraint = new p2.LockConstraint(mouseBody, item);
197 world.addConstraint(mouseConstraint);
198 }
199 });
200 }
201
202 // Функция перемещения мыши
203 function doMouseMove(event){
204 var position = getPhysicsCoord(event);
205 mouseBody.position[0] = position[0];
206 mouseBody.position[1] = position[1];
207 }
208
209 // Функция отпуская клавиши мыши
210 function doMouseUp(event){
211 world.removeConstraint(mouseConstraint);
212 }
213
214 // Перевод координат мыши в текущие координаты
215 function getPhysicsCoord(mouseEvent){
216 var rect = canvas.getBoundingClientRect();
217 var x = mouseEvent.clientX - rect.left;
218 var y = mouseEvent.clientY - rect.top;
219 x = (x - w / 2) / scaleX;
220 y = (y - h / 2) / scaleY;
221
222 return [x, y];
223 }
224
225 // Функция рисования всех шаров
226 function drawAllCircle(){
227 for (var i = 0; i < num; i++)
228 {
229 ctx.beginPath();
230 var x1 = circleBody2[i].position[0],
231 y1 = circleBody2[i].position[1],
232 radius1 = circleShape2[i].radius;
233 ctx.arc(x1,y1,radius1,0,2*Math.PI);
234 ctx.fill();
235 ctx.stroke();
236 }
237 ctx.strokeStyle = "black";
238 }
239
240 // Рисуем пол
241 function drawPlane(){
242 ctx.moveTo(-w, -4);
243 ctx.lineTo( w, -4);
244 ctx.strokeStyle = "black";
245 ctx.stroke();
246 }
247
248 // Рисуем правую стену
249 function drawRL(){
250 ctx.beginPath();
251 var x = lineBody.position[0],
252 y = lineBody.position[1];
253 ctx.moveTo(x, -y);
254 ctx.lineTo(x, y);
255 ctx.strokeStyle = "black";
256 ctx.stroke();
257 }
258
259
260 // Рисуем левую стену
261 function drawLL(){
262 ctx.beginPath();
263 var x = lineBody1.position[0],
264 y = lineBody1.position[1];
265 ctx.moveTo(x, -y);
266 ctx.lineTo(x, y);
267 ctx.strokeStyle = "black";
268 ctx.stroke();
269 }
270
271 // Рисуем все пружины
272 function drawAllSpring(){
273 for (var i = 0; i < num-1; i++)
274 {
275 ctx.beginPath();
276 var x = circleBody2[i].position[0],
277 y = circleBody2[i].position[1];
278 var x1 = circleBody2[i+1].position[0],
279 y1 = circleBody2[i+1].position[1];
280 ctx.moveTo(x, y);
281 ctx.lineTo(x1, y1);
282 ctx.strokeStyle = "black";
283 ctx.stroke();
284 }
285 }
286
287 // Рисуем пружину для связи первого шарика со стеной
288 function draw1S(){
289 ctx.beginPath();
290 var x = circleBody2[0].position[0],
291 y = circleBody2[0].position[1];
292 ctx.moveTo(-6, (s.localAnchorB[0]-4));
293 ctx.lineTo(x, y);
294 ctx.strokeStyle = "black";
295 ctx.stroke();
296 }
297
298 // Рисуем пружину для связи последнего шарика со стеной
299 function draw2S(){
300 ctx.beginPath();
301 var x = circleBody2[num-1].position[0],
302 y = circleBody2[num-1].position[1];
303 ctx.moveTo(6, 0);
304 ctx.lineTo(x, y);
305 ctx.strokeStyle = "black";
306 ctx.stroke();
307 }
308
309 function render(){
310 ctx.clearRect(0,0,w,h);
311 ctx.save();
312 ctx.translate(w/2, h/2); // Переводим начало в центр
313 ctx.scale(50, -50); //Зумируем канвас
314 // Рисуем все тела на канвасе
315 drawAllCircle();
316 drawRL();
317 drawLL();
318 drawPlane();
319 drawAllSpring();
320 draw1S();
321 draw2S();
322 ctx.restore();
323 }
324
325 function animate(){
326 requestAnimationFrame(animate);
327 if (sw == 1) FSin();
328 if (sw == 2) Stop();
329 if (sw == -1) Reset();
330 world.step(1/60);
331 render();
332 }
333
334 }