-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathchladni.js
146 lines (116 loc) · 3.16 KB
/
chladni.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
let particles, sliders, m, n, a, b;
// vibration strength params
let A = 0.02;
let minWalk = 0.002;
const settings = {
nParticles : 20000,
canvasSize : [600, 600],
drawHeatmap : false
}
const pi = 3.1415926535;
// chladni 2D closed-form solution - returns between -1 and 1
const chladni = (x, y, a, b, m, n) =>
a * sin(pi*n*x) * sin(pi*m*y) + b * sin(pi*m*x) * sin(pi*n*y);
/* Initialization */
const DOMinit = () => {
let canvas = createCanvas(...settings.canvasSize);
canvas.parent('sketch-container');
// sliders
sliders = {
m : select('#mSlider'), // freq param 1
n : select('#nSlider'), // freq param 2
a : select('#aSlider'), // freq param 3
b: select('#bSlider'), // freq param 4
v : select('#vSlider'), // velocity
num : select('#numSlider'), // number
}
}
const setupParticles = () => {
// particle array
particles = [];
for (let i = 0; i < settings.nParticles; i++) {
particles[i] = new Particle();
}
}
/* Particle dynamics */
class Particle {
constructor() {
this.x = random(0,1);
this.y = random(0,1);
this.stochasticAmplitude;
// this.color = [random(100,255), random(100,255), random(100,255)];
this.updateOffsets();
}
move() {
// what is our chladni value i.e. how much are we vibrating? (between -1 and 1, zeroes are nodes)
let eq = chladni(this.x, this.y, a, b, m, n);
// set the amplitude of the move -> proportional to the vibration
this.stochasticAmplitude = v * abs(eq);
if (this.stochasticAmplitude <= minWalk) this.stochasticAmplitude = minWalk;
// perform one random walk
this.x += random(-this.stochasticAmplitude, this.stochasticAmplitude);
this.y += random(-this.stochasticAmplitude, this.stochasticAmplitude);
this.updateOffsets();
}
updateOffsets() {
// handle edges
if (this.x <= 0) this.x = 0;
if (this.x >= 1) this.x = 1;
if (this.y <= 0) this.y = 0;
if (this.y >= 1) this.y = 1;
// convert to screen space
this.xOff = width * this.x; // (this.x + 1) / 2 * width;
this.yOff = height * this.y; // (this.y + 1) / 2 * height;
}
show() {
// stroke(...this.color);
point(this.xOff, this.yOff)
}
}
const moveParticles = () => {
let movingParticles = particles.slice(0, N);
// particle movement
for(let particle of movingParticles) {
particle.move();
particle.show();
}
}
const updateParams = () => {
m = sliders.m.value();
n = sliders.n.value();
a = sliders.a.value();
b = sliders.b.value()
v = sliders.v.value();
N = sliders.num.value();
}
const drawHeatmap = () => {
// draw the function heatmap in the background (not working)
if (settings.drawHeatmap) {
let res = 3;
for (let i = 0; i <= width; i+=res) {
for (let j = 0; j <= height; j+=res) {
let eq = chladni(i/width, j/height, a, b, m, n);
noStroke();
fill((eq + 1) * 127.5);
square(i, j, res);
}
}
}
}
const wipeScreen = () => {
background(30);
stroke(255);
}
/* Timing */
// run at DOM load
function setup() {
DOMinit();
setupParticles();
}
// run each frame
function draw() {
wipeScreen();
updateParams();
drawHeatmap();
moveParticles();
}