Алексей Безбородов
2 years ago
2 changed files with 246 additions and 7 deletions
@ -0,0 +1,243 @@
|
||||
<!-- Copyright 2023 by Alexei Bezborodov <AlexeiBv+mirocod_wave_simulate@narod.ru> --> |
||||
<!-- public domain --> |
||||
|
||||
<html lang="ru"> |
||||
|
||||
<head> |
||||
<meta charset="UTF-8"> |
||||
<title>Симуляция волн</title> |
||||
|
||||
<!-- |
||||
Загрузка скриптов из интернета |
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/brython@3.8.9/brython.min.js"></script> |
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/brython@3.8.9/brython_stdlib.js"></script> |
||||
--> |
||||
|
||||
<!-- |
||||
Загрузка скриптов из локальной папки (рядом с файлом html) |
||||
--> |
||||
<script type="text/javascript" src="brython.min.js"></script> |
||||
<script type="text/javascript" src="brython_stdlib.js"></script> |
||||
|
||||
|
||||
</head> |
||||
|
||||
<body onload="brython()"> |
||||
|
||||
<details open> |
||||
<summary>Расчётные данные</summary> |
||||
<div> |
||||
<p> |
||||
<input type="range" id="max_step_range" for="max_step" name="volume" min="10" max="1000" value="20" |
||||
oninput='document.getElementById("max_step").value = document.getElementById("max_step_range").value;'> |
||||
<input id = "max_step" type="number" value="20" step="1" |
||||
oninput='recalculate();'/> |
||||
<label for="max_step" alt="Количество расчётных точек на всю длину среды">Точек расчёта</label> |
||||
</p> |
||||
|
||||
<p> |
||||
<input type="checkbox" id="right_second" checked /> |
||||
<label for="right_second" alt="">Вторая половина справа - другая среда</label> |
||||
</p> |
||||
|
||||
<p> |
||||
<input type="checkbox" id="generate" checked /> |
||||
<label for="generate" alt="">Генерирование волны слева</label> |
||||
</p> |
||||
|
||||
<p> |
||||
<input type="range" id="length_range" for="omega" name="volume" min="0" max="200" value="50" |
||||
oninput='document.getElementById("length").value = document.getElementById("length_range").value / 100;'> |
||||
<input id = "length" type="number" value="0.5" step=".01"/> |
||||
<label for="length" alt="">Длина волны</label> |
||||
</p> |
||||
|
||||
<p> |
||||
<input type="range" id="omega_range" for="omega" name="volume" min="-1000" max="1000" value="10" |
||||
oninput='document.getElementById("omega").value = document.getElementById("omega_range").value / 100;'> |
||||
<input id = "omega" type="number" value="0.1" step=".01"/> |
||||
<label for="omega" alt="">Шаг фазы</label> |
||||
</p> |
||||
|
||||
<p> |
||||
<input type="range" id="acsel_range" for="omega" name="volume" min="0" max="1000" value="2" |
||||
oninput='document.getElementById("acsel").value = document.getElementById("acsel_range").value / 100;'> |
||||
<input id = "acsel" type="number" value="0.02" step=".01"/> |
||||
<label for="acsel" alt="">Ускрение слева</label> |
||||
</p> |
||||
|
||||
<p> |
||||
<input type="range" id="acsel_second_range" for="omega" name="volume" min="0" max="1000" value="1" |
||||
oninput='document.getElementById("acsel_second").value = document.getElementById("acsel_second_range").value / 100;'> |
||||
<input id = "acsel_second" type="number" value="0.001" step=".01"/> |
||||
<label for="acsel_second" alt="">Ускрение справа</label> |
||||
</p> |
||||
|
||||
<p> |
||||
<input type="range" id="trenie_range" for="omega" name="volume" min="-0" max="1000" value="980" |
||||
oninput='document.getElementById("trenie").value = document.getElementById("trenie_range").value / 100;'> |
||||
<input id = "trenie" type="number" value="0.98" step=".01"/> |
||||
<label for="trenie" alt="">Трение</label> |
||||
</p> |
||||
|
||||
|
||||
<button id="reload">Загрузить</button> |
||||
</div> |
||||
</details> |
||||
|
||||
<h1 class="text-center">Графики волн</h1> |
||||
<canvas id="draw-board" width="1024" height="500"></canvas> |
||||
|
||||
<script type="text/python"> |
||||
|
||||
from browser import document, html, window |
||||
import random, math |
||||
|
||||
canvas = document["draw-board"] |
||||
ctx = canvas.getContext("2d") |
||||
|
||||
x_border = 10 |
||||
y_border = 10 |
||||
|
||||
max_step = 0 |
||||
|
||||
generate = False |
||||
right_second = False |
||||
|
||||
length = 0.0 |
||||
omega = 0.0 |
||||
delta_omega = 0.0 |
||||
|
||||
trenie = 0.0 |
||||
acsel = 0.0 |
||||
acsel_second = 0.0 |
||||
|
||||
y_values = [] |
||||
vel_values = [] |
||||
|
||||
# Чёрный экран |
||||
def DrawBlackScreen(): |
||||
ctx.fillStyle = "black" |
||||
ctx.fillRect(0, 0, canvas.width, canvas.height) |
||||
|
||||
def DrawLine(x1, y1, x2, y2, lineWidth, style): |
||||
ctx.strokeStyle = style |
||||
ctx.lineWidth = lineWidth |
||||
ctx.beginPath() |
||||
ctx.moveTo(x1, y1) |
||||
ctx.lineTo(x2, y2) |
||||
ctx.stroke() |
||||
return |
||||
|
||||
def DrawAxesScreen(): |
||||
ctx.fillRect(0, 0, canvas.width, canvas.height) |
||||
x1 = x_border |
||||
x2 = canvas.width - x1 |
||||
y1 = y_border |
||||
y2 = canvas.height - y1 |
||||
ym = canvas.height/2 |
||||
style = 'red' |
||||
lw = 2 |
||||
DrawLine(x1, ym, x2, ym, lw, style) |
||||
DrawLine(x1, y1, x1, y2, lw, style) |
||||
DrawLine(x2, y1, x2, y2, lw, style) |
||||
|
||||
def base_func(length, omega): |
||||
return math.sin(length * omega) |
||||
|
||||
def reload(): |
||||
global max_step |
||||
global y_values |
||||
global vel_values |
||||
global generate |
||||
global right_second |
||||
global length |
||||
global delta_omega |
||||
global trenie |
||||
global acsel |
||||
global acsel_second |
||||
|
||||
max_step = int(document["max_step"].value) |
||||
y_values = [0.0] * max_step |
||||
vel_values = [0.0] * max_step |
||||
|
||||
generate = document["generate"].checked |
||||
right_second = document["right_second"].checked |
||||
|
||||
length = float(document["length"].value) |
||||
delta_omega = float(document["omega"].value) |
||||
trenie = float(document["trenie"].value) |
||||
acsel = float(document["acsel"].value) |
||||
acsel_second = float(document["acsel_second"].value) |
||||
|
||||
def recalculate(): |
||||
global max_step |
||||
global y_values |
||||
global vel_values |
||||
global generate |
||||
global right_second |
||||
global length |
||||
global delta_omega |
||||
global trenie |
||||
global acsel |
||||
global acsel_second |
||||
|
||||
global omega |
||||
|
||||
DrawBlackScreen() |
||||
DrawAxesScreen() |
||||
|
||||
pi = math.pi |
||||
|
||||
x1 = x_border |
||||
x2 = canvas.width - x1 |
||||
y1 = y_border |
||||
y2 = canvas.height - y1 |
||||
ym = canvas.height/2 |
||||
style = 'white' |
||||
line_width_scale = 4.0 |
||||
y_scale = 0.3 |
||||
|
||||
cur_x = 0 |
||||
prev_x = cur_x |
||||
|
||||
omega += delta_omega |
||||
|
||||
for i in range(max_step): |
||||
cur_x = x1 + (x2 - x1) * i / max_step |
||||
|
||||
if i == 0 and generate: |
||||
y_values[i] = base_func(length, omega) |
||||
vel_values[i] = 0.0 |
||||
else: |
||||
if i != max_step - 1: |
||||
ac = acsel |
||||
if right_second and i > max_step / 2: |
||||
ac = acsel_second |
||||
vel_values[i] += (y_values[i - 1] - y_values[i]) * ac + (y_values[i + 1] - y_values[i]) * ac |
||||
vel_values[i] *= trenie |
||||
y_values[i] += vel_values[i] |
||||
base_y = ym - (ym - y1) * y_scale * y_values[i] |
||||
base_y_last = ym - (ym - y1) * y_scale * y_values[i - 1] |
||||
|
||||
DrawLine(prev_x, base_y_last, cur_x, base_y, 1.0 * line_width_scale, style) |
||||
|
||||
prev_x = cur_x |
||||
|
||||
def recalculate_event(): |
||||
recalculate() |
||||
|
||||
def reload_event(event): |
||||
reload() |
||||
|
||||
reload() |
||||
|
||||
document["reload"].bind("click", reload_event) |
||||
|
||||
game_loop = window.setInterval(recalculate_event, 1000/20) |
||||
|
||||
</script> |
||||
|
||||
</body> |
||||
|
||||
</html> |
Loading…
Reference in new issue