Balls v4 — различия между версиями

Материал из Department of Theoretical and Applied Mechanics
Перейти к: навигация, поиск
 
(не показано 10 промежуточных версий 2 участников)
Строка 1: Строка 1:
[[ТМ|Кафедра ТМ]] > [[Программирование]] > [[Программирование и моделирование в Интернет|Интернет]] > [[JavaScript-программирование|JavaScript]] > [[JavaScript - Balls|Balls]] > '''Balls v4''' <HR>
+
[[Виртуальная лаборатория]] > [[Динамика взаимодействующих частиц]] > [[Balls - версии]] > [[Balls v4]] <HR>
  
<addscript src=Balls_v4_release/>
+
{{#widget:Iframe |url=http://tm.spbstu.ru/htmlets/Tcvetkov/Balls/Balls_v4_release/Balls_v4_release.html |width=830 |height=630 |border=0 }}
<htmlet nocache="yes">Balls_v4_TM</htmlet>
 
  
  
 
Скачать программу: [[Медиа:Balls_v4_release.zip|Balls_v4_release.zip]]
 
Скачать программу: [[Медиа:Balls_v4_release.zip|Balls_v4_release.zip]]
Текст программы на языке JavaScript (разработчики [[Кривцов Антон]], [[Цветков Денис]]): <toggledisplay status=hide showtext="Показать↓" hidetext="Скрыть↑" linkstyle="font-size:default">  
+
<div class="mw-collapsible mw-collapsed" style="width:100%" >
 +
'''Текст программы на языке JavaScript (разработчики [[Кривцов Антон]], [[Цветков Денис]]):''' <div class="mw-collapsible-content">
 
Файл '''"Balls_v4_release.js"'''
 
Файл '''"Balls_v4_release.js"'''
<source lang="javascript" first-line="1">
+
<syntaxhighlight lang="javascript" line start="1" enclose="div">
function MainBalls(canvas) {
+
window.addEventListener("load", MainBalls, true);
 +
function MainBalls() {
  
 
     // Предварительные установки
 
     // Предварительные установки
  
 +
    var canvas = canvasBalls;
 
     var context = canvas.getContext("2d");                  // на context происходит рисование
 
     var context = canvas.getContext("2d");                  // на context происходит рисование
 
     canvas.oncontextmenu = function (e) {return false;};    // блокировка контекстного меню
 
     canvas.oncontextmenu = function (e) {return false;};    // блокировка контекстного меню
  
     const Pi = 3.1415926;                  // число "пи"
+
     var Pi = 3.1415926;                  // число "пи"
  
     const m0 = 1;                          // масштаб массы
+
     var m0 = 1;                          // масштаб массы
     const T0 = 1;                          // масштаб времени (период колебаний исходной системы)
+
     var T0 = 1;                          // масштаб времени (период колебаний исходной системы)
     const a0 = 1;                          // масштаб расстояния (диаметр шара)
+
     var a0 = 1;                          // масштаб расстояния (диаметр шара)
  
     const g0 = a0 / T0 / T0;                // масштаб ускорения (ускорение, при котором за T0 будет пройдено расстояние a0)
+
     var g0 = a0 / T0 / T0;                // масштаб ускорения (ускорение, при котором за T0 будет пройдено расстояние a0)
     const k0 = 2 * Pi / T0;                // масштаб частоты
+
     var k0 = 2 * Pi / T0;                // масштаб частоты
     const C0 = m0 * k0 * k0;                // масштаб жесткости
+
     var C0 = m0 * k0 * k0;                // масштаб жесткости
     const B0 = 2 * m0 * k0;                // масштаб вязкости
+
     var B0 = 2 * m0 * k0;                // масштаб вязкости
  
 
     // *** Задание физических параметров ***
 
     // *** Задание физических параметров ***
  
     const Ny = 5;                          // число шаров, помещающихся по вертикали в окно (задает размер шара относительно размера окна)
+
     var Ny = 5;                          // число шаров, помещающихся по вертикали в окно (задает размер шара относительно размера окна)
     const m = 1 * m0;                      // масса
+
     var m = 1 * m0;                      // масса
     const Cwall = 10 * C0;                  // жесткость стен
+
     var Cwall = 10 * C0;                  // жесткость стен
     const Cball = 0.1 * Cwall;              // жесткость между частицами
+
     var Cball = 0.1 * Cwall;              // жесткость между частицами
     const B = 0.008 * B0;                  // вязкость среды
+
     var B = 0.008 * B0;                  // вязкость среды
     const B1 = 0.03 * B0;                   // вязкость на стенках
+
     var Bwall = 0.03 * B0;               // вязкость на стенках
     const mg = 0.25 * m * g0;              // сила тяжести
+
     var mg = 0.25 * m * g0;              // сила тяжести
     const r = 0.5 * a0;                    // радиус частицы в расчетных координатах
+
     var r = 0.5 * a0;                    // радиус частицы в расчетных координатах
     const arCoeff = 0.75;                   // сила взаимодействия ограничивается значением, реализующимся при r/a = arCoeff
+
     var K = 0.85;                         // сила взаимодействия ограничивается значением, реализующимся при r/a = K
     const a = 2 * r;                        // равновесное расстояние между частицами
+
     var a = 2 * r;                        // равновесное расстояние между частицами
     const aCut = 2 * a;                    // радиус обрезания
+
     var aCut = 2 * a;                    // радиус обрезания
  
 
     // *** Задание вычислительных параметров ***
 
     // *** Задание вычислительных параметров ***
  
     const fps = 50;                        // frames per second - число кадров в секунду (качечтво отображения)
+
     var fps = 50;                        // frames per second - число кадров в секунду (качечтво отображения)
     const spf = 100;                        // steps per frame  - число шагов интегрирования между кадрами (скорость расчета)
+
     var spf = 100;                        // steps per frame  - число шагов интегрирования между кадрами (скорость расчета)
     const dt  = 0.045 * T0 / fps;          // шаг интегрирования (качество расчета)
+
     var dt  = 0.045 * T0 / fps;          // шаг интегрирования (качество расчета)
  
 
     // Выполнение программы
 
     // Выполнение программы
  
     const scale = canvas.height / Ny / a0;  // масштабный коэффициент для перехода от расчетных к экранным координатам
+
     var scale = canvas.height / Ny / a0;  // масштабный коэффициент для перехода от расчетных к экранным координатам
     const r2 = r * r;                      // ___в целях оптимизации___
+
     var r2 = r * r;                      // ___в целях оптимизации___
     const aCut2 = aCut * aCut;              // ___в целях оптимизации___
+
     var aCut2 = aCut * aCut;              // ___в целях оптимизации___
     const a2 = a * a;                      // ___в целях оптимизации___
+
     var a2 = a * a;                      // ___в целях оптимизации___
     const D = a2 * Cball / 72;              // энергия связи между частицами
+
     var D = a2 * Cball / 72;              // энергия связи между частицами
     const LJCoeff = 12 * D / a2;            // коэффициент для расчета потенциала Л-Дж
+
     var LJCoeff = 12 * D / a2;            // коэффициент для расчета потенциала Л-Дж
 +
 
 +
    var Ka = K * a;                      // ___в целях оптимизации___
 +
    var K2a2 = K * K * a2;                // ___в целях оптимизации___
  
 
     var w = canvas.width / scale;          // ширина окна в расчетных координатах
 
     var w = canvas.width / scale;          // ширина окна в расчетных координатах
Строка 73: Строка 78:
 
             var rx = b.x - m.x;
 
             var rx = b.x - m.x;
 
             var ry = b.y - m.y;
 
             var ry = b.y - m.y;
             b.rLen2 = rx * rx + ry * ry;       // квадрат расстояния между курсором и центром шара
+
             var rLen2 = rx * rx + ry * ry;     // квадрат расстояния между курсором и центром шара
             if (b.rLen2 <= r2) {               // курсор нажал на шар
+
             if (rLen2 <= r2) {                 // курсор нажал на шар
 
                 if (e.which == 1) {            // нажата левая клавиша мыши
 
                 if (e.which == 1) {            // нажата левая клавиша мыши
 
                     dNd = b;
 
                     dNd = b;
Строка 168: Строка 173:
 
                     var r2 = rx * rx + ry * ry;                        // квадрат расстояния между шарами
 
                     var r2 = rx * rx + ry * ry;                        // квадрат расстояния между шарами
 
                     if (r2 > aCut2) continue;                          // проверка на радиус обрезания
 
                     if (r2 > aCut2) continue;                          // проверка на радиус обрезания
                     if (r2 < arCoeff * a2) r2 = arCoeff * a2;           // проверка на минимальный радиус
+
                     var rLen = (Math.sqrt(r2));
  
 +
                    // если расстояние между частицами мало, силы будут посчитаны для K * a
 +
                    if (r2 < K2a2) {
 +
                        if (rLen > 0.00001) {                          // проверка, чтобы избежать деления на 0
 +
                            rx = rx / rLen * Ka;
 +
                            ry = ry / rLen * Ka;
 +
                        }
 +
                        r2 = K2a2;
 +
                        rLen = Ka;                                      // корень K2a2
 +
                    }
 +
 +
                    // сила взаимодействия
 
                     var s2 = a2 / r2;        var s4 = s2 * s2;        // ___в целях оптимизации___
 
                     var s2 = a2 / r2;        var s4 = s2 * s2;        // ___в целях оптимизации___
 +
                    var F = LJCoeff * s4 * s4 * (s4 * s2 - 1);          // сила взаимодействия Леннарда-Джонса
  
                    var F = LJCoeff * s4 * s4 * (s4 * s2 - 1);          // сила взаимодействия Леннарда-Джонса
 
 
                     var Fx = F * rx;        var Fy = F * ry;
 
                     var Fx = F * rx;        var Fy = F * ry;
 
 
                     b.fx += Fx;            b.fy += Fy;
 
                     b.fx += Fx;            b.fy += Fy;
 
                     b2.fx -= Fx;            b2.fy -= Fy;
 
                     b2.fx -= Fx;            b2.fy -= Fy;
Строка 181: Строка 196:
 
                 if (b == dNd) continue;  // если шар схвачен курсором - его вз. со стенами и перемещение не считаем
 
                 if (b == dNd) continue;  // если шар схвачен курсором - его вз. со стенами и перемещение не считаем
  
                 if (b.y + r > h) { b.fy += -Cwall * (b.y + r - h) - B1 * b.vy; }
+
                 if (b.y + r > h) { b.fy += -Cwall * (b.y + r - h) - Bwall * b.vy; }
                 if (b.y - r < 0) { b.fy += -Cwall * (b.y - r) - B1 * b.vy;}
+
                 if (b.y - r < 0) { b.fy += -Cwall * (b.y - r) - Bwall * b.vy;}
                 if (b.x + r > w) { b.fx += -Cwall * (b.x + r - w) - B1 * b.vx; }
+
                 if (b.x + r > w) { b.fx += -Cwall * (b.x + r - w) - Bwall * b.vx; }
                 if (b.x - r < 0) { b.fx += -Cwall * (b.x - r) - B1 * b.vx; }
+
                 if (b.x - r < 0) { b.fx += -Cwall * (b.x - r) - Bwall * b.vx; }
  
 
                 b.vx += b.fx / m * dt;        b.vy += b.fy / m * dt;
 
                 b.vx += b.fx / m * dt;        b.vy += b.fy / m * dt;
Строка 218: Строка 233:
 
     setInterval(control, 1000 / fps);
 
     setInterval(control, 1000 / fps);
 
}
 
}
</source>
+
</syntaxhighlight>
 
Файл '''"Balls_v4_release.html"'''
 
Файл '''"Balls_v4_release.html"'''
<source lang="html" first-line="1">
+
<syntaxhighlight lang="html5" line start="1" enclose="div">
 
<!DOCTYPE html>
 
<!DOCTYPE html>
 
<html>
 
<html>
Строка 229: Строка 244:
 
<body>
 
<body>
 
     <canvas id="canvasBalls" width="800" height="600" style="border:1px solid #000000;"></canvas>
 
     <canvas id="canvasBalls" width="800" height="600" style="border:1px solid #000000;"></canvas>
    <script type="text/javascript">MainBalls(document.getElementById('canvasBalls'));</script>
 
 
</body>
 
</body>
 
</html>
 
</html>
</source>
+
</syntaxhighlight>
</toggledisplay>
+
</div>
 +
</div>
  
 +
[[Category: Виртуальная лаборатория]]
 
[[Category: Программирование]]
 
[[Category: Программирование]]
[[Category: JavaScript]]
 

Текущая версия на 08:50, 11 марта 2015

Виртуальная лаборатория > Динамика взаимодействующих частиц > Balls - версии > Balls v4


Скачать программу: Balls_v4_release.zip

Текст программы на языке JavaScript (разработчики Кривцов Антон, Цветков Денис):

Файл "Balls_v4_release.js"

  1 window.addEventListener("load", MainBalls, true);
  2 function MainBalls() {
  3 
  4     // Предварительные установки
  5 
  6     var canvas = canvasBalls;
  7     var context = canvas.getContext("2d");                  // на context происходит рисование
  8     canvas.oncontextmenu = function (e) {return false;};    // блокировка контекстного меню
  9 
 10     var Pi = 3.1415926;                   // число "пи"
 11 
 12     var m0 = 1;                           // масштаб массы
 13     var T0 = 1;                           // масштаб времени (период колебаний исходной системы)
 14     var a0 = 1;                           // масштаб расстояния (диаметр шара)
 15 
 16     var g0 = a0 / T0 / T0;                // масштаб ускорения (ускорение, при котором за T0 будет пройдено расстояние a0)
 17     var k0 = 2 * Pi / T0;                 // масштаб частоты
 18     var C0 = m0 * k0 * k0;                // масштаб жесткости
 19     var B0 = 2 * m0 * k0;                 // масштаб вязкости
 20 
 21     // *** Задание физических параметров ***
 22 
 23     var Ny = 5;                           // число шаров, помещающихся по вертикали в окно (задает размер шара относительно размера окна)
 24     var m = 1 * m0;                       // масса
 25     var Cwall = 10 * C0;                  // жесткость стен
 26     var Cball = 0.1 * Cwall;              // жесткость между частицами
 27     var B = 0.008 * B0;                   // вязкость среды
 28     var Bwall = 0.03 * B0;                // вязкость на стенках
 29     var mg = 0.25 * m * g0;               // сила тяжести
 30     var r = 0.5 * a0;                     // радиус частицы в расчетных координатах
 31     var K = 0.85;                         // сила взаимодействия ограничивается значением, реализующимся при r/a = K
 32     var a = 2 * r;                        // равновесное расстояние между частицами
 33     var aCut = 2 * a;                     // радиус обрезания
 34 
 35     // *** Задание вычислительных параметров ***
 36 
 37     var fps = 50;                         // frames per second - число кадров в секунду (качечтво отображения)
 38     var spf = 100;                        // steps per frame   - число шагов интегрирования между кадрами (скорость расчета)
 39     var dt  = 0.045 * T0 / fps;           // шаг интегрирования (качество расчета)
 40 
 41     // Выполнение программы
 42 
 43     var scale = canvas.height / Ny / a0;  // масштабный коэффициент для перехода от расчетных к экранным координатам
 44     var r2 = r * r;                       // ___в целях оптимизации___
 45     var aCut2 = aCut * aCut;              // ___в целях оптимизации___
 46     var a2 = a * a;                       // ___в целях оптимизации___
 47     var D = a2 * Cball / 72;              // энергия связи между частицами
 48     var LJCoeff = 12 * D / a2;            // коэффициент для расчета потенциала Л-Дж
 49 
 50     var Ka = K * a;                       // ___в целях оптимизации___
 51     var K2a2 = K * K * a2;                // ___в целях оптимизации___
 52 
 53     var w = canvas.width / scale;           // ширина окна в расчетных координатах
 54     var h = canvas.height / scale;          // высота окна в расчетных координатах
 55 
 56     var dNd = null;                         // ссылка на захваченный курсором шар (drag & drop)
 57 
 58     // Работа с мышью
 59 
 60     var mx_, my_;                           // буфер позиции мыши (для расчета скорости при отпускании шара)
 61 
 62     canvas.onmousedown = function(e) {      // функция при нажатии клавиши мыши
 63         var m = mouseCoords(e);             // получаем расчетные координаты курсора мыши
 64         // цикл в обратную сторону, чтобы захватывать шар, нарисованный "сверху"
 65         // (т.к. цикл рисования идет в обычном порядке)
 66         for (var i = balls.length - 1; i >= 0; i--) {
 67             var b = balls[i];
 68             var rx = b.x - m.x;
 69             var ry = b.y - m.y;
 70             var rLen2 = rx * rx + ry * ry;      // квадрат расстояния между курсором и центром шара
 71             if (rLen2 <= r2) {                  // курсор нажал на шар
 72                 if (e.which == 1) {             // нажата левая клавиша мыши
 73                     dNd = b;
 74                     dNd.xPlus = dNd.x - m.x;    // сдвиг курсора относительно центра шара по x
 75                     dNd.yPlus = dNd.y - m.y;    // сдвиг курсора относительно центра шара по y
 76                     mx_ = m.x;    my_ = m.y;
 77                     canvas.onmousemove = mouseMove;     // пока клавиша нажата - работает функция перемещения
 78                 } else if (e.which == 3) {              // нажата правая клавиша мыши
 79                     balls.splice(i, 1);                 // удалить шар
 80                 }
 81                 return;
 82             }
 83         }
 84 
 85         // если не вышли по return из цикла - нажатие было вне шара, добавляем новый
 86         if (e.which == 1) {
 87             dNd = addNewBall(m.x, m.y);         // добавляем шар и сразу захватываем его курсором
 88             if (dNd == null) return;            // если шар не добавился (из за стен или других шаров) - возвращаемся
 89             dNd.xPlus = 0;  dNd.yPlus = 0;      // держим шар по центру
 90             mx_ = m.x;    my_ = m.y;
 91             canvas.onmousemove = mouseMove;     // пока клавиша нажата - работает функция перемещения
 92         }
 93     };
 94 
 95     document.onmouseup = function(e) {          // функция при отпускании клавиши мыши
 96         canvas.onmousemove = null;              // когда клавиша отпущена - функции перемещения нету
 97         dNd = null;                             // когда клавиша отпущена - захваченного курсором шара нету
 98     };
 99 
100     function mouseMove(e) {                     // функция при перемещении мыши, работает только с зажатой ЛКМ
101         var m = mouseCoords(e);                 // получаем расчетные координаты курсора мыши
102         dNd.x = m.x + dNd.xPlus;
103         dNd.y = m.y + dNd.yPlus;
104         dNd.vx = 0.6 * (m.x - mx_) / dt / fps;   dNd.vy = 0.6 * (m.y - my_) / dt / fps;
105         mx_ = m.x;    my_ = m.y;
106     }
107 
108     function mouseCoords(e) {                   // функция возвращает расчетные координаты курсора мыши
109         var m = [];
110         var rect = canvas.getBoundingClientRect();
111         m.x = (e.clientX - rect.left) / scale;
112         m.y = (e.clientY - rect.top) / scale;
113         return m;
114     }
115 
116     // Работа с массивом
117 
118     var balls = [];                             // массив шаров
119     var addNewBall =  function(x, y) {
120         // проверка - не пересекается ли новый шар со стенами или уже существующими шарами
121         if (x - r < 0 || x + r > w || y - r < 0 || y + r > h) return null;
122         for (var i = 0; i < balls.length; i++) {
123             var rx = balls[i].x - x;
124             var ry = balls[i].y - y;
125             var rLen2 = rx * rx + ry * ry;
126             if (rLen2 < 4 * r2) return null;
127         }
128         var b = [];
129 
130         b.x = x;                b.y = y;        // расчетные координаты шара
131         b.fx = 0;               b.fy = mg;      // сила, действующая на шар
132         b.vx = 0;               b.vy = 0;       // скорость
133 
134         balls[balls.length] = b;                // добавить элемент в конец массива
135         return b;
136     };
137 
138     // Основной цикл программы
139 
140     function control() {
141         physics();
142         draw();
143     }
144 
145     // Расчетная часть программы
146 
147     function physics() {                        // то, что происходит каждый шаг времени
148         for (var s = 1; s <= spf; s++) {
149 
150             // пересчет сил идет отдельным массивом, т.к. далее будут добавляться силы взаимодействия между шарами
151             for (var i0 = 0; i0 < balls.length; i0++) {
152                 balls[i0].fx = - B * balls[i0].vx;
153                 balls[i0].fy = mg - B * balls[i0].vy;
154             }
155 
156             for (var i = 0; i < balls.length; i++) {
157                 // расчет взаимодействия производится со всеми следующими шарами в массиве,
158                 // чтобы не считать каждое взаимодействие дважды
159                 var b = balls[i];
160                 for (var j = i + 1; j < balls.length; j++) {
161                     var b2 = balls[j];
162                     var rx = b.x - b2.x;   var ry = b.y - b2.y;         // вектор смотрит на первый шар (b)
163                     var r2 = rx * rx + ry * ry;                         // квадрат расстояния между шарами
164                     if (r2 > aCut2) continue;                           // проверка на радиус обрезания
165                     var rLen = (Math.sqrt(r2));
166 
167                     // если расстояние между частицами мало, силы будут посчитаны для K * a
168                     if (r2 < K2a2) {
169                         if (rLen > 0.00001) {                           // проверка, чтобы избежать деления на 0
170                             rx = rx / rLen * Ka;
171                             ry = ry / rLen * Ka;
172                         }
173                         r2 = K2a2;
174                         rLen = Ka;                                      // корень K2a2
175                     }
176 
177                     // сила взаимодействия
178                     var s2 = a2 / r2;         var s4 = s2 * s2;         // ___в целях оптимизации___
179                     var F = LJCoeff * s4 * s4 * (s4 * s2 - 1);          // сила взаимодействия Леннарда-Джонса
180 
181                     var Fx = F * rx;        var Fy = F * ry;
182                     b.fx += Fx;             b.fy += Fy;
183                     b2.fx -= Fx;            b2.fy -= Fy;
184                 }
185 
186                 if (b == dNd) continue;  // если шар схвачен курсором - его вз. со стенами и перемещение не считаем
187 
188                 if (b.y + r > h) { b.fy += -Cwall * (b.y + r - h) - Bwall * b.vy; }
189                 if (b.y - r < 0) { b.fy += -Cwall * (b.y - r) - Bwall * b.vy;}
190                 if (b.x + r > w) { b.fx += -Cwall * (b.x + r - w) - Bwall * b.vx; }
191                 if (b.x - r < 0) { b.fx += -Cwall * (b.x - r) - Bwall * b.vx; }
192 
193                 b.vx += b.fx / m * dt;        b.vy += b.fy / m * dt;
194                 b.x += b.vx * dt;             b.y += b.vy * dt;
195             }
196         }
197     }
198 
199     // Рисование
200 
201     var rScale13 = r * scale * 1.3;         // ___в целях оптимизации___
202     var rScaleShift = r * scale / 5;        // ___в целях оптимизации___
203     function draw() {
204         context.clearRect(0, 0, w * scale, h * scale);      // очистить экран
205         for (var i = 0; i < balls.length; i++){
206             var xS = balls[i].x * scale;           var yS = balls[i].y * scale;
207             // расчет градиента нужно проводить для каждого шара
208             var gradient = context.createRadialGradient(xS, yS, rScale13, xS - rScaleShift, yS + rScaleShift, 0);
209             gradient.addColorStop(0, "#0000bb");
210             gradient.addColorStop(1, "#44ddff");
211             context.fillStyle = gradient;
212 
213             context.beginPath();
214             context.arc(xS, yS, r * scale, 0, 2 * Math.PI, false);
215             context.closePath();
216             context.fill();
217         }
218     }
219 
220     // Запуск системы
221     for (var i = 0; i < 1000; i++)
222         addNewBall(Math.random() * w, Math.random() * h);
223     setInterval(control, 1000 / fps);
224 }

Файл "Balls_v4_release.html"

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <title>Balls</title>
 5     <script src="Balls_v4_release.js"></script>
 6 </head>
 7 <body>
 8     <canvas id="canvasBalls" width="800" height="600" style="border:1px solid #000000;"></canvas>
 9 </body>
10 </html>