Разрываемая ткань — различия между версиями
Материал из Department of Theoretical and Applied Mechanics
Wikiadmin (обсуждение | вклад) м (Замена текста — «</syntaxhighligh>» на «</syntaxhighlight>») |
Денис (обсуждение | вклад) |
||
(не показана 1 промежуточная версия 1 участника) | |||
Строка 9: | Строка 9: | ||
Скачать [[Медиа:Tearable_Cloth.zip|Tearable_Cloth.zip]] | Скачать [[Медиа:Tearable_Cloth.zip|Tearable_Cloth.zip]] | ||
− | Текст программы на языке JavaScript (разработчик [http://codepen.io/suffick/pen/KrAwx Suffick]): < | + | <div class="mw-collapsible mw-collapsed" style="width:100%" > |
+ | '''Текст программы на языке JavaScript (разработчик [http://codepen.io/suffick/pen/KrAwx Suffick]):''' <div class="mw-collapsible-content"> | ||
Файл '''"Tearable_Cloth.js"''' | Файл '''"Tearable_Cloth.js"''' | ||
<syntaxhighlight lang="javascript" line start="1" enclose="div"> | <syntaxhighlight lang="javascript" line start="1" enclose="div"> | ||
Строка 308: | Строка 309: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Файл '''"Tearable_Cloth.html"''' | Файл '''"Tearable_Cloth.html"''' | ||
− | <syntaxhighlight lang=" | + | <syntaxhighlight lang="html5" line start="1" enclose="div"> |
<canvas id="c"></canvas> | <canvas id="c"></canvas> | ||
<script src="Tearable_Cloth.js"></script> | <script src="Tearable_Cloth.js"></script> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | </ | + | </div> |
+ | </div> | ||
[[Category: Виртуальная лаборатория]] | [[Category: Виртуальная лаборатория]] |
Текущая версия на 09:43, 11 марта 2015
Виртуальная лаборатория > Разрываемая тканьМоделирование ткани с использованием интегрирования Верле.
Лицензия данной программы предполагает, что вы можете копировать, изменять, публиковать, распространять, и даже продавать данную программу при соблюдении условия сохранения копирайта и заголовка (см. файл ниже) во всех копиях данной программы (или программ, существенно основанных на ней).
Скачать Tearable_Cloth.zip
Текст программы на языке JavaScript (разработчик Suffick):
Файл "Tearable_Cloth.js"
1 /*
2 Copyright (c) 2013 Suffick at Codepen (http://codepen.io/suffick), GitHub (https://github.com/suffick) and lonely-pixel.com
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22
23 // Настройки
24
25 var physics_accuracy = 3, // точность расчетов
26 mouse_influence = 20, // радиус захвата ткани курсором
27 mouse_cut = 5, // радиус обрезания ткани курсором (по правой кнопке мыши)
28 gravity = 1200, // гравитация
29 cloth_height = 30, // ширина ткани
30 cloth_width = 50, // высота ткани
31 start_y = 20, // высота закрепления ткани
32 spacing = 7, // расстояние между узлами ткани
33 tear_distance = 60; // прочность ткани
34
35
36 window.requestAnimFrame =
37 window.requestAnimationFrame ||
38 window.webkitRequestAnimationFrame ||
39 window.mozRequestAnimationFrame ||
40 window.oRequestAnimationFrame ||
41 window.msRequestAnimationFrame ||
42 function (callback) {
43 window.setTimeout(callback, 1000 / 60);
44 };
45
46 var canvas,
47 ctx,
48 cloth,
49 boundsx,
50 boundsy,
51 mouse = {
52 down: false,
53 button: 1,
54 x: 0,
55 y: 0,
56 px: 0,
57 py: 0
58 };
59
60 var Point = function (x, y) {
61
62 this.x = x;
63 this.y = y;
64 this.px = x;
65 this.py = y;
66 this.vx = 0;
67 this.vy = 0;
68 this.pin_x = null;
69 this.pin_y = null;
70
71 this.constraints = [];
72 };
73
74 Point.prototype.update = function (delta) {
75
76 if (mouse.down) {
77
78 var diff_x = this.x - mouse.x,
79 diff_y = this.y - mouse.y,
80 dist = Math.sqrt(diff_x * diff_x + diff_y * diff_y);
81
82 if (mouse.button == 1) {
83
84 if (dist < mouse_influence) {
85 this.px = this.x - (mouse.x - mouse.px) * 1.8;
86 this.py = this.y - (mouse.y - mouse.py) * 1.8;
87 }
88
89 } else if (dist < mouse_cut) this.constraints = [];
90 }
91
92 this.add_force(0, gravity);
93
94 delta *= delta;
95 nx = this.x + ((this.x - this.px) * .99) + ((this.vx / 2) * delta);
96 ny = this.y + ((this.y - this.py) * .99) + ((this.vy / 2) * delta);
97
98 this.px = this.x;
99 this.py = this.y;
100
101 this.x = nx;
102 this.y = ny;
103
104 this.vy = this.vx = 0
105 };
106
107 Point.prototype.draw = function () {
108
109 if (!this.constraints.length) return;
110
111 var i = this.constraints.length;
112 while (i--) this.constraints[i].draw();
113 };
114
115 Point.prototype.resolve_constraints = function () {
116
117 if (this.pin_x != null && this.pin_y != null) {
118
119 this.x = this.pin_x;
120 this.y = this.pin_y;
121 return;
122 }
123
124 var i = this.constraints.length;
125 while (i--) this.constraints[i].resolve();
126
127 this.x > boundsx ? this.x = 2 * boundsx - this.x : 1 > this.x && (this.x = 2 - this.x);
128 this.y < 1 ? this.y = 2 - this.y : this.y > boundsy && (this.y = 2 * boundsy - this.y);
129 };
130
131 Point.prototype.attach = function (point) {
132
133 this.constraints.push(
134 new Constraint(this, point)
135 );
136 };
137
138 Point.prototype.remove_constraint = function (constraint) {
139
140 this.constraints.splice(this.constraints.indexOf(constraint), 1);
141 };
142
143 Point.prototype.add_force = function (x, y) {
144
145 this.vx += x;
146 this.vy += y;
147 };
148
149 Point.prototype.pin = function (pinx, piny) {
150 this.pin_x = pinx;
151 this.pin_y = piny;
152 };
153
154 var Constraint = function (p1, p2) {
155
156 this.p1 = p1;
157 this.p2 = p2;
158 this.length = spacing;
159 };
160
161 Constraint.prototype.resolve = function () {
162
163 var diff_x = this.p1.x - this.p2.x,
164 diff_y = this.p1.y - this.p2.y,
165 dist = Math.sqrt(diff_x * diff_x + diff_y * diff_y),
166 diff = (this.length - dist) / dist;
167
168 if (dist > tear_distance) this.p1.remove_constraint(this);
169
170 var px = diff_x * diff * 0.5;
171 var py = diff_y * diff * 0.5;
172
173 this.p1.x += px;
174 this.p1.y += py;
175 this.p2.x -= px;
176 this.p2.y -= py;
177 };
178
179 Constraint.prototype.draw = function () {
180
181 ctx.moveTo(this.p1.x, this.p1.y);
182 ctx.lineTo(this.p2.x, this.p2.y);
183 };
184
185 var Cloth = function () {
186
187 this.points = [];
188
189 var start_x = canvas.width / 2 - cloth_width * spacing / 2;
190
191 for (var y = 0; y <= cloth_height; y++) {
192
193 for (var x = 0; x <= cloth_width; x++) {
194
195 var p = new Point(start_x + x * spacing, start_y + y * spacing);
196
197 x != 0 && p.attach(this.points[this.points.length - 1]);
198 y == 0 && p.pin(p.x, p.y);
199 y != 0 && p.attach(this.points[x + (y - 1) * (cloth_width + 1)])
200
201 this.points.push(p);
202 }
203 }
204 };
205
206 Cloth.prototype.update = function () {
207
208 var i = physics_accuracy;
209
210 while (i--) {
211 var p = this.points.length;
212 while (p--) this.points[p].resolve_constraints();
213 }
214
215 i = this.points.length;
216 while (i--) this.points[i].update(.016);
217 };
218
219 Cloth.prototype.draw = function () {
220
221 ctx.beginPath();
222
223 var i = cloth.points.length;
224 while (i--) cloth.points[i].draw();
225
226 ctx.stroke();
227 };
228
229 function update() {
230
231 ctx.clearRect(0, 0, canvas.width, canvas.height);
232
233 cloth.update();
234 cloth.draw();
235
236 requestAnimFrame(update); // эта функция через некоторое время снова вызовет update(), так реализуется анимация
237 }
238
239 // Инициализация и запуск программы
240 function start() {
241
242 // функция выполняется при нажатии кнопки мыши
243 canvas.onmousedown = function (e) {
244 mouse.button = e.which;
245 mouse.px = mouse.x;
246 mouse.py = mouse.y;
247 var rect = canvas.getBoundingClientRect();
248 mouse.x = e.clientX - rect.left,
249 mouse.y = e.clientY - rect.top,
250 mouse.down = true;
251 e.preventDefault();
252 };
253
254 // функция выполняется при отпускании клавиши мыши
255 window.onmouseup = function (e) { // на элементе window, чтобы не происходило залипания клавиши мыши
256 mouse.down = false;
257 e.preventDefault();
258 };
259
260 // функция выполняется при движении мыши
261 canvas.onmousemove = function (e) {
262 mouse.px = mouse.x;
263 mouse.py = mouse.y;
264 var rect = canvas.getBoundingClientRect();
265 mouse.x = e.clientX - rect.left,
266 mouse.y = e.clientY - rect.top,
267 e.preventDefault();
268 };
269
270 // функция предотвращает появление контекстного меню
271 canvas.oncontextmenu = function (e) {
272 e.preventDefault();
273 };
274
275 boundsx = canvas.width - 1;
276 boundsy = canvas.height - 1;
277
278 ctx.strokeStyle = '#888'; // цвет ткани
279
280 cloth = new Cloth();
281
282 update(); // начало расчетов/рисования
283 }
284
285 window.onload = function () { // эта функция выполняется при загрузке страницы
286
287 canvas = document.getElementById('c');
288 ctx = canvas.getContext('2d');
289
290 canvas.width = 560;
291 canvas.height = 350;
292
293 start();
294 };
Файл "Tearable_Cloth.html"
1 <canvas id="c"></canvas>
2 <script src="Tearable_Cloth.js"></script>