Поперечные волны в струне
Курсовой проект по механике дискретных сред
- разработчик Богданов Дмитрий
- руководитель Кузькин Виталий
Цель проекта
Разработка программы моделирующая колебания струны
Решение
r = r(x,y)
m - масса одной частицы
k - жесткость пружины
B - вязкость
Обе конца пружины закреплены
Результаты
Файл "Test.js" 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>