-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathe_Wave.js
108 lines (95 loc) · 3.16 KB
/
e_Wave.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
Playfield.register_experiment('Wave', function(_module) {
const tau = 2*Math.PI;
const tau_4 = tau/4;
let ctx;
_module.init = function init() {
ctx = Object.create(null);
_module.experiment_context = ctx;
ctx.geometry = [1024, 512];
ctx.koeff = 0.1;
// Displacement field. At boundary, u = 0
ctx.ufield = new Float32Array(ctx.geometry[0] * ctx.geometry[1]);
// Velocity field. At boundary, v = 0, implied by the above
ctx.vfield = new Float32Array(ctx.geometry[0] * ctx.geometry[1]);
ctx.pixels = new Uint8ClampedArray(ctx.geometry[0] * ctx.geometry[1] * 4);
ctx.img = new ImageData(ctx.pixels, ctx.geometry[0], ctx.geometry[1]);
// Make all pixels visible
for (let i = 0; i !== ctx.geometry[0] * ctx.geometry[1]; ++i)
ctx.pixels[(i << 2) | 3] = 0xFF;
// Initial position: x-axis: sine wave of frequency 2; y-axis: sine wave of frequency 3
for (let y = 0; y !== ctx.geometry[1]; ++y) {
for (let x = 0; x !== ctx.geometry[0]; ++x) {
ctx.ufield[y*ctx.geometry[0] + x] =
Math.sin(tau * x / ctx.geometry[0] * 2) *
Math.sin(tau * y / ctx.geometry[1] * 3) ;
}
}
ctx.renderNeeded = true;
ctx.simulationRunning = true;
};
function simulateStep() {
/*
ð²u/ðt² = c² * (ð²u/ðx² + ð²u/ðy²)
Δv/Δt(x, y) = c² * (u(x + 1, y) + u(x - 1, y) - 2*u(x, y) + u(x, y + 1) + u(x, y - 1) - 2*u(x, y))
= c² * (u(x + 1, y) + u(x - 1, y) + u(x, y + 1) + u(x, y - 1) - 4*u(x, y))
Δu/Δt(x, y) = v(x, y)
*/
// Boundaries DON'T MATTER lol, except they do
/*const bases = [
0, // Top left -> right
ctx.geometry[0] - 1, // Top right -> down
(ctx.geometry[1] - 1) * ctx.geometry[0] + 1, // Bottom right <- left
ctx.geometry[0] // Bottom left <- down
];
for (let dir = 0; dir !== 4; ++dir) {
const max = ((dir & 1) ? ctx.geometry[1] : ctx.geometry[0]) - 1;
const base = bases[dir];
const dw = (dir & 1) ? ctx.geometry[0] : 1;
for (let w = 0; w !== max; ++w) {
const idx = base + dw*w;
ctx.vfield[idx] += ctx.koeff * (
dir ===
);
}
}*/
// Interior
for (let y = 1; y !== ctx.geometry[1] - 1; ++y) {
for (let x = 1; x !== ctx.geometry[0] - 1; ++x) {
const idx = y * ctx.geometry[0] + x;
ctx.vfield[idx] += ctx.koeff * (
ctx.ufield[idx + 1] +
ctx.ufield[idx - 1] +
ctx.ufield[idx + ctx.geometry[0]] +
ctx.ufield[idx - ctx.geometry[0]] -
4 * ctx.ufield[idx]
);
}
}
// Apply velocity
for (let y = 0; y !== ctx.geometry[1]; ++y) {
for (let x = 0; x !== ctx.geometry[0]; ++x) {
const idx = y * ctx.geometry[0] + x;
ctx.ufield[idx] += ctx.vfield[idx];
}
}
}
_module.render = function render() {
if (!ctx.renderNeeded)
return;
if (ctx.simulationRunning)
simulateStep();
const dctx = _module.canvas.getContext('2d');
// Gradient: -1 --> red; 0 --> green; 1 --> blue
for (let y = 0; y !== ctx.geometry[1]; ++y) {
for (let x = 0; x !== ctx.geometry[0]; ++x) {
const idx = (y * ctx.geometry[0] + x) << 2;
const val = ctx.ufield[y * ctx.geometry[0] + x];
ctx.pixels[idx + 0] = -val * 0xFF;
ctx.pixels[idx + 1] = Math.cos(tau_4 * val) * 0xFF;
ctx.pixels[idx + 2] = val * 0xFF;
}
}
dctx.clearRect(0, 0, _module.canvas.width, _module.canvas.height);
dctx.putImageData(ctx.img, 0, 0);
};
});