@zushah/chalkboard 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3481 @@
1
+ /*
2
+ The Chalkboard Library
3
+ Version 1.5.0 released 12/18/2023
4
+ Authored by Zushah ===> https://www.github.com/Zushah
5
+ Available under the MIT License ===> https://www.opensource.org/license/mit/
6
+
7
+ The Chalkboard library is a JavaScript namespace that provides a plethora of both practical and abstract mathematical functionalities for its user.
8
+
9
+ Latest release ===> https://www.github.com/Zushah/Chalkboard/releases/tag/v1.5.0
10
+ Documentation ===> https://zushah.github.io/Chalkboard/documentation.html/
11
+ */
12
+ var Chalkboard = {
13
+ README: function() {
14
+ console.log("The Chalkboard Library\nVersion 1.5.0 released 12/18/2023\nAuthored by Zushah ===> https://www.github.com/Zushah\nAvailable under the MIT License ===> https://www.opensource.org/license/mit/\n\nThe Chalkboard library is a JavaScript namespace that provides a plethora of both practical and abstract mathematical functionalities for its user.\n\nLatest release ===> https://www.github.com/Zushah/Chalkboard/releases/tag/v1.5.0\nDocumentation ===> https://zushah.github.io/Chalkboard/documentation.html/");
15
+ },
16
+ LOGO: function(x, y, s, context) {
17
+ x = x || canvas.width / 2;
18
+ y = y || canvas.height / 2;
19
+ s = s || 1;
20
+ context = context || ctx;
21
+ context.save();
22
+ context.translate(x, y);
23
+ context.scale(s, s);
24
+ context.fillStyle = "rgb(25, 25, 25)";
25
+ context.fillRect(-50, -50, 100, 100);
26
+ context.fillStyle = "rgb(50, 125, 200)";
27
+ context.textAlign = "center";
28
+ context.textBaseline = "middle";
29
+ context.font = "75px Times New Roman";
30
+ context.fillText("C", -25, 6);
31
+ context.fillText("B", 25, 6);
32
+ context.strokeStyle = "rgb(50, 125, 200)";
33
+ context.lineWidth = 6;
34
+ context.lineCap = "butt";
35
+ context.beginPath();
36
+ context.moveTo(-30, 25);
37
+ context.lineTo(-30, -22.5);
38
+ context.stroke();
39
+ context.beginPath();
40
+ context.moveTo(22, 25);
41
+ context.lineTo(22, -22.5);
42
+ context.stroke();
43
+ context.restore();
44
+ },
45
+ PI: function(coefficient) {
46
+ coefficient = coefficient || 1;
47
+ return coefficient * 4 * (4 * Math.atan(1/5) - Math.atan(1/239));
48
+ },
49
+ E: function(exponent) {
50
+ exponent = exponent || 1;
51
+ return Math.pow(Math.pow(10, 1 / Math.log(10)), exponent);
52
+ },
53
+ numb: {
54
+ random: function(inf, sup) {
55
+ inf = inf || 0;
56
+ sup = sup || 1;
57
+ return inf + Math.random() * (sup - inf);
58
+ },
59
+ factorial: function(num) {
60
+ if(num >= 0) {
61
+ var n = 1;
62
+ for(var i = 1; i <= num; i++) {
63
+ n *= i;
64
+ }
65
+ i--;
66
+ return n;
67
+ } else if(num < 0) {
68
+ return undefined;
69
+ }
70
+ },
71
+ gcd: function(a, b) {
72
+ if(b === 0) {
73
+ return a;
74
+ }
75
+ return Chalkboard.numb.gcd(b, a % b);
76
+ },
77
+ lcm: function(a, b) {
78
+ return a * (b / Chalkboard.numb.gcd(a, b));
79
+ },
80
+ sum: function(formula, inf, sup) {
81
+ var result = 0;
82
+ var f = Chalkboard.real.parse("n => " + formula);
83
+ for(var i = inf; i <= sup; i++) {
84
+ result += f(i);
85
+ }
86
+ return result;
87
+ },
88
+ mul: function(formula, inf, sup) {
89
+ var result = 1;
90
+ var f = Chalkboard.real.parse("n => " + formula);
91
+ for(var i = inf; i <= sup; i++) {
92
+ result *= f(i);
93
+ }
94
+ return result;
95
+ },
96
+ combination: function(n, r) {
97
+ return Chalkboard.numb.factorial(n) / (Chalkboard.numb.factorial(n - r) * Chalkboard.numb.factorial(r));
98
+ },
99
+ permutation: function(n, r) {
100
+ return Chalkboard.numb.factorial(n) / Chalkboard.numb.factorial(n - r);
101
+ },
102
+ prime: function(num) {
103
+ if(num === 2) {
104
+ return 2;
105
+ }
106
+ var n = 1;
107
+ var prime = 3;
108
+ while(n < num) {
109
+ if(Chalkboard.numb.isPrime(prime)) {
110
+ n++;
111
+ }
112
+ if(n < num) {
113
+ prime += 2;
114
+ }
115
+ }
116
+ return prime;
117
+ },
118
+ isPrime: function(num) {
119
+ for(var i = 2; i <= Chalkboard.real.sqrt(num); i++) {
120
+ if(num % i === 0) {
121
+ return false;
122
+ }
123
+ }
124
+ return num > 1;
125
+ },
126
+ nextPrime: function(num) {
127
+ var result = num + 1;
128
+ while(!Chalkboard.numb.isPrime(result)) {
129
+ result++;
130
+ }
131
+ return result;
132
+ },
133
+ primeGap: function(inf, sup) {
134
+ var prime = null;
135
+ var gap = 0;
136
+ for(var i = inf; i <= sup; i++) {
137
+ if(Chalkboard.numb.isPrime(i)) {
138
+ if(prime !== null) {
139
+ var temp = i - prime;
140
+ if(temp > gap) {
141
+ gap = temp;
142
+ }
143
+ }
144
+ prime = i;
145
+ }
146
+ }
147
+ return gap;
148
+ },
149
+ primeArr: function(inf, sup) {
150
+ var result = [];
151
+ for(var i = inf; i <= sup; i++) {
152
+ if(Chalkboard.numb.isPrime(i)) {
153
+ result.push(i);
154
+ }
155
+ }
156
+ return result;
157
+ },
158
+ primeCount: function(inf, sup) {
159
+ return Chalkboard.numb.primeArr(inf, sup).length;
160
+ },
161
+ compositeArr: function(inf, sup) {
162
+ var result = [];
163
+ for(var i = inf; i <= sup; i++) {
164
+ if(!Chalkboard.numb.isPrime(i)) {
165
+ result.push(i);
166
+ }
167
+ }
168
+ return result;
169
+ },
170
+ compositeCount: function(inf, sup) {
171
+ return Chalkboard.numb.compositeArr(inf, sup).length;
172
+ },
173
+ factors: function(num) {
174
+ var result = [];
175
+ while(num % 2 === 0) {
176
+ result.push(2);
177
+ num /= 2;
178
+ }
179
+ for(var i = 3; i <= Chalkboard.real.sqrt(num); i += 2) {
180
+ while(num % i === 0) {
181
+ result.push(i);
182
+ num /= i;
183
+ }
184
+ }
185
+ if(num > 2) {
186
+ result.push(num);
187
+ }
188
+ return result;
189
+ },
190
+ divisors: function(num) {
191
+ var result = [];
192
+ for(var i = 1; i <= num; i++) {
193
+ if(num % i === 0) {
194
+ result.push(i);
195
+ }
196
+ }
197
+ return result;
198
+ },
199
+ sgn: function(num) {
200
+ if(num < 0) {
201
+ return -1;
202
+ } else if(num === 0) {
203
+ return 0;
204
+ } else if(num > 0) {
205
+ return 1;
206
+ }
207
+ },
208
+ Kronecker: function(a, b) {
209
+ if(a === b) {
210
+ return 1;
211
+ } else if(a !== b) {
212
+ return 0;
213
+ } else {
214
+ return undefined;
215
+ }
216
+ },
217
+ change: function(initial, final) {
218
+ return (final - initial) / initial;
219
+ },
220
+ map: function(num, range1, range2) {
221
+ return range2[0] + (range2[1] - range2[0]) * ((num - range1[0]) / (range1[1] - range1[0]));
222
+ },
223
+ constrain: function(num, range) {
224
+ if(range === undefined) {
225
+ return Math.max(Math.min(num, 1), 0);
226
+ } else {
227
+ return Math.max(Math.min(num, range[1]), range[0]);
228
+ }
229
+ },
230
+ binomial: function(n, k) {
231
+ if(k === 0 || k === n) {
232
+ return 1;
233
+ } else {
234
+ return Chalkboard.numb.binomial(n - 1, k - 1) + Chalkboard.numb.binomial(n - 1, k);
235
+ }
236
+ },
237
+ Fibonacci: function(num) {
238
+ var sequence = [0, 1];
239
+ if(sequence[num] === undefined) {
240
+ sequence.push(Chalkboard.numb.Fibonacci(num - 1) + sequence[num - 2]);
241
+ }
242
+ return sequence[num];
243
+ },
244
+ Gaussian: function(height, mean, deviation) {
245
+ var u, v, s;
246
+ for(;;) {
247
+ u = Chalkboard.numb.random(-1, 1);
248
+ v = Chalkboard.numb.random(-1, 1);
249
+ s = u * u + v * v;
250
+ if(s < 1 && s !== 0) {
251
+ break;
252
+ }
253
+ }
254
+ var z = u * Chalkboard.real.sqrt(-2 * Chalkboard.real.ln(s) / s);
255
+ return z * height * deviation + mean;
256
+ }
257
+ },
258
+ real: {
259
+ function: function(definition, type) {
260
+ type = type || "expl";
261
+ if(type === "expl") {
262
+ return {definition: definition, type: type};
263
+ } else if(type === "pola") {
264
+ return {definition: definition, type: type};
265
+ } else if(type === "curv") {
266
+ return definition.length === 2 ? {definition: [definition[0], definition[1]], type: type} : {definition: [definition[0], definition[1], definition[2]], type: type};
267
+ } else if(type === "surf") {
268
+ return {definition: [definition[0], definition[1], definition[2]], type: type};
269
+ } else if(type === "mult") {
270
+ return {definition: definition, type: type};
271
+ } else {
272
+ return "TypeError: Parameter \"type\" must be either \"expl\", \"pola\", \"curv\", \"surf\", or \"mult\".";
273
+ }
274
+ },
275
+ parse: function(str, init) {
276
+ init = init || '';
277
+ return Function('"use strict"; ' + init + ' return (' + str + ')')();
278
+ },
279
+ val: function(func, val) {
280
+ if(func.type === "expl") {
281
+ var f = Chalkboard.real.parse("x => " + func.definition);
282
+ return f(val);
283
+ } else if(func.type === "pola") {
284
+ var r = Chalkboard.real.parse("O => " + func.definition);
285
+ return r(val);
286
+ } else if(func.type === "curv") {
287
+ if(func.definition.length === 2) {
288
+ var x = Chalkboard.real.parse("t => " + func.definition[0]),
289
+ y = Chalkboard.real.parse("t => " + func.definition[1]);
290
+ return Chalkboard.vec2.new(x(val), y(val));
291
+ } else if(func.definition.length === 3) {
292
+ var x = Chalkboard.real.parse("t => " + func.definition[0]),
293
+ y = Chalkboard.real.parse("t => " + func.definition[1]),
294
+ z = Chalkboard.real.parse("t => " + func.definition[2]);
295
+ return Chalkboard.vec3.new(x(val), y(val), z(val));
296
+ }
297
+ } else if(func.type === "surf") {
298
+ var x = Chalkboard.real.parse("(s, t) => " + func.definition[0]),
299
+ y = Chalkboard.real.parse("(s, t) => " + func.definition[1]),
300
+ z = Chalkboard.real.parse("(s, t) => " + func.definition[2]);
301
+ if(val.type === "vec2") {
302
+ return Chalkboard.vec3.new(x(val.x, val.y), y(val.x, val.y), z(val.x, val.y));
303
+ } else {
304
+ return "TypeError: Parameter \"val\" must be of type \"vec2\".";
305
+ }
306
+ } else if(func.type === "mult") {
307
+ if(val.type === "vec2") {
308
+ var f = Chalkboard.real.parse("(x, y) => " + func.definition);
309
+ return f(val.x, val.y);
310
+ } else {
311
+ return "TypeError: Parameter \"val\" must be of type \"vec2\".";
312
+ }
313
+ } else {
314
+ return "TypeError: Parameter \"func\" must be of type \"expl\", \"pola\", \"curv\", \"surf\", or \"mult\".";
315
+ }
316
+ },
317
+ pow: function(base, num) {
318
+ return Math.exp(num * Math.log(base));
319
+ },
320
+ log: function(base, num) {
321
+ return Chalkboard.real.ln(num) / Chalkboard.real.ln(base);
322
+ },
323
+ ln: function(num) {
324
+ return Chalkboard.calc.fxdx(Chalkboard.real.function("1 / x"), 1, num);
325
+ },
326
+ log10: function(num) {
327
+ return Chalkboard.real.log(10, num);
328
+ },
329
+ sqrt: function(num) {
330
+ if(num >= 0) {
331
+ return Math.exp(Math.log(num) / 2);
332
+ } else if(num < 0) {
333
+ return undefined;
334
+ }
335
+ },
336
+ nrt: function(num, index) {
337
+ return Math.exp(Math.log(num) / index);
338
+ },
339
+ tetration: function(base, num) {
340
+ if(num === 0) {
341
+ return 1;
342
+ } else if(num > 0) {
343
+ return Math.pow(base, Chalkboard.real.tetration(base, num - 1));
344
+ } else {
345
+ return undefined;
346
+ }
347
+ },
348
+ Heaviside: function(num, edge, scl) {
349
+ edge = edge || 0;
350
+ scl = scl || 1;
351
+ if(num >= edge) {
352
+ return scl;
353
+ } else if(num < edge) {
354
+ return 0;
355
+ }
356
+ },
357
+ Dirac: function(num, edge, scl) {
358
+ edge = edge || 0;
359
+ scl = scl || 1;
360
+ if(num === edge) {
361
+ return scl;
362
+ } else if(num !== edge) {
363
+ return 0;
364
+ }
365
+ },
366
+ ramp: function(num, edge, scl) {
367
+ edge = edge || 0;
368
+ scl = scl || 1;
369
+ if(num >= edge) {
370
+ return num * scl;
371
+ } else if(num < edge) {
372
+ return 0;
373
+ }
374
+ },
375
+ rect: function(num, center, width, scl) {
376
+ center = center || 0;
377
+ width = width || 2;
378
+ scl = scl || 1;
379
+ if(num > (center + width / 2) || num < (center - width / 2)) {
380
+ return 0;
381
+ } else if(num <= (center + width / 2) || num >= (center - width / 2)) {
382
+ return scl;
383
+ }
384
+ },
385
+ pingpong: function(num, edge, scl) {
386
+ edge = edge || 0;
387
+ scl = scl || 1;
388
+ if((num + edge) % (2 * scl) < scl) {
389
+ return (num + edge) % scl;
390
+ } else {
391
+ return scl - (num + edge) % scl;
392
+ }
393
+ },
394
+ slope: function(x1, y1, x2, y2) {
395
+ return (y2 - y1) / (x2 - x1);
396
+ },
397
+ linear: function(x1, y1, x2, y2) {
398
+ return Chalkboard.real.function(Chalkboard.real.slope(x1, y1, x2, y2).toString() + " * (x - " + x2.toString() + ") + " + y2.toString());
399
+ },
400
+ linearFormula: function(a, b, c, d) {
401
+ if(c === undefined && d === undefined) {
402
+ return -b / a;
403
+ } else if(d === undefined) {
404
+ return c / a;
405
+ } else {
406
+ return -b / Chalkboard.real.slope(a, b, c, d) + a;
407
+ }
408
+ },
409
+ lerp: function(p, t) {
410
+ return (p[1] - p[0]) * t + p[0];
411
+ },
412
+ quadratic: function(a, b, c, form) {
413
+ form = form || "stan";
414
+ if(form === "stan") {
415
+ return Chalkboard.real.function(a.toString() + "* x * x + " + b.toString() + " * x +" + c.toString());
416
+ } else if(form === "vert") {
417
+ return Chalkboard.real.function(a.toString() + " * ((x - " + b.toString() + ") * (x - " + b.toString() + ")) +" + c.toString());
418
+ } else {
419
+ return "TypeError: Parameter \"form\" must be \"stan\" or \"vert\".";
420
+ }
421
+ },
422
+ discriminant: function(a, b, c, form) {
423
+ form = form || "stan";
424
+ if(form === "stan") {
425
+ return b * b - 4 * a * c;
426
+ } else if(form === "vert") {
427
+ return (2 * a * b) * (2 * a * b) - 4 * a * c;
428
+ } else {
429
+ return "TypeError: Parameter \"form\" must be \"stan\" or \"vert\".";
430
+ }
431
+ },
432
+ quadraticFormula: function(a, b, c, form) {
433
+ form = form || "stan";
434
+ if(form === "stan") {
435
+ return [(-b + Chalkboard.real.sqrt(Chalkboard.real.discriminant(a, b, c, "stan"))) / (2 * a), (-b - Math.sqrt(Chalkboard.real.discriminant(a, b, c, "stan"))) / (2 * a)];
436
+ } else if(form === "vert") {
437
+ return [b + Chalkboard.real.sqrt(-c / a), b - Chalkboard.real.sqrt(-c / a)];
438
+ } else {
439
+ return "TypeError: Parameter \"form\" must be \"stan\" or \"vert\".";
440
+ }
441
+ },
442
+ qerp: function(p1, p2, p3, t) {
443
+ var a = p1[1] / ((p1[0] - p2[0]) * (p1[0] - p3[0])) + p2[1] / ((p2[0] - p1[0]) * (p2[0] - p3[0])) + p3[1] / ((p3[0] - p1[0]) * (p3[0] - p2[0]));
444
+ var b = -p1[1] * (p2[0] + p3[0]) / ((p1[0] - p2[0]) * (p1[0] - p3[0])) - p2[1] * (p1[0] + p3[0]) / ((p2[0] - p1[0]) * (p2[0] - p3[0])) - p3[1] * (p1[0] + p2[0]) / ((p3[0] - p1[0]) * (p3[0] - p2[0]));
445
+ var c = p1[1] * p2[0] * p3[0] / ((p1[0] - p2[0]) * (p1[0] - p3[0])) + p2[1] * p1[0] * p3[0] / ((p2[0] - p1[0]) * (p2[0] - p3[0])) + p3[1] * p1[0] * p2[0] / ((p3[0] - p1[0]) * (p3[0] - p2[0]));
446
+ return a * t * t + b * t + c;
447
+ }
448
+ },
449
+ comp: {
450
+ new: function(a, b) {
451
+ return {a: a, b: b, type: "comp"};
452
+ },
453
+ function: function(realDefinition, imagDefinition) {
454
+ return {definition: [realDefinition, imagDefinition], type: "comp"};
455
+ },
456
+ parse: function(str, init) {
457
+ init = init || '';
458
+ return Function('"use strict"; ' + init + ' return (' + str + ')')();
459
+ },
460
+ val: function(func, comp) {
461
+ if(func.type === "comp") {
462
+ var u = Chalkboard.comp.parse("(a, b) => " + func.definition[0]),
463
+ v = Chalkboard.comp.parse("(a, b) => " + func.definition[1]);
464
+ return Chalkboard.comp.new(u(comp.a, comp.b), v(comp.a, comp.b));
465
+ } else {
466
+ return "TypeError: Parameter \"func\" must be of type \"comp\".";
467
+ }
468
+ },
469
+ Re: function(funcORcomp) {
470
+ if(funcORcomp.definition !== undefined && funcORcomp.type === "comp") {
471
+ return funcORcomp.definition[0];
472
+ } else if(funcORcomp.a !== undefined && funcORcomp.type === "comp") {
473
+ return funcORcomp.a;
474
+ }
475
+ },
476
+ Im: function(funcORcomp) {
477
+ if(funcORcomp.definition !== undefined && funcORcomp.type === "comp") {
478
+ return funcORcomp.definition[1];
479
+ } else if(funcORcomp.b !== undefined && funcORcomp.type === "comp") {
480
+ return funcORcomp.b;
481
+ }
482
+ },
483
+ random: function(inf, sup) {
484
+ return Chalkboard.comp.new(Chalkboard.numb.random(inf, sup), Chalkboard.numb.random(inf, sup));
485
+ },
486
+ mag: function(comp) {
487
+ return Chalkboard.real.sqrt((comp.a * comp.a) + (comp.b * comp.b));
488
+ },
489
+ magsq: function(comp) {
490
+ return (comp.a * comp.a) + (comp.b * comp.b);
491
+ },
492
+ magset: function(comp, num) {
493
+ return Chalkboard.comp.scl(Chalkboard.comp.normalize(comp), num);
494
+ },
495
+ arg: function(comp) {
496
+ return Chalkboard.trig.arctan2(comp.b, comp.a);
497
+ },
498
+ slope: function(comp) {
499
+ return comp.b / comp.a;
500
+ },
501
+ average: function(comp) {
502
+ return (comp.a + comp.b) / 2;
503
+ },
504
+ normalize: function(comp) {
505
+ return Chalkboard.comp.new(comp.a / Chalkboard.comp.mag(comp), comp.b / Chalkboard.comp.mag(comp));
506
+ },
507
+ zero: function(comp) {
508
+ return Chalkboard.comp.new(comp.a * 0, comp.b * 0);
509
+ },
510
+ negate: function(comp) {
511
+ return Chalkboard.comp.new(-comp.a, -comp.b);
512
+ },
513
+ reciprocate: function(comp) {
514
+ return Chalkboard.comp.new(1 / comp.a, 1 / comp.b);
515
+ },
516
+ absolute: function(comp) {
517
+ return Chalkboard.comp.new(Math.abs(comp.a), Math.abs(comp.b));
518
+ },
519
+ round: function(comp) {
520
+ return Chalkboard.comp.new(Math.round(comp.a), Math.round(comp.b));
521
+ },
522
+ Euler: function(rad) {
523
+ return Chalkboard.comp.new(Chalkboard.trig.cos(rad), Chalkboard.trig.sin(rad));
524
+ },
525
+ pow: function(comp, num) {
526
+ return Chalkboard.comp.new(Chalkboard.real.pow(Chalkboard.comp.mag(comp), num) * Chalkboard.trig.cos(num * Chalkboard.comp.arg(comp)), Chalkboard.real.pow(Chalkboard.comp.mag(comp), num) * Chalkboard.trig.sin(num * Chalkboard.comp.arg(comp)));
527
+ },
528
+ ln: function(comp) {
529
+ return Chalkboard.comp.new(Chalkboard.real.ln(Chalkboard.comp.mag(comp)), Chalkboard.trig.arctan2(comp.b, comp.a));
530
+ },
531
+ sq: function(comp) {
532
+ return Chalkboard.comp.new((comp.a * comp.a) - (comp.b * comp.b), 2 * comp.a * comp.b);
533
+ },
534
+ sqrt: function(comp) {
535
+ return Chalkboard.comp.new(Chalkboard.real.sqrt((comp.a + Chalkboard.real.sqrt((comp.a * comp.a) + (comp.b * comp.b))) / 2), Chalkboard.numb.sgn(comp.b) * Chalkboard.real.sqrt((-comp.a + Chalkboard.real.sqrt((comp.a * comp.a) + (comp.b * comp.b))) / 2));
536
+ },
537
+ rotate: function(comp, rad) {
538
+ return Chalkboard.comp.new(Chalkboard.comp.mag(comp) * Chalkboard.trig.cos(Chalkboard.comp.arg(comp) + rad), Chalkboard.comp.mag(comp) * Chalkboard.trig.sin(Chalkboard.comp.arg(comp) + rad));
539
+ },
540
+ invert: function(comp) {
541
+ return Chalkboard.comp.new(comp.a / Chalkboard.comp.magsq(comp), -comp.b / Chalkboard.comp.magsq(comp));
542
+ },
543
+ conjugate: function(comp) {
544
+ return Chalkboard.comp.new(comp.a, -comp.b);
545
+ },
546
+ root: function(comp, n) {
547
+ if(Number.isInteger(n) && n > 0) {
548
+ var result = [];
549
+ var r = Chalkboard.comp.mag(comp);
550
+ var t = Chalkboard.comp.arg(comp);
551
+ for(var i = 0; i < n; i++) {
552
+ result.push(Chalkboard.comp.new(Chalkboard.real.nrt(r, n) * Chalkboard.trig.cos((t + Chalkboard.PI(2 * i)) / n), Chalkboard.real.nrt(r, n) * Chalkboard.trig.sin((t + Chalkboard.PI(2 * i)) / n)));
553
+ }
554
+ return result;
555
+ }
556
+ },
557
+ dist: function(comp_1, comp_2) {
558
+ return Chalkboard.real.sqrt(((comp_2.a - comp_1.a) * (comp_2.a - comp_1.a)) + ((comp_2.b - comp_1.b) * (comp_2.b - comp_1.b)));
559
+ },
560
+ distsq: function(comp_1, comp_2) {
561
+ return ((comp_2.a - comp_1.a) * (comp_2.a - comp_1.a)) + ((comp_2.b - comp_1.b) * (comp_2.b - comp_1.b));
562
+ },
563
+ scl: function(comp, num) {
564
+ return Chalkboard.comp.new(comp.a * num, comp.b * num);
565
+ },
566
+ constrain: function(comp, range) {
567
+ return Chalkboard.comp.new(Chalkboard.numb.constrain(comp.a, range), Chalkboard.numb.constrain(comp.b, range));
568
+ },
569
+ add: function(comp_1, comp_2) {
570
+ return Chalkboard.comp.new(comp_1.a + comp_2.a, comp_1.b + comp_2.b);
571
+ },
572
+ sub: function(comp_1, comp_2) {
573
+ return Chalkboard.comp.new(comp_1.a - comp_2.a, comp_1.b - comp_2.b);
574
+ },
575
+ mul: function(comp_1, comp_2) {
576
+ return Chalkboard.comp.new((comp_1.a * comp_2.a) - (comp_1.b * comp_2.b), (comp_1.a * comp_2.b) + (comp_1.b * comp_2.a));
577
+ },
578
+ div: function(comp_1, comp_2) {
579
+ return Chalkboard.comp.new(((comp_1.a * comp_2.a) - (comp_1.b * comp_2.b)) / Chalkboard.comp.magsq(comp_2), ((comp_1.a * comp_2.b) + (comp_1.b * comp_2.a)) / Chalkboard.comp.magsq(comp_2));
580
+ },
581
+ toVector: function(comp) {
582
+ return Chalkboard.vec2.new(comp.a, comp.b);
583
+ },
584
+ toArray: function(comp) {
585
+ return [comp.a, comp.b];
586
+ },
587
+ toString: function(comp) {
588
+ if(comp.b >= 0) {
589
+ return comp.a.toString() + " + " + comp.b.toString() + "i";
590
+ } else if(comp.b < 0) {
591
+ return comp.a.toString() + " - " + Math.abs(comp.b).toString() + "i";
592
+ }
593
+ },
594
+ print: function(comp) {
595
+ console.log(Chalkboard.comp.toString(comp));
596
+ }
597
+ },
598
+ quat: {
599
+ new: function(a, b, c, d) {
600
+ return {a: a, b: b, c: c, d: d, type: "quat"};
601
+ },
602
+ random: function(inf, sup) {
603
+ return Chalkboard.quat.new(Chalkboard.numb.random(inf, sup), Chalkboard.numb.random(inf, sup), Chalkboard.numb.random(inf, sup), Chalkboard.numb.random(inf, sup));
604
+ },
605
+ mag: function(quat) {
606
+ return Chalkboard.real.sqrt((quat.a * quat.a) + (quat.b * quat.b) + (quat.c * quat.c) + (quat.d * quat.d));
607
+ },
608
+ magsq: function(quat) {
609
+ return (quat.a * quat.a) + (quat.b * quat.b) + (quat.c * quat.c) + (quat.d * quat.d);
610
+ },
611
+ magset: function(quat, num) {
612
+ return Chalkboard.quat.scl(Chalkboard.quat.normalize(quat), num);
613
+ },
614
+ average: function(quat) {
615
+ return (quat.a + quat.b + quat.c + quat.d) / 4;
616
+ },
617
+ normalize: function(quat) {
618
+ return Chalkboard.quat.new(quat.a / Chalkboard.quat.mag(quat), quat.b / Chalkboard.quat.mag(quat), quat.c / Chalkboard.quat.mag(quat), quat.d / Chalkboard.quat.mag(quat));
619
+ },
620
+ zero: function(quat) {
621
+ return Chalkboard.quat.new(quat.a * 0, quat.b * 0, quat.c * 0, quat.d * 0);
622
+ },
623
+ negate: function(quat) {
624
+ return Chalkboard.quat.new(-quat.a, -quat.b, -quat.c, -quat.d);
625
+ },
626
+ reciprocate: function(quat) {
627
+ return Chalkboard.quat.new(1 / quat.a, 1 / quat.b, 1 / quat.c, 1 / quat.d);
628
+ },
629
+ absolute: function(quat) {
630
+ return Chalkboard.quat.new(Math.abs(quat.a), Math.abs(quat.b), Math.abs(quat.c), Math.abs(quat.d));
631
+ },
632
+ round: function(quat) {
633
+ return Chalkboard.quat.new(Math.round(quat.a), Math.round(quat.b), Math.round(quat.c), Math.round(quat.d));
634
+ },
635
+ invert: function(quat) {
636
+ return Chalkboard.quat.new(quat.a / Chalkboard.quat.magsq(quat), -quat.b / Chalkboard.quat.magsq(quat), -quat.c / Chalkboard.quat.magsq(quat), -quat.d / Chalkboard.quat.magsq(quat));
637
+ },
638
+ conjugate: function(quat) {
639
+ return Chalkboard.quat.new(quat.a, -quat.b, -quat.c, -quat.d);
640
+ },
641
+ dist: function(quat_1, quat_2) {
642
+ return Chalkboard.real.sqrt(((quat_2.a - quat_1.a) * (quat_2.a - quat_1.a)) + ((quat_2.b - quat_1.b) * (quat_2.b - quat_1.b)) + ((quat_2.c - quat_1.c) * (quat_2.c - quat_1.c)) + ((quat_2.d - quat_1.d) * (quat_2.d - quat_1.d)));
643
+ },
644
+ distsq: function(quat_1, quat_2) {
645
+ return ((quat_2.a - quat_1.a) * (quat_2.a - quat_1.a)) + ((quat_2.b - quat_1.b) * (quat_2.b - quat_1.b)) + ((quat_2.c - quat_1.c) * (quat_2.c - quat_1.c)) + ((quat_2.d - quat_1.d) * (quat_2.d - quat_1.d));
646
+ },
647
+ scl: function(quat, num) {
648
+ return Chalkboard.quat.new(quat.a * num, quat.b * num, quat.c * num, quat.d * num);
649
+ },
650
+ constrain: function(quat, range) {
651
+ return Chalkboard.quat.new(Chalkboard.numb.constrain(quat.a, range), Chalkboard.numb.constrain(quat.b, range), Chalkboard.numb.constrain(quat.c, range), Chalkboard.numb.constrain(quat.d, range));
652
+ },
653
+ add: function(quat_1, quat_2) {
654
+ return Chalkboard.quat.new(quat_1.a + quat_2.a, quat_1.b + quat_2.b, quat_1.c + quat_2.c, quat_1.d + quat_2.d);
655
+ },
656
+ sub: function(quat_1, quat_2) {
657
+ return Chalkboard.quat.new(quat_1.a - quat_2.a, quat_1.b - quat_2.b, quat_1.c - quat_2.c, quat_1.d - quat_2.d);
658
+ },
659
+ mul: function(quat_1, quat_2) {
660
+ return Chalkboard.quat.new((quat_1.a * quat_2.a) - (quat_1.b * quat_2.b) - (quat_1.c * quat_2.c) - (quat_1.d * quat_2.d), (quat_1.a * quat_2.b) + (quat_1.b * quat_2.a) + (quat_1.c * quat_2.d) - (quat_1.d * quat_2.c), (quat_1.a * quat_2.c) - (quat_1.b * quat_2.d) + (quat_1.c * quat_2.a) + (quat_1.d * quat_2.b), (quat_1.a * quat_2.d) + (quat_1.b * quat_2.c) - (quat_1.c * quat_2.b) + (quat_1.d * quat_2.a));
661
+ },
662
+ fromAxis: function(vec3, rad) {
663
+ return Chalkboard.quat.new(Chalkboard.trig.cos(rad / 2), vec3.x * Chalkboard.trig.sin(rad / 2), vec3.y * Chalkboard.trig.sin(rad / 2), vec3.z * Chalkboard.trig.sin(rad / 2));
664
+ },
665
+ fromVector: function(vec3) {
666
+ return Chalkboard.quat.new(0, vec3.x, vec3.y, vec3.z);
667
+ },
668
+ toRotation: function(quat, vec3) {
669
+ var vector = Chalkboard.quat.fromVector(vec3);
670
+ var inverse = Chalkboard.quat.invert(quat);
671
+ var quat_vector_inverse = Chalkboard.quat.mul(quat, Chalkboard.quat.mul(vector, inverse));
672
+ return Chalkboard.vec3.new(quat_vector_inverse.b, quat_vector_inverse.c, quat_vector_inverse.d);
673
+ },
674
+ toVector: function(quat) {
675
+ return Chalkboard.vec4.new(quat.a, quat.b, quat.c, quat.d);
676
+ },
677
+ toArray: function(quat) {
678
+ return [quat.a, quat.b, quat.c, quat.d];
679
+ },
680
+ toString: function(quat) {
681
+ var quat_b = "";
682
+ var quat_c = "";
683
+ var quat_d = "";
684
+ if(quat.b >= 0) {
685
+ quat_b = " + " + quat.b.toString() + "i ";
686
+ } else if(quat.b < 0) {
687
+ quat_b = " - " + Math.abs(quat.b.toString()) + "i ";
688
+ }
689
+ if(quat.c >= 0) {
690
+ quat_c = "+ " + quat.c.toString() + "j ";
691
+ } else if(quat.c < 0) {
692
+ quat_c = "- " + Math.abs(quat.c.toString()) + "j ";
693
+ }
694
+ if(quat.d >= 0) {
695
+ quat_d = "+ " + quat.d.toString() + "k ";
696
+ } else if(quat.d < 0) {
697
+ quat_d = "- " + Math.abs(quat.d.toString()) + "k ";
698
+ }
699
+ return quat.a.toString() + quat_b + quat_c + quat_d;
700
+ },
701
+ print: function(quat) {
702
+ console.log(Chalkboard.quat.toString(quat));
703
+ }
704
+ },
705
+ plot: {
706
+ xyplane: function(scl, rgba, origin, weight, context) {
707
+ scl = scl || 1;
708
+ scl /= 100;
709
+ rgba = rgba || [0, 0, 0];
710
+ origin = origin || [canvas.width / 2, canvas.height / 2];
711
+ weight = weight || 2;
712
+ context = context || ctx;
713
+ context.save();
714
+ context.translate(origin[0], origin[1]);
715
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
716
+ context.lineWidth = weight / 4;
717
+ context.beginPath();
718
+ for(var i = Math.floor(-origin[0] / scl); i <= (canvas.width - origin[0]) / scl; i++) {
719
+ context.moveTo(i / scl, -origin[1]);
720
+ context.lineTo(i / scl, canvas.width - origin[1]);
721
+ }
722
+ context.stroke();
723
+ context.beginPath();
724
+ for(var i = Math.floor(-origin[1] / scl); i <= (canvas.width - origin[1]) / scl; i++) {
725
+ context.moveTo(-origin[0], i / scl);
726
+ context.lineTo(canvas.width - origin[0], i / scl);
727
+ }
728
+ context.stroke();
729
+ context.lineWidth = weight;
730
+ context.beginPath();
731
+ context.moveTo(-origin[0], 0);
732
+ context.lineTo(canvas.width - origin[0], 0);
733
+ context.stroke();
734
+ context.beginPath();
735
+ context.moveTo(0, -origin[1]);
736
+ context.lineTo(0, canvas.width - origin[1]);
737
+ context.stroke();
738
+ context.restore();
739
+ },
740
+ rOplane: function(scl, rgba, origin, weight, context) {
741
+ scl = scl || 1;
742
+ scl /= 100;
743
+ rgba = rgba || [0, 0, 0];
744
+ origin = origin || [canvas.width / 2, canvas.height / 2];
745
+ weight = weight || 2;
746
+ context = context || ctx;
747
+ context.save();
748
+ context.translate(origin[0], origin[1]);
749
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
750
+ context.lineWidth = weight / 4;
751
+ context.beginPath();
752
+ for(var i = 0; i <= scl * canvas.width / 2; i++) {
753
+ context.ellipse(0, 0, i / scl, i / scl, 0, 0, Chalkboard.PI(2));
754
+ }
755
+ context.stroke();
756
+ context.lineWidth = weight;
757
+ context.beginPath();
758
+ context.moveTo(-origin[0], 0);
759
+ context.lineTo(canvas.width - origin[0], 0);
760
+ context.stroke()
761
+ context.beginPath();
762
+ context.moveTo(0, -origin[1]);
763
+ context.lineTo(0, canvas.width - origin[1]);
764
+ context.stroke();
765
+ context.restore();
766
+ },
767
+ function: function(func, scl, rgba, domain, origin, weight, context) {
768
+ scl = scl || 1;
769
+ scl /= 100;
770
+ rgba = rgba || [0, 0, 0];
771
+ domain = domain || func.type === "comp" ? [[-10, 10], [-10, 10]] : [-10, 10];
772
+ origin = origin || [canvas.width / 2, canvas.height / 2];
773
+ weight = weight || 2;
774
+ context = context || ctx;
775
+ var data = [];
776
+ context.save();
777
+ context.translate(origin[0], origin[1]);
778
+ context.lineWidth = weight;
779
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
780
+ context.beginPath();
781
+ if(func.type === "expl") {
782
+ var f = Chalkboard.real.parse("x => " + func.definition);
783
+ for(var i = domain[0] / scl; i <= domain[1] / scl; i++) {
784
+ context.lineTo(i, -f(i * scl) / scl);
785
+ data.push([i, f(i)]);
786
+ }
787
+ } else if(func.type === "pola") {
788
+ var r = Chalkboard.real.parse("O => " + func.definition);
789
+ for(var i = domain[0] / scl; i <= domain[1] / scl; i++) {
790
+ context.lineTo(r(i * scl) / scl * Chalkboard.trig.cos(i * scl), -r(i * scl) / scl * Chalkboard.trig.sin(i * scl));
791
+ data.push([i, r(i)]);
792
+ }
793
+ } else if(func.type === "curv") {
794
+ var x = Chalkboard.real.parse("t => " + func.definition[0]),
795
+ y = Chalkboard.real.parse("t => " + func.definition[1]);
796
+ for(var i = domain[0] / scl; i <= domain[1] / scl; i++) {
797
+ context.lineTo(x(i * scl) / scl, -y(i * scl) / scl);
798
+ data.push([x(i), y(i)]);
799
+ }
800
+ } else if(func.type === "comp") {
801
+ var u = Chalkboard.comp.parse("(a, b) => " + func.definition[0]),
802
+ v = Chalkboard.comp.parse("(a, b) => " + func.definition[1]);
803
+ for(var i = domain[0][0] / scl; i <= domain[0][1] / scl; i += 5) {
804
+ for(var j = domain[1][0] / scl; j <= domain[1][1] / scl; j += 5) {
805
+ var z = Chalkboard.comp.new(u(i * scl, j * scl) / scl, v(i * scl, j * scl) / scl);
806
+ if(z.a === 0 && z.b === 0) {
807
+ context.fillStyle = "rgb(0, 0, 0)";
808
+ } else if(z.a === Infinity && z.b === Infinity) {
809
+ context.fillStyle = "rgb(255, 255, 255)";
810
+ } else {
811
+ context.fillStyle = "hsl(" + Chalkboard.trig.toDeg(Chalkboard.comp.arg(z)) + ", 100%, " + (Chalkboard.trig.tanh(Chalkboard.comp.mag(z) / Chalkboard.real.pow(10, 20)) + 0.5) * 100 + "%)";
812
+ }
813
+ context.fillRect(i, j, 5, 5);
814
+ data.push([u(i, j), v(i, j)]);
815
+ }
816
+ }
817
+ } else {
818
+ return "TypeError: Property \"type\" of parameter \"func\" must be either \"expl\", \"pola\", \"curv\", or \"comp\".";
819
+ }
820
+ context.stroke();
821
+ context.restore();
822
+ return data;
823
+ },
824
+ barplot: function(arr, bins, scl, rgba, origin, weight, context) {
825
+ scl = scl || 1;
826
+ scl /= 100;
827
+ rgba = rgba || [[0, 0, 0], [255, 255, 255]];
828
+ origin = origin || [canvas.width / 2, canvas.height / 2];
829
+ weight = weight || 2;
830
+ context = context || ctx;
831
+ context.save();
832
+ context.translate(origin[0], origin[1]);
833
+ context.lineWidth = weight;
834
+ context.strokeStyle = rgba[0].length === 3 ? "rgb(" + rgba[0][0].toString() + ", " + rgba[0][1].toString() + ", " + rgba[0][2].toString() + ")" : "rgba(" + rgba[0][0].toString() + ", " + rgba[0][1].toString() + ", " + rgba[0][2].toString() + ", " + rgba[0][3].toString() + ")";
835
+ context.fillStyle = rgba[1].length === 3 ? "rgb(" + rgba[1][0].toString() + ", " + rgba[1][1].toString() + ", " + rgba[1][2].toString() + ")" : "rgba(" + rgba[1][0].toString() + ", " + rgba[1][1].toString() + ", " + rgba[1][2].toString() + ", " + rgba[1][3].toString() + ")";
836
+ var bars = [];
837
+ for(var i = 0; i < bins.length; i++) {
838
+ if(i === 0) {
839
+ bars.push(Chalkboard.stat.lt(arr, bins[0], true));
840
+ } else if(i === bins.length) {
841
+ bars.push(Chalkboard.stat.gt(arr, bins[bins.length - 1], true));
842
+ } else {
843
+ bars.push(Chalkboard.stat.ineq(arr, bins[i - 1], bins[i], false, true));
844
+ }
845
+ }
846
+ var counts = [];
847
+ for(var i = 0; i < bars.length; i++) {
848
+ counts.push(bars[i].length);
849
+ }
850
+ var x = 0, width = counts.length / (2 * scl);
851
+ for(var i = 0; i < counts.length; i++) {
852
+ context.fillRect(x - width, 0, 1 / scl, -counts[i] / scl);
853
+ context.strokeRect(x - width, 0, 1 / scl, -counts[i] / scl);
854
+ x += 1 / scl;
855
+ }
856
+ context.restore();
857
+ return bars;
858
+ },
859
+ lineplot: function(arr, bins, scl, rgba, origin, weight, context) {
860
+ scl = scl || 1;
861
+ scl /= 100;
862
+ rgba = rgba || [0, 0, 0];
863
+ origin = origin || [canvas.width / 2, canvas.height / 2];
864
+ weight = weight || 2;
865
+ context = context || ctx;
866
+ context.save();
867
+ context.translate(origin[0], origin[1]);
868
+ context.lineWidth = weight;
869
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
870
+ var verts = [];
871
+ for(var i = 0; i < bins.length; i++) {
872
+ if(i === 0) {
873
+ verts.push(Chalkboard.stat.lt(arr, bins[0], true));
874
+ } else if(i === bins.length) {
875
+ verts.push(Chalkboard.stat.gt(arr, bins[bins.length - 1], true));
876
+ } else {
877
+ verts.push(Chalkboard.stat.ineq(arr, bins[i - 1], bins[i], false, true));
878
+ }
879
+ }
880
+ var counts = [];
881
+ for(var i = 0; i < verts.length; i++) {
882
+ counts.push(verts[i].length);
883
+ }
884
+ context.beginPath();
885
+ for(var i = 0; i < counts.length; i++) {
886
+ context.lineTo(i / scl, -counts[i] / scl);
887
+ }
888
+ context.stroke();
889
+ context.restore();
890
+ return verts;
891
+ },
892
+ scatterplot: function(arr1, arr2, scl, rgba, origin, weight, context) {
893
+ scl = scl || 1;
894
+ scl /= 100;
895
+ rgba = rgba || [0, 0, 0];
896
+ origin = origin || [canvas.width / 2, canvas.height / 2];
897
+ weight = weight || 5;
898
+ context = context || ctx;
899
+ var data = [];
900
+ context.save();
901
+ context.translate(origin[0], origin[1]);
902
+ context.fillStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
903
+ if(arr1.length === arr2.length) {
904
+ for(var i = 0; i < arr1.length; i++) {
905
+ context.beginPath();
906
+ context.ellipse(arr1[i] / scl - arr1.length / (2 * scl), -arr2[i] / scl + arr1.length / (2 * scl), weight, weight, 0, 0, Chalkboard.PI(2));
907
+ context.fill();
908
+ data.push([arr1[i], arr2[i]]);
909
+ }
910
+ }
911
+ context.restore();
912
+ return data;
913
+ },
914
+ comp: function(comp, scl, rgba, origin, weight, context) {
915
+ scl = scl || 1;
916
+ scl /= 100;
917
+ rgba = rgba || [0, 0, 0];
918
+ origin = origin || [canvas.width / 2, canvas.height / 2];
919
+ weight = weight || 5;
920
+ context = context || ctx;
921
+ context.fillStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
922
+ context.save();
923
+ context.translate(origin[0], origin[1]);
924
+ context.beginPath();
925
+ context.ellipse(comp.a / scl, -comp.b / scl, weight, weight, 0, 0, Chalkboard.PI(2));
926
+ context.fill();
927
+ context.restore();
928
+ return [[comp.a], [comp.b]];
929
+ },
930
+ vec2: function(vec2, scl, rgba, origin, weight, context) {
931
+ scl = scl || 1;
932
+ scl /= 100;
933
+ rgba = rgba || [0, 0, 0];
934
+ origin = origin || [canvas.width / 2, canvas.height / 2];
935
+ weight = weight || 5;
936
+ context = context || ctx;
937
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
938
+ context.lineWidth = weight;
939
+ context.save();
940
+ context.translate(origin[0], origin[1]);
941
+ context.beginPath();
942
+ context.moveTo(0, 0);
943
+ context.lineTo(vec2.x / scl, -vec2.y / scl);
944
+ context.stroke();
945
+ context.restore();
946
+ return [[vec2.x], [vec2.y]];
947
+ },
948
+ field: function(vec2field, scl, rgba, domain, origin, weight, res, context) {
949
+ scl = scl || 1;
950
+ scl /= 100;
951
+ rgba = rgba || [0, 0, 0];
952
+ domain = domain || [[-10, 10], [-10, 10]];
953
+ origin = origin || [canvas.width / 2, canvas.height / 2];
954
+ weight = weight || 5;
955
+ res = res || 25;
956
+ context = context || ctx;
957
+ var data = [];
958
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
959
+ context.lineWidth = weight;
960
+ context.save();
961
+ context.translate(origin[0], origin[1]);
962
+ for(var i = domain[0][0] / scl; i <= domain[0][1] / scl; i += res) {
963
+ for(var j = domain[1][0] / scl; j <= domain[1][1] / scl; j += res) {
964
+ var v = Chalkboard.vec2.fromField(vec2field, Chalkboard.vec2.new(i, j));
965
+ context.beginPath();
966
+ context.moveTo(i, j);
967
+ context.lineTo(i + v.x, j + v.y);
968
+ context.stroke();
969
+ data.push([i + v.x, j + v.y]);
970
+ }
971
+ }
972
+ context.restore();
973
+ return data;
974
+ },
975
+ vec3: function(vec3, scl, rgba, origin, weight, context) {
976
+ scl = scl || 1;
977
+ scl /= 100;
978
+ rgba = rgba || [0, 0, 0];
979
+ origin = origin || [canvas.width / 2, canvas.height / 2];
980
+ weight = weight || 5;
981
+ context = context || ctx;
982
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
983
+ context.lineWidth = weight;
984
+ context.save();
985
+ context.translate(origin[0], origin[1]);
986
+ context.beginPath();
987
+ context.moveTo(0, 0);
988
+ context.lineTo((vec3.x / scl) / (vec3.z * 0.25 + 1), (-vec3.y / scl) / (vec3.z * 0.25 + 1));
989
+ context.stroke();
990
+ context.restore();
991
+ return [[vec3.x], [vec3.y], [vec3.z]];
992
+ },
993
+ matr: function(matr, scl, rgba, origin, weight, context) {
994
+ scl = scl || 1;
995
+ scl /= 100;
996
+ rgba = rgba || [0, 0, 0];
997
+ origin = origin || [canvas.width / 2, canvas.height / 2];
998
+ weight = weight || 2;
999
+ var plotposx = Chalkboard.vec2.new(matr[0][0], matr[1][0]);
1000
+ var plotnegx = Chalkboard.vec2.new(-matr[0][0], -matr[1][0]);
1001
+ var plotposy = Chalkboard.vec2.new(matr[0][1], matr[1][1]);
1002
+ var plotnegy = Chalkboard.vec2.new(-matr[0][1], -matr[1][1]);
1003
+ for(var i = -10; i <= 10; i++) {
1004
+ Chalkboard.vec2.plot(plotposx, scl, rgba, [origin[0], origin[1] + (i / scl) * matr[1][1]], weight / 4, context);
1005
+ Chalkboard.vec2.plot(plotnegx, scl, rgba, [origin[0], origin[1] + (i / scl) * matr[1][1]], weight / 4, context);
1006
+ Chalkboard.vec2.plot(plotposy, scl, rgba, [origin[0] + (i / scl) * matr[0][0], origin[1]], weight / 4, context);
1007
+ Chalkboard.vec2.plot(plotnegy, scl, rgba, [origin[0] + (i / scl) * matr[0][0], origin[1]], weight / 4, context);
1008
+ }
1009
+ var plotposaxisx = Chalkboard.vec2.new(matr[0][0], matr[1][0]);
1010
+ var plotnegaxisx = Chalkboard.vec2.new(-matr[0][0], -matr[1][0]);
1011
+ var plotposaxisy = Chalkboard.vec2.new(matr[0][1], matr[1][1]);
1012
+ var plotnegaxisy = Chalkboard.vec2.new(-matr[0][1], -matr[1][1]);
1013
+ Chalkboard.vec2.plot(plotposaxisx, scl, rgba, origin, weight, context);
1014
+ Chalkboard.vec2.plot(plotnegaxisx, scl, rgba, origin, weight, context);
1015
+ Chalkboard.vec2.plot(plotposaxisy, scl, rgba, origin, weight, context);
1016
+ Chalkboard.vec2.plot(plotnegaxisy, scl, rgba, origin, weight, context);
1017
+ return matr;
1018
+ },
1019
+ dfdx: function(func, scl, rgba, domain, origin, weight, res, context) {
1020
+ scl = scl || 1;
1021
+ scl /= 100;
1022
+ rgba = rgba || [0, 0, 0];
1023
+ domain = domain || [-10, 10];
1024
+ origin = origin || [canvas.width / 2, canvas.height / 2];
1025
+ weight = weight || 2;
1026
+ res = res || 25;
1027
+ context = context || ctx;
1028
+ var data = [];
1029
+ context.save();
1030
+ context.translate(origin[0], origin[1]);
1031
+ context.lineWidth = weight;
1032
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
1033
+ context.beginPath();
1034
+ for(var i = domain[0] / scl; i <= domain[1] / scl; i += res) {
1035
+ context.lineTo(i, -Chalkboard.calc.dfdx(func, i * scl) / scl);
1036
+ data.push([i, Chalkboard.calc.dfdx(func, i)]);
1037
+ }
1038
+ context.stroke();
1039
+ context.restore();
1040
+ return data;
1041
+ },
1042
+ d2fdx2: function(func, scl, rgba, domain, origin, weight, res, context) {
1043
+ scl = scl || 1;
1044
+ scl /= 100;
1045
+ rgba = rgba || [0, 0, 0];
1046
+ domain = domain || [-10, 10];
1047
+ origin = origin || [canvas.width / 2, canvas.height / 2];
1048
+ weight = weight || 2;
1049
+ res = res || 25;
1050
+ context = context || ctx;
1051
+ var data = [];
1052
+ context.save();
1053
+ context.translate(origin[0], origin[1]);
1054
+ context.lineWidth = weight;
1055
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
1056
+ context.beginPath();
1057
+ for(var i = domain[0] / scl; i <= domain[1] / scl; i += res) {
1058
+ context.lineTo(i, -Chalkboard.calc.d2fdx2(func, i * scl) / scl);
1059
+ data.push([i, Chalkboard.calc.d2fdx2(func, i)]);
1060
+ }
1061
+ context.stroke();
1062
+ context.restore();
1063
+ return data;
1064
+ },
1065
+ fxdx: function(func, scl, rgba, domain, origin, weight, res, context) {
1066
+ scl = scl || 1;
1067
+ scl /= 100;
1068
+ rgba = rgba || [0, 0, 0];
1069
+ domain = domain || [-10, 10];
1070
+ origin = origin || [canvas.width / 2, canvas.height / 2];
1071
+ weight = weight || 2;
1072
+ res = res || 25;
1073
+ context = context || ctx;
1074
+ var data = [];
1075
+ context.save();
1076
+ context.translate(origin[0], origin[1]);
1077
+ context.lineWidth = weight;
1078
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
1079
+ context.beginPath();
1080
+ for(var i = domain[0] / scl; i <= domain[1] / scl; i += res) {
1081
+ context.lineTo(i, -Chalkboard.calc.fxdx(func, 0, i * scl) / scl);
1082
+ data.push([i, Chalkboard.calc.fxdx(func, 0, i)]);
1083
+ }
1084
+ context.stroke();
1085
+ context.restore();
1086
+ return data;
1087
+ },
1088
+ convolution: function(func_1, func_2, scl, rgba, domain, origin, weight, res, context) {
1089
+ scl = scl || 1;
1090
+ scl /= 100;
1091
+ rgba = rgba || [0, 0, 0];
1092
+ domain = domain || [-10, 10];
1093
+ origin = origin || [canvas.width / 2, canvas.height / 2];
1094
+ weight = weight || 2;
1095
+ res = res || 25;
1096
+ context = context || ctx;
1097
+ var data = [];
1098
+ context.save();
1099
+ context.translate(origin[0], origin[1]);
1100
+ context.lineWidth = weight;
1101
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
1102
+ context.beginPath();
1103
+ for(var i = domain[0] / scl; i <= domain[1] / scl; i += res) {
1104
+ context.lineTo(i, -Chalkboard.calc.convolution(func_1, func_2, i * scl) / scl);
1105
+ data.push([i, Chalkboard.calc.convolution(func_1, func_2, i)]);
1106
+ }
1107
+ context.stroke();
1108
+ context.restore();
1109
+ return data;
1110
+ },
1111
+ correlation: function(func_1, func_2, scl, rgba, domain, origin, weight, res, context) {
1112
+ scl = scl || 1;
1113
+ scl /= 100;
1114
+ rgba = rgba || [0, 0, 0];
1115
+ domain = domain || [-10, 10];
1116
+ origin = origin || [canvas.width / 2, canvas.height / 2];
1117
+ weight = weight || 2;
1118
+ res = res || 25;
1119
+ context = context || ctx;
1120
+ var data = [];
1121
+ context.save();
1122
+ context.translate(origin[0], origin[1]);
1123
+ context.lineWidth = weight;
1124
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
1125
+ context.beginPath();
1126
+ for(var i = domain[0] / scl; i <= domain[1] / scl; i += res) {
1127
+ context.lineTo(i, -Chalkboard.calc.correlation(func_1, func_2, i * scl) / scl);
1128
+ data.push([i, Chalkboard.calc.correlation(func_1, func_2, i)]);
1129
+ }
1130
+ context.stroke();
1131
+ context.restore();
1132
+ return data;
1133
+ },
1134
+ autocorrelation: function(func, scl, rgba, domain, origin, weight, res, context) {
1135
+ scl = scl || 1;
1136
+ scl /= 100;
1137
+ rgba = rgba || [0, 0, 0];
1138
+ domain = domain || [-10, 10];
1139
+ origin = origin || [canvas.width / 2, canvas.height / 2];
1140
+ weight = weight || 2;
1141
+ res = res || 25;
1142
+ context = context || ctx;
1143
+ var data = [];
1144
+ context.save();
1145
+ context.translate(origin[0], origin[1]);
1146
+ context.lineWidth = weight;
1147
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
1148
+ context.beginPath();
1149
+ for(var i = domain[0] / scl; i <= domain[1] / scl; i += res) {
1150
+ context.lineTo(i, -Chalkboard.calc.autocorrelation(func, i * scl) / scl);
1151
+ data.push([i, Chalkboard.calc.autocorrelation(func, i)]);
1152
+ }
1153
+ context.stroke();
1154
+ context.restore();
1155
+ return data;
1156
+ },
1157
+ Taylor: function(func, n, a, scl, rgba, domain, origin, weight, res, context) {
1158
+ scl = scl || 1;
1159
+ scl /= 100;
1160
+ rgba = rgba || [0, 0, 0];
1161
+ domain = domain || [-10, 10];
1162
+ origin = origin || [canvas.width / 2, canvas.height / 2];
1163
+ weight = weight || 2;
1164
+ res = res || 25;
1165
+ context = context || ctx;
1166
+ var data = [];
1167
+ context.save();
1168
+ context.translate(origin[0], origin[1]);
1169
+ context.lineWidth = weight;
1170
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
1171
+ context.beginPath();
1172
+ for(var i = domain[0] / scl; i <= domain[1] / scl; i += res) {
1173
+ context.lineTo(i, -Chalkboard.calc.Taylor(func, i * scl, n, a) / scl);
1174
+ data.push([i, Chalkboard.calc.Taylor(func, i, n, a)]);
1175
+ }
1176
+ context.stroke();
1177
+ context.restore();
1178
+ return data;
1179
+ },
1180
+ Laplace: function(func, scl, rgba, domain, origin, weight, res, context) {
1181
+ scl = scl || 1;
1182
+ scl /= 100;
1183
+ rgba = rgba || [0, 0, 0];
1184
+ domain = domain || [-10, 10];
1185
+ origin = origin || [canvas.width / 2, canvas.height / 2];
1186
+ weight = weight || 2;
1187
+ res = res || 25;
1188
+ context = context || ctx;
1189
+ var data = [];
1190
+ context.save();
1191
+ context.translate(origin[0], origin[1]);
1192
+ context.lineWidth = weight;
1193
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
1194
+ context.beginPath();
1195
+ if(domain[0] >= 0) {
1196
+ for(var i = domain[0] / scl; i <= domain[1] / scl; i += res) {
1197
+ context.lineTo(i, -Chalkboard.calc.Laplace(func, i * scl) / scl);
1198
+ data.push([i, Chalkboard.calc.Laplace(func, i)]);
1199
+ }
1200
+ } else {
1201
+ for(var i = 0; i <= domain[1] / scl; i += res) {
1202
+ context.lineTo(i, -Chalkboard.calc.Laplace(func, i * scl) / scl);
1203
+ data.push([i, Chalkboard.calc.Laplace(func, i)]);
1204
+ }
1205
+ }
1206
+ context.stroke();
1207
+ context.restore();
1208
+ return data;
1209
+ },
1210
+ Fourier: function(func, scl, rgba, domain, origin, weight, res, context) {
1211
+ scl = scl || 1;
1212
+ scl /= 100;
1213
+ rgba = rgba || [0, 0, 0];
1214
+ domain = domain || [-10, 10];
1215
+ origin = origin || [canvas.width / 2, canvas.height / 2];
1216
+ weight = weight || 2;
1217
+ res = res || 25;
1218
+ context = context || ctx;
1219
+ var data = [];
1220
+ context.save();
1221
+ context.translate(origin[0], origin[1]);
1222
+ context.lineWidth = weight;
1223
+ context.strokeStyle = rgba.length === 3 ? "rgb(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ")" : "rgba(" + rgba[0].toString() + ", " + rgba[1].toString() + ", " + rgba[2].toString() + ", " + rgba[3].toString() + ")";
1224
+ context.beginPath();
1225
+ for(var i = domain[0] / scl; i <= domain[1] / scl; i += res) {
1226
+ context.lineTo(i, -Chalkboard.calc.Fourier(func, i * scl) / scl);
1227
+ data.push([i, Chalkboard.calc.Fourier(func, i)]);
1228
+ }
1229
+ context.stroke();
1230
+ context.restore();
1231
+ return data;
1232
+ }
1233
+ },
1234
+ geom: {
1235
+ EulerCharacteristic: function(v, e, f) {
1236
+ return v - e + f;
1237
+ },
1238
+ Pythagorean: function(a, b, type) {
1239
+ type = type || "hyp";
1240
+ if(type === "hyp") {
1241
+ return Math.sqrt((a * a) + (b * b));
1242
+ } else if(type === "leg") {
1243
+ return Math.sqrt((b * b) - (a * a));
1244
+ } else {
1245
+ return undefined;
1246
+ }
1247
+ },
1248
+ PythagoreanTriple: function(inf, sup) {
1249
+ var a = 2 * Math.round(Chalkboard.numb.random(inf, sup)) - 1,
1250
+ b = ((a * a) / 2) - 0.5,
1251
+ c = ((a * a) / 2) + 0.5;
1252
+ return a + ", " + b + ", " + c;
1253
+ },
1254
+ dist: function(p1, p2) {
1255
+ if(p1.length === p2.length) {
1256
+ var result = 0;
1257
+ for(var i = 0; i < p1.length; i++) {
1258
+ result += (p1[i] - p2[i]) * (p1[i] - p2[i]);
1259
+ }
1260
+ return Chalkboard.real.sqrt(result);
1261
+ } else {
1262
+ return undefined;
1263
+ }
1264
+ },
1265
+ distsq: function(p1, p2) {
1266
+ if(p1.length === p2.length) {
1267
+ var result = 0;
1268
+ for(var i = 0; i < p1.length; i++) {
1269
+ result += (p1[i] - p2[i]) * (p1[i] - p2[i]);
1270
+ }
1271
+ return result;
1272
+ } else {
1273
+ return undefined;
1274
+ }
1275
+ },
1276
+ mid: function(p1, p2) {
1277
+ if(p1.length === p2.length) {
1278
+ var result = [];
1279
+ for(var i = 0; i < p1.length; i++) {
1280
+ result[i] = (p1[i] + p2[i]) / 2;
1281
+ }
1282
+ return result;
1283
+ } else {
1284
+ return undefined;
1285
+ }
1286
+ },
1287
+ circleP: function(r) {
1288
+ return 2 * Chalkboard.PI() * r;
1289
+ },
1290
+ circleA: function(r) {
1291
+ return Chalkboard.PI() * r * r;
1292
+ },
1293
+ sectorP: function(r, rad) {
1294
+ return r * rad;
1295
+ },
1296
+ sectorA: function(r, rad) {
1297
+ return (r * r * rad) / 2;
1298
+ },
1299
+ ellipseP: function(a, b) {
1300
+ var h = ((a - b) * (a - b)) / ((a + b) * (a + b));
1301
+ return Chalkboard.PI() * (a + b) * (1 + (3 * h) / (10 + Math.sqrt(4 - 3 * h)));
1302
+ },
1303
+ ellipseA: function(a, b) {
1304
+ return Chalkboard.PI() * a * b;
1305
+ },
1306
+ squareP: function(s) {
1307
+ return 4 * s;
1308
+ },
1309
+ squareA: function(s) {
1310
+ return s * s;
1311
+ },
1312
+ parallelogramP: function(l, w) {
1313
+ return 2 * (l + w);
1314
+ },
1315
+ parallelogramA: function(l, w) {
1316
+ return l * w;
1317
+ },
1318
+ triangleP: function(a, b, c) {
1319
+ return a + b + c;
1320
+ },
1321
+ triangleA: function(b, h) {
1322
+ return (b * h) / 2;
1323
+ },
1324
+ trianglesidesA: function(a, b, c) {
1325
+ var s = (a + b + c) / 2;
1326
+ return Chalkboard.real.sqrt(s * ((s - a) * (s - b) * (s - c)));
1327
+ },
1328
+ trapezoidP: function(a, b, c, d) {
1329
+ return a + b + c + d;
1330
+ },
1331
+ trapezoidA: function(b1, b2, h) {
1332
+ return ((b1 + b2) / 2) * h;
1333
+ },
1334
+ polygonP: function(n, s) {
1335
+ return n * s;
1336
+ },
1337
+ polygonA: function(n, s, a) {
1338
+ return (n * s * a) / 2;
1339
+ },
1340
+ sphereA: function(r) {
1341
+ return 4 * Chalkboard.PI() * r * r;
1342
+ },
1343
+ sphereV: function(r) {
1344
+ return (4 * Chalkboard.PI() * r * r * r) / 3;
1345
+ },
1346
+ cylinderA: function(r, h) {
1347
+ return 2 * Chalkboard.PI() * r * r + 2 * Math.PI * r * h;
1348
+ },
1349
+ cylinderV: function(r, h) {
1350
+ return Chalkboard.PI() * r * r * h;
1351
+ },
1352
+ coneA: function(r, h) {
1353
+ return Chalkboard.PI() * r * (r + Math.sqrt(h * h + r * r));
1354
+ },
1355
+ coneV: function(r, h) {
1356
+ return (Chalkboard.PI() * r * r * h) / 3;
1357
+ },
1358
+ cubeA: function(s) {
1359
+ return 6 * s * s;
1360
+ },
1361
+ cubeV: function(s) {
1362
+ return s * s * s;
1363
+ },
1364
+ rectangularprismA: function(l, w, h) {
1365
+ return 2 * (l * h + l * h + w * h);
1366
+ },
1367
+ rectangularprismV: function(l, w, h) {
1368
+ return l * w * h;
1369
+ },
1370
+ triangularprismA: function(a, b, c, h) {
1371
+ var s = (a + b + c) / 2;
1372
+ return 2 * Chalkboard.real.sqrt(s * ((s - a) * (s - b) * (s - c))) + h * (a + b + c);
1373
+ },
1374
+ triangularprismV: function(a, b, c, h) {
1375
+ return h * (Chalkboard.real.sqrt(-(a * a * a * a) + 2 * (a * b) * (a * b) + 2 * (a * c) * (a * c) - (b * b * b * b) + 2 * (b * c) * (b * c) - (c * c * c * c))) / 4;
1376
+ },
1377
+ line3D: function(x1, y1, z1, x2, y2, z2, context) {
1378
+ context = context || ctx;
1379
+ context.beginPath();
1380
+ context.moveTo(x1 / (z1 * 0.0025 + 1), y1 / (z1 * 0.0025 + 1));
1381
+ context.lineTo(x2 / (z2 * 0.0025 + 1), y2 / (z2 * 0.0025 + 1));
1382
+ context.stroke();
1383
+ }
1384
+ },
1385
+ trig: {
1386
+ toRad: function(deg) {
1387
+ return deg * (Chalkboard.PI() / 180);
1388
+ },
1389
+ toDeg: function(rad) {
1390
+ return rad * (180 / Chalkboard.PI());
1391
+ },
1392
+ coterminal: function(rad) {
1393
+ return rad % (2 * Chalkboard.PI());
1394
+ },
1395
+ sin: function(rad) {
1396
+ rad = Chalkboard.trig.coterminal(rad);
1397
+ return ((rad) - (Math.pow(rad, 3) / Chalkboard.numb.factorial(3)) + (Math.pow(rad, 5) / Chalkboard.numb.factorial(5)) - (Math.pow(rad, 7) / Chalkboard.numb.factorial(7)) + (Math.pow(rad, 9) / Chalkboard.numb.factorial(9)) - (Math.pow(rad, 11) / Chalkboard.numb.factorial(11)) + (Math.pow(rad, 13) / Chalkboard.numb.factorial(13)) - (Math.pow(rad, 15) / Chalkboard.numb.factorial(15)) + (Math.pow(rad, 17) / Chalkboard.numb.factorial(17)) - (Math.pow(rad, 19) / Chalkboard.numb.factorial(19)) + (Math.pow(rad, 21) / Chalkboard.numb.factorial(21)) - (Math.pow(rad, 23) / Chalkboard.numb.factorial(23)) + (Math.pow(rad, 25) / Chalkboard.numb.factorial(25)) - (Math.pow(rad, 27) / Chalkboard.numb.factorial(27)) + (Math.pow(rad, 29) / Chalkboard.numb.factorial(29)));
1398
+ },
1399
+ cos: function(rad) {
1400
+ rad = Chalkboard.trig.coterminal(rad);
1401
+ return ((1) - (Math.pow(rad, 2) / Chalkboard.numb.factorial(2)) + (Math.pow(rad, 4) / Chalkboard.numb.factorial(4)) - (Math.pow(rad, 6) / Chalkboard.numb.factorial(6)) + (Math.pow(rad, 8) / Chalkboard.numb.factorial(8)) - (Math.pow(rad, 10) / Chalkboard.numb.factorial(10)) + (Math.pow(rad, 12) / Chalkboard.numb.factorial(12)) - (Math.pow(rad, 14) / Chalkboard.numb.factorial(14)) + (Math.pow(rad, 16) / Chalkboard.numb.factorial(16)) - (Math.pow(rad, 18) / Chalkboard.numb.factorial(18)) + (Math.pow(rad, 20) / Chalkboard.numb.factorial(20)) - (Math.pow(rad, 22) / Chalkboard.numb.factorial(22)) + (Math.pow(rad, 24) / Chalkboard.numb.factorial(24)) - (Math.pow(rad, 26) / Chalkboard.numb.factorial(26)) + (Math.pow(rad, 28) / Chalkboard.numb.factorial(28)));
1402
+ },
1403
+ tan: function(rad) {
1404
+ return Chalkboard.trig.sin(rad) / Chalkboard.trig.cos(rad);
1405
+ },
1406
+ csc: function(rad) {
1407
+ return 1 / Chalkboard.trig.sin(rad);
1408
+ },
1409
+ sec: function(rad) {
1410
+ return 1 / Chalkboard.trig.cos(rad);
1411
+ },
1412
+ cot: function(rad) {
1413
+ return 1 / Chalkboard.trig.tan(rad);
1414
+ },
1415
+ sinh: function(rad) {
1416
+ return (Math.pow(Chalkboard.E(), rad) - Math.pow(Chalkboard.E(), -rad)) / 2;
1417
+ },
1418
+ cosh: function(rad) {
1419
+ return (Math.pow(Chalkboard.E(), rad) + Math.pow(Chalkboard.E(), -rad)) / 2;
1420
+ },
1421
+ tanh: function(rad) {
1422
+ return Chalkboard.trig.sinh(rad) / Chalkboard.trig.cosh(rad);
1423
+ },
1424
+ csch: function(rad) {
1425
+ return 1 / Chalkboard.trig.sinh(rad);
1426
+ },
1427
+ sech: function(rad) {
1428
+ return 1 / Chalkboard.trig.cosh(rad);
1429
+ },
1430
+ coth: function(rad) {
1431
+ return 1 / Chalkboard.trig.tanh(rad);
1432
+ },
1433
+ arcsin: function(rad) {
1434
+ if(rad > -1 && rad < 1) {
1435
+ return Chalkboard.calc.fxdx(Chalkboard.real.function("1 / (Math.sqrt(1 - x * x))"), 0, rad);
1436
+ } else if(rad === 1) {
1437
+ return Chalkboard.PI() / 2;
1438
+ } else if(rad === -1) {
1439
+ return -Chalkboard.PI() / 2;
1440
+ } else {
1441
+ return undefined;
1442
+ }
1443
+ },
1444
+ arccos: function(rad) {
1445
+ if(rad > -1 && rad < 1) {
1446
+ return Chalkboard.calc.fxdx(Chalkboard.real.function("1 / (Math.sqrt(1 - x * x))"), rad, 1);
1447
+ } else if(rad === 1) {
1448
+ return 0;
1449
+ } else if(rad === -1) {
1450
+ return Chalkboard.PI();
1451
+ } else {
1452
+ return undefined;
1453
+ }
1454
+ },
1455
+ arctan: function(rad) {
1456
+ return Chalkboard.calc.fxdx(Chalkboard.real.function("1 / (1 + x * x)"), 0, rad);
1457
+ },
1458
+ arctan2: function(y, x) {
1459
+ if(x === 0) {
1460
+ if(y > 0) {
1461
+ return Math.PI / 2;
1462
+ } else if(y < 0) {
1463
+ return -Math.PI / 2;
1464
+ } else {
1465
+ return 0;
1466
+ }
1467
+ } else {
1468
+ if(x > 0 && y >= 0) {
1469
+ return Math.atan(Math.abs(y / x));
1470
+ } else if(x < 0 && y >= 0) {
1471
+ return Math.PI - Math.atan(Math.abs(y / x));
1472
+ } else if(x < 0 && y < 0) {
1473
+ return -Math.PI + Math.atan(Math.abs(y / x));
1474
+ } else {
1475
+ return -Math.atan(Math.abs(y / x));
1476
+ }
1477
+ }
1478
+ },
1479
+ arccsc: function(rad) {
1480
+ if(rad > 1) {
1481
+ return Chalkboard.calc.fxdx(Chalkboard.real.function("1 / (x * Math.sqrt(x * x - 1))"), rad, 1000);
1482
+ } else if(rad === 1) {
1483
+ return Chalkboard.PI() / 2;
1484
+ } else if(rad === -1) {
1485
+ return -Chalkboard.PI() / 2;
1486
+ } else if(rad < 1) {
1487
+ return -Chalkboard.calc.fxdx(Chalkboard.real.function("1 / (x * Math.sqrt(x * x - 1))"), Math.abs(rad), 1000);
1488
+ } else {
1489
+ return undefined;
1490
+ }
1491
+ },
1492
+ arcsec: function(rad) {
1493
+ if(rad > 1) {
1494
+ return Chalkboard.calc.fxdx(Chalkboard.real.function("1 / (x * Math.sqrt(x * x - 1))"), 1.000001, rad);
1495
+ } else if(rad === 1) {
1496
+ return 0;
1497
+ } else if(rad === -1) {
1498
+ return Chalkboard.PI();
1499
+ } else {
1500
+ return undefined;
1501
+ }
1502
+ },
1503
+ arccot: function(rad) {
1504
+ return Chalkboard.calc.fxdx(Chalkboard.real.function("1 / (1 + x * x)"), rad, 1000);
1505
+ },
1506
+ arcsinh: function(rad) {
1507
+ return Math.log(rad + Math.sqrt(rad * rad + 1));
1508
+ },
1509
+ arccosh: function(rad) {
1510
+ if(rad >= 1) {
1511
+ return Math.log(rad + Math.sqrt(rad * rad - 1));
1512
+ } else {
1513
+ return undefined;
1514
+ }
1515
+ },
1516
+ arctanh: function(rad) {
1517
+ if(rad > -1 && rad < 1) {
1518
+ return (Math.log((1 + rad) / (1 - rad))) / 2;
1519
+ } else {
1520
+ return undefined;
1521
+ }
1522
+ },
1523
+ arccsch: function(rad) {
1524
+ if(rad !== 0) {
1525
+ return Math.log((1 / rad) + Math.sqrt((1 / (rad * rad)) + 1));
1526
+ } else {
1527
+ return undefined;
1528
+ }
1529
+ },
1530
+ arcsech: function(rad) {
1531
+ if(rad > 0 && rad <= 1) {
1532
+ return Math.log((1 / rad) + Math.sqrt((1 / (rad * rad)) - 1));
1533
+ } else {
1534
+ return undefined;
1535
+ }
1536
+ },
1537
+ arccoth: function(rad) {
1538
+ if(rad < -1 || rad > 1) {
1539
+ return (Math.log((rad + 1) / (rad - 1))) / 2;
1540
+ } else {
1541
+ return undefined;
1542
+ }
1543
+ }
1544
+ },
1545
+ stat: {
1546
+ array: function(inf, sup, length) {
1547
+ length = length || sup - inf + 1;
1548
+ var result = [];
1549
+ var step = (sup - inf) / (length - 1);
1550
+ for(var i = 0; i < length; i++) {
1551
+ result.push(inf + (step * i));
1552
+ }
1553
+ return result;
1554
+ },
1555
+ random: function(inf, sup, length) {
1556
+ var result = [];
1557
+ for(var i = 0; i < length; i++) {
1558
+ result.push(Chalkboard.numb.random(inf, sup));
1559
+ }
1560
+ return result;
1561
+ },
1562
+ norm: function(arr, type) {
1563
+ type = type || "L2";
1564
+ var result = 0;
1565
+ if(type === "L0") {
1566
+ for(var i = 0; i < arr.length; i++) {
1567
+ if(arr[i] !== 0) {
1568
+ result += 1;
1569
+ }
1570
+ }
1571
+ return result;
1572
+ } else if(type === "L1") {
1573
+ for(var i = 0; i < arr.length; i++) {
1574
+ result += Math.abs(arr[i]);
1575
+ }
1576
+ return result;
1577
+ } else if(type === "L2") {
1578
+ for(var i = 0; i < arr.length; i++) {
1579
+ result += arr[i] * arr[i];
1580
+ }
1581
+ return Chalkboard.real.sqrt(result);
1582
+ } else if(type === "LInfinity") {
1583
+ return Math.abs(Chalkboard.stat.max(arr));
1584
+ } else {
1585
+ return "TypeError: Parameter \"type\" must be \"L0\", \"L1\", \"L2\", or \"LInfinity\".";
1586
+ }
1587
+ },
1588
+ normsq: function(arr, type) {
1589
+ type = type || "L2";
1590
+ var result = 0;
1591
+ if(type === "L0") {
1592
+ for(var i = 0; i < arr.length; i++) {
1593
+ if(arr[i] !== 0) {
1594
+ result += 1;
1595
+ }
1596
+ }
1597
+ return result * result;
1598
+ } else if(type === "L1") {
1599
+ for(var i = 0; i < arr.length; i++) {
1600
+ result += Math.abs(arr[i]);
1601
+ }
1602
+ return result * result;
1603
+ } else if(type === "L2") {
1604
+ for(var i = 0; i < arr.length; i++) {
1605
+ result += arr[i] * arr[i];
1606
+ }
1607
+ return result;
1608
+ } else if(type === "LInfinity") {
1609
+ return Math.abs(Chalkboard.stat.max(arr)) * Math.abs(Chalkboard.stat.max(arr));
1610
+ } else {
1611
+ return "TypeError: Parameter \"type\" must be \"L0\", \"L1\", \"L2\", or \"LInfinity\".";
1612
+ }
1613
+ },
1614
+ normalize: function(arr, type) {
1615
+ if(type === "L0" || type === "L1" || type === "L2" || type === "LInfinity") {
1616
+ var result = [];
1617
+ var norm = Chalkboard.stat.norm(arr, type);
1618
+ for(var i = 0; i < arr.length; i++) {
1619
+ result.push(arr[i] / norm);
1620
+ }
1621
+ return result;
1622
+ } else {
1623
+ return "TypeError: Parameter \"type\" must be \"L0\", \"L1\", \"L2\", or \"LInfinity\".";
1624
+ }
1625
+ },
1626
+ constrain: function(arr, range) {
1627
+ var result = [];
1628
+ for(var i = 0; i < arr.length; i++) {
1629
+ result.push(Chalkboard.numb.constrain(arr[i], range));
1630
+ }
1631
+ return result;
1632
+ },
1633
+ eq: function(arr, arrORnum) {
1634
+ var result = [];
1635
+ if(arrORnum.constructor === Array) {
1636
+ if(arr.length === arrORnum.length) {
1637
+ for(var i = 0; i < arr.length; i++) {
1638
+ if(arr[i] === arrORnum[i]) {
1639
+ result.push(arr[i]);
1640
+ }
1641
+ }
1642
+ }
1643
+ } else {
1644
+ for(var i = 0; i < arr.length; i++) {
1645
+ if(arr[i] === arrORnum) {
1646
+ result.push(arr[i]);
1647
+ }
1648
+ }
1649
+ }
1650
+ return result;
1651
+ },
1652
+ ineq: function(arr, inf, sup, includeInf, includeSup) {
1653
+ includeInf = includeInf || false;
1654
+ includeSup = includeSup || false;
1655
+ var result = [];
1656
+ if(inf.constructor === Array && sup.constructor === Array) {
1657
+ if(arr.length === inf.length && arr.length === sup.length) {
1658
+ for(var i = 0; i < arr.length; i++) {
1659
+ if(includeInf) {
1660
+ if(includeSup) {
1661
+ if(arr[i] >= inf[i] && arr[i] <= sup[i]) {
1662
+ result.push(arr[i]);
1663
+ }
1664
+ } else {
1665
+ if(arr[i] >= inf[i] && arr[i] < sup[i]) {
1666
+ result.push(arr[i]);
1667
+ }
1668
+ }
1669
+ } else {
1670
+ if(includeSup) {
1671
+ if(arr[i] > inf[i] && arr[i] <= sup[i]) {
1672
+ result.push(arr[i]);
1673
+ }
1674
+ } else {
1675
+ if(arr[i] > inf[i] && arr[i] < sup[i]) {
1676
+ result.push(arr[i]);
1677
+ }
1678
+ }
1679
+ }
1680
+ }
1681
+ }
1682
+ } else {
1683
+ for(var i = 0; i < arr.length; i++) {
1684
+ if(includeInf) {
1685
+ if(includeSup) {
1686
+ if(arr[i] >= inf && arr[i] <= sup) {
1687
+ result.push(arr[i]);
1688
+ }
1689
+ } else {
1690
+ if(arr[i] >= inf && arr[i] < sup) {
1691
+ result.push(arr[i]);
1692
+ }
1693
+ }
1694
+ } else {
1695
+ if(includeSup) {
1696
+ if(arr[i] > inf && arr[i] <= sup) {
1697
+ result.push(arr[i]);
1698
+ }
1699
+ } else {
1700
+ if(arr[i] > inf && arr[i] < sup) {
1701
+ result.push(arr[i]);
1702
+ }
1703
+ }
1704
+ }
1705
+ }
1706
+ }
1707
+ return result;
1708
+ },
1709
+ lt: function(arr, arrORnum, includeEnd) {
1710
+ includeEnd = includeEnd || false;
1711
+ var result = [];
1712
+ if(arrORnum.constructor === Array) {
1713
+ if(arr.length === arrORnum.length) {
1714
+ for(var i = 0; i < arr.length; i++) {
1715
+ if(includeEnd) {
1716
+ if(arr[i] <= arrORnum[i]) {
1717
+ result.push(arr[i]);
1718
+ }
1719
+ } else {
1720
+ if(arr[i] < arrORnum[i]) {
1721
+ result.push(arr[i]);
1722
+ }
1723
+ }
1724
+ }
1725
+ }
1726
+ } else {
1727
+ for(var i = 0; i < arr.length; i++) {
1728
+ if(includeEnd) {
1729
+ if(arr[i] <= arrORnum) {
1730
+ result.push(arr[i]);
1731
+ }
1732
+ } else {
1733
+ if(arr[i] < arrORnum) {
1734
+ result.push(arr[i]);
1735
+ }
1736
+ }
1737
+ }
1738
+ }
1739
+ return result;
1740
+ },
1741
+ gt: function(arr, arrORnum, includeEnd) {
1742
+ includeEnd = includeEnd || false;
1743
+ var result = [];
1744
+ if(arrORnum.constructor === Array) {
1745
+ if(arr.length === arrORnum.length) {
1746
+ for(var i = 0; i < arr.length; i++) {
1747
+ if(includeEnd) {
1748
+ if(arr[i] >= arrORnum[i]) {
1749
+ result.push(arr[i]);
1750
+ }
1751
+ } else {
1752
+ if(arr[i] > arrORnum[i]) {
1753
+ result.push(arr[i]);
1754
+ }
1755
+ }
1756
+ }
1757
+ }
1758
+ } else {
1759
+ for(var i = 0; i < arr.length; i++) {
1760
+ if(includeEnd) {
1761
+ if(arr[i] >= arrORnum) {
1762
+ result.push(arr[i]);
1763
+ }
1764
+ } else {
1765
+ if(arr[i] > arrORnum) {
1766
+ result.push(arr[i]);
1767
+ }
1768
+ }
1769
+ }
1770
+ }
1771
+ return result;
1772
+ },
1773
+ max: function(arr) {
1774
+ var max = arr[0];
1775
+ for(var i = 0; i < arr.length; i++) {
1776
+ if(arr[i] > max) {
1777
+ max = arr[i];
1778
+ }
1779
+ }
1780
+ return max;
1781
+ },
1782
+ min: function(arr) {
1783
+ var min = arr[0];
1784
+ for(var i = 0; i < arr.length; i++) {
1785
+ if(arr[i] < min) {
1786
+ min = arr[i];
1787
+ }
1788
+ }
1789
+ return min;
1790
+ },
1791
+ range: function(arr) {
1792
+ return Chalkboard.stat.max(arr) - Chalkboard.stat.min(arr);
1793
+ },
1794
+ mean: function(arr, type) {
1795
+ type = type || "arithmetic";
1796
+ var result = 0;
1797
+ if(type === "arithmetic") {
1798
+ for(var i = 0; i < arr.length; i++) {
1799
+ result += arr[i];
1800
+ }
1801
+ return result / arr.length;
1802
+ } else if(type === "geometric") {
1803
+ for(var i = 0; i < arr.length; i++) {
1804
+ result *= arr[i];
1805
+ }
1806
+ return Chalkboard.real.nrt(Math.abs(result), arr.length);
1807
+ } else if(type === "harmonic") {
1808
+ for(var i = 0; i < arr.length; i++) {
1809
+ result += 1 / arr[i];
1810
+ }
1811
+ return arr.length / result;
1812
+ } else {
1813
+ return "TypeError: Parameter \"type\" must be \"arithmetic\", \"geometric\", or \"harmonic\".";
1814
+ }
1815
+ },
1816
+ median: function(arr) {
1817
+ var temp = arr.slice().sort(function(a, b) {
1818
+ return a - b;
1819
+ });
1820
+ if(temp.length % 2 === 1) {
1821
+ return temp[Math.floor(temp.length / 2)];
1822
+ } else {
1823
+ return (temp[temp.length / 2] + temp[(temp.length / 2) - 1]) / 2;
1824
+ }
1825
+ },
1826
+ mode: function(arr) {
1827
+ var temp = arr.slice().sort(function(a, b) {
1828
+ return a - b;
1829
+ });
1830
+ var bestStr = 1;
1831
+ var currStr = 1;
1832
+ var bestElm = temp[0];
1833
+ var currElm = temp[0];
1834
+ for(var i = 1; i < temp.length; i++) {
1835
+ if(temp[i - 1] !== temp[i]) {
1836
+ if(currStr > bestStr) {
1837
+ bestStr = currStr;
1838
+ bestElm = currElm;
1839
+ }
1840
+ currStr = 0;
1841
+ currElm = temp[i];
1842
+ }
1843
+ currStr++;
1844
+ }
1845
+ if(currStr > bestStr) {
1846
+ return currElm;
1847
+ } else {
1848
+ return bestElm;
1849
+ }
1850
+ },
1851
+ deviation: function(arr) {
1852
+ var result = 0;
1853
+ for(var i = 0; i < arr.length; i++) {
1854
+ result += (arr[i] - Chalkboard.stat.mean(arr)) * (arr[i] - Chalkboard.stat.mean(arr));
1855
+ }
1856
+ return Chalkboard.real.sqrt(result / arr.length);
1857
+ },
1858
+ variance: function(arr) {
1859
+ var result = 0;
1860
+ for(var i = 0; i < arr.length; i++) {
1861
+ result += (arr[i] - Chalkboard.stat.mean(arr)) * (arr[i] - Chalkboard.stat.mean(arr));
1862
+ }
1863
+ return result / arr.length;
1864
+ },
1865
+ mad: function(arr) {
1866
+ var result = 0;
1867
+ for(var i = 0; i < arr.length; i++) {
1868
+ result += Math.abs(arr[i] - Chalkboard.stat.mean(arr));
1869
+ }
1870
+ return result / arr.length;
1871
+ },
1872
+ error: function(arr) {
1873
+ return Chalkboard.stat.deviation(arr) / Chalkboard.real.sqrt(arr.length);
1874
+ },
1875
+ skewness: function(arr) {
1876
+ var result = 0;
1877
+ var mean = Chalkboard.stat.mean(arr);
1878
+ var deviation = Chalkboard.stat.deviation(arr);
1879
+ for(var i = 0; i < arr.length; i++) {
1880
+ result += (arr[i] - mean) * (arr[i] - mean) * (arr[i] - mean);
1881
+ }
1882
+ return result / ((arr.length - 1) * (deviation * deviation * deviation));
1883
+ },
1884
+ kurtosis: function(arr) {
1885
+ var result = 0;
1886
+ var mean = Chalkboard.stat.mean(arr);
1887
+ var deviation = Chalkboard.stat.deviation(arr);
1888
+ for(var i = 0; i < arr.length; i++) {
1889
+ result += (arr[i] - mean) * (arr[i] - mean) * (arr[i] - mean) * (arr[i] - mean);
1890
+ }
1891
+ return result / (deviation * deviation * deviation * deviation) - 3;
1892
+ },
1893
+ confidenceInterval: function(arr) {
1894
+ return [Chalkboard.stat.mean(arr) - 1.96 * (Chalkboard.stat.deviation(arr) / Chalkboard.real.sqrt(arr.length)), Chalkboard.stat.mean(arr) + 1.96 * (Chalkboard.stat.deviation(arr) / Chalkboard.real.sqrt(arr.length))];
1895
+ },
1896
+ percentile: function(arr, num) {
1897
+ var result = 0;
1898
+ for(var i = 0; i < arr.length; i++) {
1899
+ if(num >= arr[i]) {
1900
+ result++;
1901
+ }
1902
+ }
1903
+ return (result / arr.length) * 100;
1904
+ },
1905
+ quartile: function(arr, type) {
1906
+ var temp = arr.slice().sort(function(a, b) {
1907
+ return a - b;
1908
+ });
1909
+ var lo = temp.slice(0, Math.floor(temp.length / 2));
1910
+ var hi = temp.slice(Math.ceil(temp.length / 2));
1911
+ if(type === "Q1") {
1912
+ return Chalkboard.stat.median(lo);
1913
+ } else if(type === "Q2") {
1914
+ return Chalkboard.stat.median(arr);
1915
+ } else if(type === "Q3") {
1916
+ return Chalkboard.stat.median(hi);
1917
+ } else {
1918
+ return "TypeError: Parameter \"type\" must be either \"Q1\", \"Q2\", or \"Q3\".";
1919
+ }
1920
+ },
1921
+ convolution: function(arr1, arr2) {
1922
+ var result = [];
1923
+ for(var i = 0; i < arr1.length + arr2.length - 1; i++) {
1924
+ var sum = 0;
1925
+ for(var j = Math.max(0, i - arr2.length + 1); j < Math.min(arr1.length, i + 1); j++) {
1926
+ sum += arr1[j] * arr2[i - j];
1927
+ }
1928
+ result.push(sum);
1929
+ }
1930
+ return result;
1931
+ },
1932
+ correlation: function(arr1, arr2) {
1933
+ var result = [];
1934
+ for(var i = 0; i < arr1.length + arr2.length - 1; i++) {
1935
+ var sum = 0;
1936
+ for(var j = Math.max(0, i - arr2.length + 1); j < Math.min(arr1.length, i + 1); j++) {
1937
+ sum += arr1[j] * arr2[arr2.length - 1 - i + j];
1938
+ }
1939
+ result.push(sum);
1940
+ }
1941
+ return result;
1942
+ },
1943
+ autocorrelation: function(arr) {
1944
+ return Chalkboard.stat.correlation(arr, arr);
1945
+ },
1946
+ change: function(initialArr, finalArr) {
1947
+ var result = [];
1948
+ if(initialArr.length === finalArr.length) {
1949
+ for(var i = 0; i < initialArr.length; i++) {
1950
+ result.push(Chalkboard.numb.change(initialArr[i], finalArr[i]));
1951
+ }
1952
+ return result;
1953
+ } else {
1954
+ return undefined;
1955
+ }
1956
+ },
1957
+ chiSquared: function(observedArr, expectedArr) {
1958
+ var result = [];
1959
+ if(observedArr.length === expectedArr.length) {
1960
+ for(var i = 0; i < observedArr.length; i++) {
1961
+ result.push(((observedArr[i] - expectedArr[i]) * (observedArr[i] - expectedArr[i])) / expectedArr[i]);
1962
+ }
1963
+ return result;
1964
+ } else {
1965
+ return undefined;
1966
+ }
1967
+ },
1968
+ Gaussian: function(height, mean, deviation) {
1969
+ return Chalkboard.real.function(height.toString() + " * Math.exp(-((x - " + mean.toString() + ") * (x - " + mean.toString() + ")) / (2 * " + deviation.toString() + " * " + deviation.toString() + "))");
1970
+ },
1971
+ toVector: function(arr, type) {
1972
+ if(type === "vec2") {
1973
+ return Chalkboard.vec2.new(arr[0], arr[1]);
1974
+ } else if(type === "vec3") {
1975
+ return Chalkboard.vec3.new(arr[0], arr[1], arr[2]);
1976
+ } else if(type === "vec4") {
1977
+ return Chalkboard.vec4.new(arr[0], arr[1], arr[2], arr[3]);
1978
+ } else {
1979
+ return "TypeError: Parameter \"type\" should be \"vec2\", \"vec3\", or \"vec4\".";
1980
+ }
1981
+ },
1982
+ toMatrix: function(arr, rows, cols) {
1983
+ var result = Chalkboard.matr.new();
1984
+ var index = 0;
1985
+ for(var i = 0; i < rows; i++) {
1986
+ result[i] = [];
1987
+ for(var j = 0; j < cols; j++) {
1988
+ if(index < arr.length) {
1989
+ result[i].push(arr[index]);
1990
+ } else {
1991
+ result[i].push(0);
1992
+ }
1993
+ index++;
1994
+ }
1995
+ }
1996
+ return result;
1997
+ },
1998
+ toObject: function(arr) {
1999
+ var result = {};
2000
+ for(var i = 0; i < arr.length; i++) {
2001
+ result["_" + i] = arr[i];
2002
+ }
2003
+ return result;
2004
+ },
2005
+ toString: function(arr) {
2006
+ return "[" + arr.join(", ") + "]";
2007
+ },
2008
+ print: function(arr) {
2009
+ console.log(Chalkboard.stat.toString(arr));
2010
+ }
2011
+ },
2012
+ vec2: {
2013
+ new: function(x, y) {
2014
+ if(y === undefined) {
2015
+ return {x: x, y: x, type: "vec2"};
2016
+ } else {
2017
+ return {x: x, y: y, type: "vec2"};
2018
+ }
2019
+ },
2020
+ random: function(inf, sup) {
2021
+ return Chalkboard.vec2.new(Chalkboard.numb.random(inf, sup), Chalkboard.numb.random(inf, sup));
2022
+ },
2023
+ mag: function(vec2) {
2024
+ return Chalkboard.real.sqrt((vec2.x * vec2.x) + (vec2.y * vec2.y));
2025
+ },
2026
+ magsq: function(vec2) {
2027
+ return (vec2.x * vec2.x) + (vec2.y * vec2.y);
2028
+ },
2029
+ magset: function(vec2, num) {
2030
+ return Chalkboard.vec2.scl(Chalkboard.vec2.normalize(vec2), num);
2031
+ },
2032
+ ang: function(vec2) {
2033
+ return Chalkboard.trig.arctan2(vec2.y, vec2.x);
2034
+ },
2035
+ slope: function(vec2) {
2036
+ return vec2.y / vec2.x;
2037
+ },
2038
+ azimuth: function(vec2) {
2039
+ return Chalkboard.trig.arctan(vec2.x / vec2.y);
2040
+ },
2041
+ average: function(vec2) {
2042
+ return (vec2.x + vec2.y) / 2;
2043
+ },
2044
+ normalize: function(vec2) {
2045
+ return Chalkboard.vec2.new(vec2.x / Chalkboard.vec2.mag(vec2), vec2.y / Chalkboard.vec2.mag(vec2));
2046
+ },
2047
+ zero: function(vec2) {
2048
+ return Chalkboard.vec2.new(vec2.x * 0, vec2.y * 0);
2049
+ },
2050
+ negate: function(vec2) {
2051
+ return Chalkboard.vec2.new(-vec2.x, -vec2.y);
2052
+ },
2053
+ reciprocate: function(vec2) {
2054
+ return Chalkboard.vec2.new(1 / vec2.x, 1 / vec2.y);
2055
+ },
2056
+ absolute: function(vec2) {
2057
+ return Chalkboard.vec2.new(Math.abs(vec2.x), Math.abs(vec2.y));
2058
+ },
2059
+ round: function(vec2) {
2060
+ return Chalkboard.vec2.new(Math.round(vec2.x), Math.round(vec2.y));
2061
+ },
2062
+ dist: function(vec2_1, vec2_2) {
2063
+ return Chalkboard.real.sqrt(((vec2_2.x - vec2_1.x) * (vec2_2.x - vec2_1.x)) + ((vec2_2.y - vec2_1.y) * (vec2_2.y - vec2_1.y)));
2064
+ },
2065
+ distsq: function(vec2_1, vec2_2) {
2066
+ return ((vec2_2.x - vec2_1.x) * (vec2_2.x - vec2_1.x)) + ((vec2_2.y - vec2_1.y) * (vec2_2.y - vec2_1.y));
2067
+ },
2068
+ angBtwn: function(vec2_1, vec2_2) {
2069
+ return Math.acos((Chalkboard.vec2.dot(vec2_1, vec2_2)) / (Chalkboard.vec2.mag(vec2_1) * Chalkboard.vec2.mag(vec2_2)));
2070
+ },
2071
+ scl: function(vec2, num) {
2072
+ return Chalkboard.vec2.new(vec2.x * num, vec2.y * num);
2073
+ },
2074
+ constrain: function(vec2, range) {
2075
+ return Chalkboard.vec2.new(Chalkboard.numb.constrain(vec2.x, range), Chalkboard.numb.constrain(vec2.y, range));
2076
+ },
2077
+ add: function(vec2_1, vec2_2) {
2078
+ return Chalkboard.vec2.new(vec2_1.x + vec2_2.x, vec2_1.y + vec2_2.y);
2079
+ },
2080
+ sub: function(vec2_1, vec2_2) {
2081
+ return Chalkboard.vec2.new(vec2_1.x - vec2_2.x, vec2_1.y - vec2_2.y);
2082
+ },
2083
+ mid: function(vec2_1, vec2_2) {
2084
+ return Chalkboard.vec2.new((vec2_1.x + vec2_2.x) / 2, (vec2_1.y + vec2_2.y) / 2);
2085
+ },
2086
+ dot: function(vec2_1, vec2_2) {
2087
+ return (vec2_1.x * vec2_2.x) + (vec2_1.y * vec2_2.y);
2088
+ },
2089
+ cross: function(vec2_1, vec2_2) {
2090
+ return Chalkboard.vec3.new(0, 0, (vec2_1.x * vec2_2.y) - (vec2_1.y * vec2_2.x));
2091
+ },
2092
+ proj: function(vec2_1, vec2_2) {
2093
+ return Chalkboard.vec2.scl(vec2_2, Chalkboard.vec2.dot(vec2_1, vec2_2) / Chalkboard.vec2.dot(vec2_2, vec2_2));
2094
+ },
2095
+ oproj: function(vec2_1, vec2_2) {
2096
+ return Chalkboard.vec2.sub(vec2_1, Chalkboard.vec2.proj(vec2_1, vec2_2));
2097
+ },
2098
+ reflect: function(vec2_1, vec2_2) {
2099
+ return Chalkboard.vec2.sub(vec2_1, Chalkboard.vec2.scl(vec2_2, 2 * Chalkboard.vec2.dot(vec2_1, vec2_2)));
2100
+ },
2101
+ refract: function(vec2_1, vec2_2, refractiveIndex) {
2102
+ if(refractiveIndex > 0) {
2103
+ var perp = Chalkboard.vec2.scl(Chalkboard.vec2.sub(vec2_1, Chalkboard.vec2.scl(vec2_2, Chalkboard.vec2.dot(vec2_1, vec2_2))), refractiveIndex);
2104
+ var parr = Chalkboard.vec2.scl(vec2_2, -Chalkboard.real.sqrt(1 - (refractiveIndex * refractiveIndex) * (1 - (Chalkboard.vec2.dot(vec2_1, vec2_2) * Chalkboard.vec2.dot(vec2_1, vec2_2)))));
2105
+ return Chalkboard.vec2.add(perp, parr);
2106
+ } else {
2107
+ return undefined;
2108
+ }
2109
+ },
2110
+ fromAngle: function(rad) {
2111
+ return Chalkboard.vec2.new(Chalkboard.trig.cos(rad), Chalkboard.trig.sin(rad));
2112
+ },
2113
+ fromPolar: function(vec2) {
2114
+ return Chalkboard.vec2.new(vec2.x * Chalkboard.trig.cos(vec2.y), vec2.x * Chalkboard.trig.sin(vec2.y));
2115
+ },
2116
+ fromBipolar: function(vec2) {
2117
+ return Chalkboard.vec2.new((vec2.x * vec2.x - vec2.y * vec2.y) / 4, Chalkboard.real.sqrt(16 * vec2.x * vec2.x - (vec2.x * vec2.x - vec2.y * vec2.y + 4) * (vec2.x * vec2.x - vec2.y * vec2.y + 4)));
2118
+ },
2119
+ toPolar: function(vec2) {
2120
+ return Chalkboard.vec2.new(Chalkboard.vec2.mag(vec2), Chalkboard.vec2.ang(vec2));
2121
+ },
2122
+ toBipolar: function(vec2) {
2123
+ return Chalkboard.vec2.new((vec2.x + 1) * (vec2.x + 1) + (vec2.y * vec2.y), (vec2.x - 1) * (vec2.x - 1) + (vec2.y * vec2.y));
2124
+ },
2125
+ toMatrix: function(vec2, type) {
2126
+ type = type || "col";
2127
+ if(type === "col") {
2128
+ return Chalkboard.matr.new([vec2.x], [vec2.y]);
2129
+ } else if(type === "row") {
2130
+ return Chalkboard.matr.new([vec2.x, vec2.y]);
2131
+ } else {
2132
+ return "TypeError: Parameter \"type\" should be \"row\" or \"col\".";
2133
+ }
2134
+ },
2135
+ toComplex: function(vec2) {
2136
+ return Chalkboard.comp.new(vec2.x, vec2.y);
2137
+ },
2138
+ toArray: function(vec2) {
2139
+ return [vec2.x, vec2.y];
2140
+ },
2141
+ toString: function(vec2) {
2142
+ return "(" + vec2.x.toString() + ", " + vec2.y.toString() + ")";
2143
+ },
2144
+ field: function(p, q) {
2145
+ return {p: p, q: q, type: "vec2field"};
2146
+ },
2147
+ fromField: function(vec2field, vec2) {
2148
+ var p = Chalkboard.real.parse("(x, y) => " + vec2field.p),
2149
+ q = Chalkboard.real.parse("(x, y) => " + vec2field.q);
2150
+ return Chalkboard.vec2.new(p(vec2.x, vec2.y), q(vec2.x, vec2.y));
2151
+ },
2152
+ print: function(vec2) {
2153
+ console.log(Chalkboard.vec2.toString(vec2));
2154
+ }
2155
+ },
2156
+ vec3: {
2157
+ new: function(x, y, z) {
2158
+ if(y === undefined && z === undefined) {
2159
+ return {x: x, y: x, z: x, type: "vec3"};
2160
+ } else {
2161
+ return {x: x, y: y, z: z, type: "vec3"};
2162
+ }
2163
+ },
2164
+ random: function(inf, sup) {
2165
+ return Chalkboard.vec3.new(Chalkboard.numb.random(inf, sup), Chalkboard.numb.random(inf, sup), Chalkboard.numb.random(inf, sup));
2166
+ },
2167
+ mag: function(vec3) {
2168
+ return Chalkboard.real.sqrt((vec3.x * vec3.x) + (vec3.y * vec3.y) + (vec3.z * vec3.z));
2169
+ },
2170
+ magsq: function(vec3) {
2171
+ return (vec3.x * vec3.x) + (vec3.y * vec3.y) + (vec3.z * vec3.z);
2172
+ },
2173
+ magset: function(vec3, num) {
2174
+ return Chalkboard.vec3.scl(Chalkboard.vec3.normalize(vec3), num);
2175
+ },
2176
+ ang: function(vec3) {
2177
+ return [Math.acos(vec3.x / Chalkboard.vec3.mag(vec3)), Math.acos(vec3.y / Chalkboard.vec3.mag(vec3)), Math.acos(vec3.z / Chalkboard.vec3.mag(vec3))];
2178
+ },
2179
+ slope: function(vec3) {
2180
+ return vec3.z / Chalkboard.real.sqrt((vec3.x * vec3.x) + (vec3.y * vec3.y));
2181
+ },
2182
+ azimuth: function(vec3) {
2183
+ return Chalkboard.trig.arctan(vec3.x / vec3.y);
2184
+ },
2185
+ average: function(vec3) {
2186
+ return (vec3.x + vec3.y + vec3.z) / 3;
2187
+ },
2188
+ normalize: function(vec3) {
2189
+ return Chalkboard.vec3.new(vec3.x / Chalkboard.vec3.mag(vec3), vec3.y / Chalkboard.vec3.mag(vec3), vec3.z / Chalkboard.vec3.mag(vec3));
2190
+ },
2191
+ zero: function(vec3) {
2192
+ return Chalkboard.vec3.new(vec3.x * 0, vec3.y * 0, vec3.z * 0);
2193
+ },
2194
+ negate: function(vec3) {
2195
+ return Chalkboard.vec3.new(-vec3.x, -vec3.y, -vec3.z);
2196
+ },
2197
+ reciprocate: function(vec3) {
2198
+ return Chalkboard.vec3.new(1 / vec3.x, 1 / vec3.y, 1 / vec3.z);
2199
+ },
2200
+ absolute: function(vec3) {
2201
+ return Chalkboard.vec3.new(Math.abs(vec3.x), Math.abs(vec3.y), Math.abs(vec3.z));
2202
+ },
2203
+ round: function(vec3) {
2204
+ return Chalkboard.vec3.new(Math.round(vec3.x), Math.round(vec3.y), Math.round(vec3.z));
2205
+ },
2206
+ dist: function(vec3_1, vec3_2) {
2207
+ return Chalkboard.real.sqrt(((vec3_2.x - vec3_1.x) * (vec3_2.x - vec3_1.x)) + ((vec3_2.y - vec3_1.y) * (vec3_2.y - vec3_1.y)) + ((vec3_2.z - vec3_1.z) * (vec3_2.z - vec3_1.z)));
2208
+ },
2209
+ distsq: function(vec3_1, vec3_2) {
2210
+ return ((vec3_2.x - vec3_1.x) * (vec3_2.x - vec3_1.x)) + ((vec3_2.y - vec3_1.y) * (vec3_2.y - vec3_1.y)) + ((vec3_2.z - vec3_1.z) * (vec3_2.z - vec3_1.z));
2211
+ },
2212
+ angBtwn: function(vec3_1, vec3_2) {
2213
+ return Math.acos((Chalkboard.vec3.dot(vec3_1, vec3_2)) / (Chalkboard.vec3.mag(vec3_1) * Chalkboard.vec3.mag(vec3_2)));
2214
+ },
2215
+ scl: function(vec3, num) {
2216
+ return Chalkboard.vec3.new(vec3.x * num, vec3.y * num, vec3.z * num);
2217
+ },
2218
+ constrain: function(vec3, range) {
2219
+ return Chalkboard.vec3.new(Chalkboard.numb.constrain(vec3.x, range), Chalkboard.numb.constrain(vec3.y, range), Chalkboard.numb.constrain(vec3.z, range));
2220
+ },
2221
+ add: function(vec3_1, vec3_2) {
2222
+ return Chalkboard.vec3.new(vec3_1.x + vec3_2.x, vec3_1.y + vec3_2.y, vec3_1.z + vec3_2.z);
2223
+ },
2224
+ sub: function(vec3_1, vec3_2) {
2225
+ return Chalkboard.vec3.new(vec3_1.x - vec3_2.x, vec3_1.y - vec3_2.y, vec3_1.z - vec3_2.z);
2226
+ },
2227
+ mid: function(vec3_1, vec3_2) {
2228
+ return Chalkboard.vec3.new((vec3_1.x + vec3_2.x) / 2, (vec3_1.y + vec3_2.y) / 2, (vec3_1.z + vec3_2.z) / 2);
2229
+ },
2230
+ dot: function(vec3_1, vec3_2) {
2231
+ return (vec3_1.x * vec3_2.x) + (vec3_1.y * vec3_2.y) + (vec3_1.z * vec3_2.z);
2232
+ },
2233
+ cross: function(vec3_1, vec3_2) {
2234
+ return Chalkboard.vec3.new((vec3_1.y * vec3_2.z) - (vec3_1.z * vec3_2.y), (vec3_1.z * vec3_2.x) - (vec3_1.x * vec3_2.z), (vec3_1.x * vec3_2.y) - (vec3_1.y * vec3_2.x));
2235
+ },
2236
+ scalarTriple: function(vec3_1, vec3_2, vec3_3) {
2237
+ return Chalkboard.vec3.dot(vec3_1, Chalkboard.vec3.cross(vec3_2, vec3_3));
2238
+ },
2239
+ vectorTriple: function(vec3_1, vec3_2, vec3_3) {
2240
+ return Chalkboard.vec3.cross(vec3_1, Chalkboard.vec3.cross(vec3_2, vec3_3));
2241
+ },
2242
+ proj: function(vec3_1, vec3_2) {
2243
+ return Chalkboard.vec3.scl(vec3_2, Chalkboard.vec3.dot(vec3_1, vec3_2) / Chalkboard.vec3.dot(vec3_2, vec3_2));
2244
+ },
2245
+ oproj: function(vec3_1, vec3_2) {
2246
+ return Chalkboard.vec3.sub(vec3_1, Chalkboard.vec3.proj(vec3_1, vec3_2));
2247
+ },
2248
+ reflect: function(vec3_1, vec3_2) {
2249
+ return Chalkboard.vec3.sub(vec3_1, Chalkboard.vec3.scl(vec3_2, 2 * Chalkboard.vec3.dot(vec3_1, vec3_2)));
2250
+ },
2251
+ refract: function(vec3_1, vec3_2, refractiveIndex) {
2252
+ if(refractiveIndex > 0) {
2253
+ var perp = Chalkboard.vec3.scl(Chalkboard.vec3.sub(vec3_1, Chalkboard.vec3.scl(vec3_2, Chalkboard.vec3.dot(vec3_1, vec3_2))), refractiveIndex);
2254
+ var parr = Chalkboard.vec3.scl(vec3_2, -Chalkboard.real.sqrt(1 - (refractiveIndex * refractiveIndex) * (1 - (Chalkboard.vec3.dot(vec3_1, vec3_2) * Chalkboard.vec3.dot(vec3_1, vec3_2)))));
2255
+ return Chalkboard.vec3.add(perp, parr);
2256
+ } else {
2257
+ return undefined;
2258
+ }
2259
+ },
2260
+ fromAngles: function(rad1, rad2) {
2261
+ return Chalkboard.vec3.new(Chalkboard.trig.cos(rad1) * Chalkboard.trig.cos(rad2), Chalkboard.trig.sin(rad1) * Chalkboard.trig.cos(rad2), Chalkboard.trig.sin(rad2));
2262
+ },
2263
+ fromVector: function(vec2) {
2264
+ return Chalkboard.vec3.new(vec2.x, vec2.y, 0);
2265
+ },
2266
+ fromCylindrical: function(vec3) {
2267
+ return Chalkboard.vec3.new(vec3.x * Chalkboard.trig.cos(vec3.y), vec3.x * Chalkboard.trig.sin(vec3.y), vec3.z);
2268
+ },
2269
+ fromSpherical: function(vec3) {
2270
+ return Chalkboard.vec3.new(vec3.x * Chalkboard.trig.sin(vec3.z) * Chalkboard.trig.cos(vec3.y), vec3.x * Chalkboard.trig.sin(vec3.z) * Chalkboard.trig.sin(vec3.y), vec3.x * Chalkboard.trig.cos(vec3.z));
2271
+ },
2272
+ toCylindrical: function(vec3) {
2273
+ return Chalkboard.vec3.new(Chalkboard.vec2.mag(vec3), Chalkboard.vec2.ang(vec3), vec3.z);
2274
+ },
2275
+ toSpherical: function(vec3) {
2276
+ return Chalkboard.vec3.new(Chalkboard.vec3.mag(vec3), Chalkboard.vec2.ang(vec3), Chalkboard.vec3.ang(vec3)[2]);
2277
+ },
2278
+ toMatrix: function(vec3, type) {
2279
+ type = type || "col";
2280
+ if(type === "col") {
2281
+ return Chalkboard.matr.new([vec3.x], [vec3.y], [vec3.z]);
2282
+ } else if(type === "row") {
2283
+ return Chalkboard.matr.new([vec3.x, vec3.y, vec3.z]);
2284
+ } else {
2285
+ return "TypeError: Parameter \"type\" should be \"row\" or \"col\".";
2286
+ }
2287
+ },
2288
+ toArray: function(vec3) {
2289
+ return [vec3.x, vec3.y, vec3.z];
2290
+ },
2291
+ toString: function(vec3) {
2292
+ return "(" + vec3.x.toString() + ", " + vec3.y.toString() + ", " + vec3.z.toString() + ")";
2293
+ },
2294
+ field: function(p, q, r) {
2295
+ return {p: p, q: q, r: r, type: "vec3field"};
2296
+ },
2297
+ fromField: function(vec3field, vec3) {
2298
+ var p = Chalkboard.real.parse("(x, y, z) => " + vec3field.p),
2299
+ q = Chalkboard.real.parse("(x, y, z) => " + vec3field.q),
2300
+ r = Chalkboard.real.parse("(x, y, z) => " + vec3field.r);
2301
+ return Chalkboard.vec3.new(p(vec3.x, vec3.y, vec3.z), q(vec3.x, vec3.y, vec3.z), r(vec3.x, vec3.y, vec3.z));
2302
+ },
2303
+ print: function(vec3) {
2304
+ console.log(Chalkboard.vec3.toString(vec3));
2305
+ }
2306
+ },
2307
+ vec4: {
2308
+ new: function(x, y, z, w) {
2309
+ if(y === undefined && z === undefined && w === undefined) {
2310
+ return {x: x, y: x, z: x, w: x, type: "vec4"};
2311
+ } else {
2312
+ return {x: x, y: y, z: z, w: w, type: "vec4"};
2313
+ }
2314
+ },
2315
+ random: function(inf, sup) {
2316
+ return Chalkboard.vec4.new(Chalkboard.numb.random(inf, sup), Chalkboard.numb.random(inf, sup), Chalkboard.numb.random(inf, sup), Chalkboard.numb.random(inf, sup));
2317
+ },
2318
+ mag: function(vec4) {
2319
+ return Chalkboard.real.sqrt((vec4.x * vec4.x) + (vec4.y * vec4.y) + (vec4.z * vec4.z) + (vec4.w * vec4.w));
2320
+ },
2321
+ magsq: function(vec4) {
2322
+ return (vec4.x * vec4.x) + (vec4.y * vec4.y) + (vec4.z * vec4.z) + (vec4.w * vec4.w);
2323
+ },
2324
+ magset: function(vec4, num) {
2325
+ return Chalkboard.vec4.scl(Chalkboard.vec4.normalize(vec4), num);
2326
+ },
2327
+ ang: function(vec4) {
2328
+ return [Math.acos(vec4.x / Chalkboard.vec4.mag(vec4)), Math.acos(vec4.y / Chalkboard.vec4.mag(vec4)), Math.acos(vec4.z / Chalkboard.vec4.mag(vec4)), Math.acos(vec4.w / Chalkboard.vec4.mag(vec4))];
2329
+ },
2330
+ slope: function(vec4) {
2331
+ return vec4.w / Chalkboard.real.sqrt((vec4.x * vec4.x) + (vec4.y * vec4.y) + (vec4.z * vec4.z));
2332
+ },
2333
+ average: function(vec4) {
2334
+ return (vec4.x + vec4.y + vec4.z + vec4.w) / 4;
2335
+ },
2336
+ normalize: function(vec4) {
2337
+ return Chalkboard.vec4.new(vec4.x / Chalkboard.vec4.mag(vec4), vec4.y / Chalkboard.vec4.mag(vec4), vec4.z / Chalkboard.vec4.mag(vec4), vec4.w / Chalkboard.vec4.mag(vec4));
2338
+ },
2339
+ zero: function(vec4) {
2340
+ return Chalkboard.vec4.new(vec4.x * 0, vec4.y * 0, vec4.z * 0, vec4.w * 0);
2341
+ },
2342
+ negate: function(vec4) {
2343
+ return Chalkboard.vec4.new(-vec4.x, -vec4.y, -vec4.z, -vec4.w);
2344
+ },
2345
+ reciprocate: function(vec4) {
2346
+ return Chalkboard.vec4.new(1 / vec4.x, 1 / vec4.y, 1 / vec4.z, 1 / vec4.w);
2347
+ },
2348
+ absolute: function(vec4) {
2349
+ return Chalkboard.vec4.new(Math.abs(vec4.x), Math.abs(vec4.y), Math.abs(vec4.z), Math.abs(vec4.w));
2350
+ },
2351
+ round: function(vec4) {
2352
+ return Chalkboard.vec4.new(Math.round(vec4.x), Math.round(vec4.y), Math.round(vec4.z), Math.round(vec4.w));
2353
+ },
2354
+ dist: function(vec4_1, vec4_2) {
2355
+ return Chalkboard.real.sqrt(((vec4_2.x - vec4_1.x) * (vec4_2.x - vec4_1.x)) + ((vec4_2.y - vec4_1.y) * (vec4_2.y - vec4_1.y)) + ((vec4_2.z - vec4_1.z) * (vec4_2.z - vec4_1.z)) + ((vec4_2.w - vec4_1.w) * (vec4_2.w - vec4_1.w)));
2356
+ },
2357
+ distsq: function(vec4_1, vec4_2) {
2358
+ return ((vec4_2.x - vec4_1.x) * (vec4_2.x - vec4_1.x)) + ((vec4_2.y - vec4_1.y) * (vec4_2.y - vec4_1.y)) + ((vec4_2.z - vec4_1.z) * (vec4_2.z - vec4_1.z)) + ((vec4_2.w - vec4_1.w) * (vec4_2.w - vec4_1.w));
2359
+ },
2360
+ angBtwn: function(vec4_1, vec4_2) {
2361
+ return Math.acos((Chalkboard.vec4.dot(vec4_1, vec4_2)) / (Chalkboard.vec4.mag(vec4_1) * Chalkboard.vec4.mag(vec4_2)));
2362
+ },
2363
+ scl: function(vec4, num) {
2364
+ return Chalkboard.vec4.new(vec4.x * num, vec4.y * num, vec4.z * num, vec4.w * num);
2365
+ },
2366
+ constrain: function(vec4, range) {
2367
+ return Chalkboard.vec4.new(Chalkboard.numb.constrain(vec4.x, range), Chalkboard.numb.constrain(vec4.y, range), Chalkboard.numb.constrain(vec4.z, range), Chalkboard.numb.constrain(vec4.w, range));
2368
+ },
2369
+ add: function(vec4_1, vec4_2) {
2370
+ return Chalkboard.vec4.new(vec4_1.x + vec4_2.x, vec4_1.y + vec4_2.y, vec4_1.z + vec4_2.z, vec4_1.w + vec4_2.w);
2371
+ },
2372
+ sub: function(vec4_1, vec4_2) {
2373
+ return Chalkboard.vec4.new(vec4_1.x - vec4_2.x, vec4_1.y - vec4_2.y, vec4_1.z - vec4_2.z, vec4_1.w - vec4_2.w);
2374
+ },
2375
+ mid: function(vec4_1, vec4_2) {
2376
+ return Chalkboard.vec4.new((vec4_1.x + vec4_2.x) / 2, (vec4_1.y + vec4_2.y) / 2, (vec4_1.z + vec4_2.z) / 2, (vec4_1.w + vec4_2.w) / 2);
2377
+ },
2378
+ dot: function(vec4_1, vec4_2) {
2379
+ return (vec4_1.x * vec4_2.x) + (vec4_1.y * vec4_2.y) + (vec4_1.z * vec4_2.z) + (vec4_1.w * vec4_2.w);
2380
+ },
2381
+ proj: function(vec4_1, vec4_2) {
2382
+ return Chalkboard.vec4.scl(vec4_2, Chalkboard.vec4.dot(vec4_1, vec4_2) / Chalkboard.vec4.dot(vec4_2, vec4_2));
2383
+ },
2384
+ oproj: function(vec4_1, vec4_2) {
2385
+ return Chalkboard.vec4.sub(vec4_1, Chalkboard.vec4.proj(vec4_1, vec4_2));
2386
+ },
2387
+ reflect: function(vec4_1, vec4_2) {
2388
+ return Chalkboard.vec4.sub(vec4_1, Chalkboard.vec4.scl(vec4_2, 2 * Chalkboard.vec4.dot(vec4_1, vec4_2)));
2389
+ },
2390
+ refract: function(vec4_1, vec4_2, refractiveIndex) {
2391
+ if(refractiveIndex > 0) {
2392
+ var perp = Chalkboard.vec4.scl(Chalkboard.vec4.sub(vec4_1, Chalkboard.vec4.scl(vec4_2, Chalkboard.vec4.dot(vec4_1, vec4_2))), refractiveIndex);
2393
+ var parr = Chalkboard.vec4.scl(vec4_2, -Chalkboard.real.sqrt(1 - (refractiveIndex * refractiveIndex) * (1 - (Chalkboard.vec4.dot(vec4_1, vec4_2) * Chalkboard.vec4.dot(vec4_1, vec4_2)))));
2394
+ return Chalkboard.vec4.add(perp, parr);
2395
+ } else {
2396
+ return undefined;
2397
+ }
2398
+ },
2399
+ fromVector: function(vec3) {
2400
+ return Chalkboard.vec4.new(vec3.x, vec3.y, vec3.z, 0);
2401
+ },
2402
+ fromHypercylindrical: function(vec4) {
2403
+ return Chalkboard.vec4.new(vec4.x * Chalkboard.trig.cos(vec4.y) * Chalkboard.trig.cos(vec4.z), vec4.x * Chalkboard.trig.cos(vec4.y) * Chalkboard.trig.sin(vec4.z), vec4.x * Chalkboard.trig.sin(vec4.y), vec4.w);
2404
+ },
2405
+ fromHyperspherical: function(vec4) {
2406
+ return Chalkboard.vec4.new(vec4.x * Chalkboard.trig.cos(vec4.y) * Chalkboard.trig.cos(vec4.z) * Chalkboard.trig.cos(vec4.w), vec4.x * Chalkboard.trig.cos(vec4.y) * Chalkboard.trig.sin(vec4.z) * Chalkboard.trig.cos(vec4.w), vec4.x * Chalkboard.trig.sin(vec4.y) * Chalkboard.trig.cos(vec4.w), vec4.x * Chalkboard.trig.sin(vec4.w));
2407
+ },
2408
+ toHypercylindrical: function(vec4) {
2409
+ return Chalkboard.vec4.new(Chalkboard.vec3.mag(vec4), Chalkboard.vec2.ang(vec4), Chalkboard.vec3.ang(vec4)[2], vec4.w);
2410
+ },
2411
+ toHyperspherical: function(vec4) {
2412
+ return Chalkboard.vec4.new(Chalkboard.vec4.mag(vec4), Chalkboard.vec2.ang(vec4), Chalkboard.vec3.ang(vec4)[2], Chalkboard.vec4.ang(vec4)[3]);
2413
+ },
2414
+ toMatrix: function(vec4, type) {
2415
+ type = type || "col";
2416
+ if(type === "col") {
2417
+ return Chalkboard.matr.new([vec4.x], [vec4.y], [vec4.z], [vec4.w]);
2418
+ } else if(type === "row") {
2419
+ return Chalkboard.matr.new([vec4.x, vec4.y, vec4.z, vec4.w]);
2420
+ } else {
2421
+ return "TypeError: Parameter \"type\" should be \"row\" or \"col\".";
2422
+ }
2423
+ },
2424
+ toQuaternion: function(vec4) {
2425
+ return Chalkboard.quat.new(vec4.x, vec4.y, vec4.z, vec4.w);
2426
+ },
2427
+ toArray: function(vec4) {
2428
+ return [vec4.x, vec4.y, vec4.z, vec4.w];
2429
+ },
2430
+ toString: function(vec4) {
2431
+ return "(" + vec4.x.toString() + ", " + vec4.y.toString() + ", " + vec4.z.toString() + ", " + vec4.w.toString() + ")";
2432
+ },
2433
+ field: function(p, q, r, s) {
2434
+ return {p: p, q: q, r: r, s: s, type: "vec4field"};
2435
+ },
2436
+ fromField: function(vec4field, vec4) {
2437
+ var p = Chalkboard.real.parse("(x, y, z, w) => " + vec4field.p),
2438
+ q = Chalkboard.real.parse("(x, y, z, w) => " + vec4field.q),
2439
+ r = Chalkboard.real.parse("(x, y, z, w) => " + vec4field.r),
2440
+ s = Chalkboard.real.parse("(x, y, z, w) => " + vec4field.s);
2441
+ return Chalkboard.vec4.new(p(vec4.x, vec4.y, vec4.z, vec4.w), q(vec4.x, vec4.y, vec4.z, vec4.w), r(vec4.x, vec4.y, vec4.z, vec4.w), s(vec4.x, vec4.y, vec4.z, vec4.w));
2442
+ },
2443
+ print: function(vec4) {
2444
+ console.log(Chalkboard.vec4.toString(vec4));
2445
+ }
2446
+ },
2447
+ matr: {
2448
+ new: function(matrix) {
2449
+ return Array.from(arguments);
2450
+ },
2451
+ rows: function(matr) {
2452
+ return matr.length;
2453
+ },
2454
+ cols: function(matr) {
2455
+ return matr[0].length;
2456
+ },
2457
+ empty: function(dimension) {
2458
+ if(Number.isInteger(dimension) && dimension > 0) {
2459
+ var result = Chalkboard.matr.new();
2460
+ for(var i = 0; i < dimension; i++) {
2461
+ result.push([]);
2462
+ for(var j = 0; j < dimension; j++) {
2463
+ result[i].push(null);
2464
+ }
2465
+ }
2466
+ return result;
2467
+ } else {
2468
+ return undefined;
2469
+ }
2470
+ },
2471
+ identity: function(dimension) {
2472
+ if(Number.isInteger(dimension) && dimension > 0) {
2473
+ var result = Chalkboard.matr.new();
2474
+ for(var i = 0; i < dimension; i++) {
2475
+ result.push(Array(dimension).fill(0));
2476
+ result[i][i] = 1;
2477
+ }
2478
+ return result;
2479
+ } else {
2480
+ return undefined;
2481
+ }
2482
+ },
2483
+ random: function(dimension, inf, sup) {
2484
+ if(Number.isInteger(dimension) && dimension > 0) {
2485
+ inf = inf || 0;
2486
+ sup = sup || 1;
2487
+ var result = Chalkboard.matr.new();
2488
+ for(var i = 0; i < dimension; i++) {
2489
+ result.push([]);
2490
+ for(var j = 0; j < dimension; j++) {
2491
+ result[i].push(Chalkboard.numb.random(inf, sup));
2492
+ }
2493
+ }
2494
+ return result;
2495
+ } else {
2496
+ return undefined;
2497
+ }
2498
+ },
2499
+ cofactor: function(matr, row, col) {
2500
+ return matr.slice(0, row - 1).concat(matr.slice(row)).map(function (row) {
2501
+ return row.slice(0, col - 1).concat(row.slice(col));
2502
+ });
2503
+ },
2504
+ adjugate: function(matr, row, col) {
2505
+ return Chalkboard.matr.transpose(Chalkboard.matr.cofactor(matr, row, col));
2506
+ },
2507
+ det: function(matr) {
2508
+ if(Chalkboard.matr.rows(matr) === Chalkboard.matr.cols(matr)) {
2509
+ var result = 0;
2510
+ if(Chalkboard.matr.rows(matr) === 1) {
2511
+ return matr[0][0];
2512
+ } else if(Chalkboard.matr.rows(matr) === 2) {
2513
+ return (matr[0][0] * matr[1][1]) - (matr[0][1] * matr[1][0]);
2514
+ } else {
2515
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2516
+ var cofactor = matr[0][i] * Chalkboard.matr.det(Chalkboard.matr.cofactor(matr, 1, i + 1));
2517
+ result += i % 2 === 0 ? cofactor : -cofactor;
2518
+ }
2519
+ return result;
2520
+ }
2521
+ } else {
2522
+ return undefined;
2523
+ }
2524
+ },
2525
+ trace: function(matr) {
2526
+ if(Chalkboard.matr.rows(matr) === Chalkboard.matr.cols(matr)) {
2527
+ var result = 0;
2528
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2529
+ result += matr[i][i];
2530
+ }
2531
+ return result;
2532
+ } else {
2533
+ return undefined;
2534
+ }
2535
+ },
2536
+ rank: function(matr) {
2537
+ return Chalkboard.matr.reduce(matr).filter(function (row) {
2538
+ return row.some(function (element) {
2539
+ return element !== 0;
2540
+ });
2541
+ }).length;
2542
+ },
2543
+ rowspace: function(matr) {
2544
+ return Chalkboard.matr.reduce(matr).filter(function (row) {
2545
+ return row.some(function (element) {
2546
+ return element !== 0;
2547
+ });
2548
+ });
2549
+ },
2550
+ colspace: function(matr) {
2551
+ return Chalkboard.matr.transpose(Chalkboard.matr.rowspace(Chalkboard.matr.transpose(matr)));
2552
+ },
2553
+ nullspace: function(matr) {
2554
+ var augmented = matr.map(function (row) {
2555
+ return row.slice().concat(Array(Chalkboard.matr.rows(matr)).fill(0));
2556
+ });
2557
+ var reduced = Chalkboard.matr.reduce(augmented);
2558
+ return reduced.filter(function (row) {
2559
+ return row.slice(0, Chalkboard.matr.rows(matr)).every(function (element) {
2560
+ return element === 0;
2561
+ });
2562
+ }).map(function (row) {
2563
+ return row.slice(Chalkboard.matr.rows(matr));
2564
+ });
2565
+ },
2566
+ transpose: function(matr) {
2567
+ var result = Chalkboard.matr.new();
2568
+ for(var i = 0; i < Chalkboard.matr.cols(matr); i++) {
2569
+ result[i] = [];
2570
+ for(var j = 0; j < Chalkboard.matr.rows(matr); j++) {
2571
+ result[i][j] = matr[j][i];
2572
+ }
2573
+ }
2574
+ return result;
2575
+ },
2576
+ invert: function(matr) {
2577
+ if(Chalkboard.matr.rows(matr) === Chalkboard.matr.cols(matr)) {
2578
+ var result = Chalkboard.matr.new();
2579
+ var augmented = Chalkboard.matr.new();
2580
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2581
+ augmented.push(matr[i].concat(Array(Chalkboard.matr.rows(matr)).fill(0)));
2582
+ augmented[i][Chalkboard.matr.cols(matr) + i] = 1;
2583
+ }
2584
+ for(var row = 0; row < Chalkboard.matr.rows(matr); row++) {
2585
+ var diagonal = augmented[row][row];
2586
+ if(diagonal === 0) {
2587
+ var max = row;
2588
+ for(var i = row + 1; i < Chalkboard.matr.rows(matr); i++) {
2589
+ if(Math.abs(augmented[i][row]) > Math.abs(augmented[max][row])) {
2590
+ max = i;
2591
+ }
2592
+ }
2593
+ var temp = augmented[row];
2594
+ augmented[row] = augmented[max];
2595
+ augmented[max] = temp;
2596
+ diagonal = augmented[row][row];
2597
+ }
2598
+ for(var col = 0; col < 2 * Chalkboard.matr.cols(matr); col++) {
2599
+ augmented[row][col] /= diagonal;
2600
+ }
2601
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2602
+ if(i !== row) {
2603
+ var coeff = augmented[i][row];
2604
+ for(var j = 0; j < 2 * Chalkboard.matr.cols(matr); j++) {
2605
+ augmented[i][j] -= coeff * augmented[row][j];
2606
+ }
2607
+ }
2608
+ }
2609
+ }
2610
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2611
+ result.push(augmented[i].slice(Chalkboard.matr.cols(matr), 2 * Chalkboard.matr.cols(matr)));
2612
+ }
2613
+ return result;
2614
+ } else {
2615
+ return undefined;
2616
+ }
2617
+ },
2618
+ zero: function(matr) {
2619
+ var result = Chalkboard.matr.new();
2620
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2621
+ result[i] = [];
2622
+ for(var j = 0; j < Chalkboard.matr.cols(matr); j++) {
2623
+ result[i][j] = 0;
2624
+ }
2625
+ }
2626
+ return result;
2627
+ },
2628
+ negate: function(matr) {
2629
+ var result = Chalkboard.matr.new();
2630
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2631
+ result[i] = [];
2632
+ for(var j = 0; j < Chalkboard.matr.cols(matr); j++) {
2633
+ result[i][j] = -matr[i][j];
2634
+ }
2635
+ }
2636
+ return result;
2637
+ },
2638
+ reciprocate: function(matr) {
2639
+ var result = Chalkboard.matr.new();
2640
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2641
+ result[i] = [];
2642
+ for(var j = 0; j < Chalkboard.matr.cols(matr); j++) {
2643
+ result[i][j] = 1 / matr[i][j];
2644
+ }
2645
+ }
2646
+ return result;
2647
+ },
2648
+ absolute: function(matr) {
2649
+ var result = Chalkboard.matr.new();
2650
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2651
+ result[i] = [];
2652
+ for(var j = 0; j < Chalkboard.matr.cols(matr); j++) {
2653
+ result[i][j] = Math.abs(matr[i][j]);
2654
+ }
2655
+ }
2656
+ return result;
2657
+ },
2658
+ round: function(matr) {
2659
+ var result = Chalkboard.matr.new();
2660
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2661
+ result[i] = [];
2662
+ for(var j = 0; j < Chalkboard.matr.cols(matr); j++) {
2663
+ result[i][j] = Math.round(matr[i][j]);
2664
+ }
2665
+ }
2666
+ return result;
2667
+ },
2668
+ scaler: function(vec) {
2669
+ if(vec.type === "vec2") {
2670
+ return Chalkboard.matr.new([vec.x, 0], [0, vec.y]);
2671
+ } else if(vec.type === "vec3") {
2672
+ return Chalkboard.matr.new([vec.x, 0, 0], [0, vec.y, 0], [0, 0, vec.z]);
2673
+ } else if(vec.type === "vec4") {
2674
+ return Chalkboard.matr.new([vec.x, 0, 0, 0], [0, vec.y, 0, 0], [0, 0, vec.z, 0], [0, 0, 0, vec.w]);
2675
+ }
2676
+ },
2677
+ translator: function(vec) {
2678
+ if(vec.type === "vec2") {
2679
+ return Chalkboard.matr.new([1, 0, vec.x], [0, 1, vec.y], [0, 0, 1]);
2680
+ } else if(vec.type === "vec3") {
2681
+ return Chalkboard.matr.new([1, 0, 0, vec.x], [0, 1, 0, vec.y], [0, 0, 1, vec.z], [0, 0, 0, 1]);
2682
+ } else if(vec.type === "vec4") {
2683
+ return Chalkboard.matr.new([1, 0, 0, 0, vec.x], [0, 1, 0, 0, vec.y], [0, 0, 1, 0, vec.z], [0, 0, 0, 1, vec.w], [0, 0, 0, 0, 1]);
2684
+ } else {
2685
+ return "TypeError: Parameter \"vec\" should be \"vec2\", \"vec3\", or \"vec4\".";
2686
+ }
2687
+ },
2688
+ rotator: function(radx, rady, radz) {
2689
+ if(rady === undefined && radz === undefined) {
2690
+ return Chalkboard.matr.new([Chalkboard.trig.cos(radx), -Chalkboard.trig.sin(radx)], [Chalkboard.trig.sin(radx), Chalkboard.trig.cos(radx)]);
2691
+ } else {
2692
+ var matr_x = Chalkboard.matr.new([1, 0, 0], [0, Chalkboard.trig.cos(radx), -Chalkboard.trig.sin(radx)], [0, Chalkboard.trig.sin(radx), Chalkboard.trig.cos(radx)]),
2693
+ matr_y = Chalkboard.matr.new([Chalkboard.trig.cos(rady), 0, Chalkboard.trig.sin(rady)], [0, 1, 0], [-Chalkboard.trig.sin(rady), 0, Chalkboard.trig.cos(rady)]),
2694
+ matr_z = Chalkboard.matr.new([Chalkboard.trig.cos(radz), -Chalkboard.trig.sin(radz), 0], [Chalkboard.trig.sin(radz), Chalkboard.trig.cos(radz), 0], [0, 0, 1]);
2695
+ return Chalkboard.matr.mul(matr_x, Chalkboard.matr.mul(matr_y, matr_z));
2696
+ }
2697
+ },
2698
+ scl: function(matr, num) {
2699
+ var result = Chalkboard.matr.new();
2700
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2701
+ result[i] = [];
2702
+ for(var j = 0; j < Chalkboard.matr.cols(matr); j++) {
2703
+ result[i][j] = matr[i][j] * num;
2704
+ }
2705
+ }
2706
+ return result;
2707
+ },
2708
+ constrain: function(matr, range) {
2709
+ var result = Chalkboard.matr.new();
2710
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2711
+ result[i] = [];
2712
+ for(var j = 0; j < Chalkboard.matr.cols(matr); j++) {
2713
+ result[i][j] = Chalkboard.numb.constrain(matr[i][j], range);
2714
+ }
2715
+ }
2716
+ return result;
2717
+ },
2718
+ add: function(matr_1, matr_2) {
2719
+ if(Chalkboard.matr.rows(matr_1) === Chalkboard.matr.rows(matr_2) && Chalkboard.matr.cols(matr_1) === Chalkboard.matr.cols(matr_2)) {
2720
+ var result = Chalkboard.matr.new();
2721
+ for(var i = 0; i < Chalkboard.matr.rows(matr_1); i++) {
2722
+ result[i] = [];
2723
+ for(var j = 0; j < Chalkboard.matr.cols(matr_1); j++) {
2724
+ result[i][j] = matr_1[i][j] + matr_2[i][j];
2725
+ }
2726
+ }
2727
+ return result;
2728
+ } else {
2729
+ return undefined;
2730
+ }
2731
+ },
2732
+ sub: function(matr_1, matr_2) {
2733
+ if(Chalkboard.matr.rows(matr_1) === Chalkboard.matr.rows(matr_2) && Chalkboard.matr.cols(matr_1) === Chalkboard.matr.cols(matr_2)) {
2734
+ var result = Chalkboard.matr.new();
2735
+ for(var i = 0; i < Chalkboard.matr.rows(matr_1); i++) {
2736
+ result[i] = [];
2737
+ for(var j = 0; j < Chalkboard.matr.cols(matr_1); j++) {
2738
+ result[i][j] = matr_1[i][j] - matr_2[i][j];
2739
+ }
2740
+ }
2741
+ return result;
2742
+ } else {
2743
+ return undefined;
2744
+ }
2745
+ },
2746
+ mul: function(matr_1, matr_2) {
2747
+ if(Chalkboard.matr.cols(matr_1) === Chalkboard.matr.rows(matr_2)) {
2748
+ var result = Chalkboard.matr.new();
2749
+ for(var i = 0; i < Chalkboard.matr.rows(matr_1); i++) {
2750
+ result[i] = [];
2751
+ for(var j = 0; j < Chalkboard.matr.cols(matr_2); j++) {
2752
+ result[i][j] = 0;
2753
+ for(var k = 0; k < Chalkboard.matr.cols(matr_1); k++) {
2754
+ result[i][j] += matr_1[i][k] * matr_2[k][j];
2755
+ }
2756
+ }
2757
+ }
2758
+ return result;
2759
+ } else {
2760
+ return undefined;
2761
+ }
2762
+ },
2763
+ pow: function(matr, num) {
2764
+ if(Chalkboard.matr.rows(matr) === Chalkboard.matr.cols(matr)) {
2765
+ if(Number.isInteger(num) && num >= 0) {
2766
+ if(num === 0) {
2767
+ return Chalkboard.matr.identity(Chalkboard.matr.rows(matr));
2768
+ } else {
2769
+ var result = matr;
2770
+ for(var i = 1; i < num; i++) {
2771
+ result = Chalkboard.matr.mul(matr, result);
2772
+ }
2773
+ return result;
2774
+ }
2775
+ } else {
2776
+ return undefined;
2777
+ }
2778
+ } else {
2779
+ return undefined;
2780
+ }
2781
+ },
2782
+ reduce: function(matr) {
2783
+ var lead = 0;
2784
+ for(var row = 0; row < Chalkboard.matr.rows(matr); row++) {
2785
+ if(lead >= Chalkboard.matr.cols(matr)) {
2786
+ break;
2787
+ }
2788
+ var i = row;
2789
+ while(matr[i][lead] === 0) {
2790
+ i++;
2791
+ if(i === Chalkboard.matr.rows(matr)) {
2792
+ i = row;
2793
+ lead++;
2794
+ if(Chalkboard.matr.cols(matr) === lead) {
2795
+ return matr;
2796
+ }
2797
+ }
2798
+ }
2799
+ var temp = matr[i];
2800
+ matr[i] = matr[row];
2801
+ matr[row] = temp;
2802
+ var scl = matr[row][lead];
2803
+ for(var j = 0; j < Chalkboard.matr.cols(matr); j++) {
2804
+ matr[row][j] /= scl;
2805
+ }
2806
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2807
+ if(i !== row) {
2808
+ var coeff = matr[i][lead];
2809
+ for(var j = 0; j < Chalkboard.matr.cols(matr); j++) {
2810
+ matr[i][j] -= coeff * matr[row][j];
2811
+ }
2812
+ }
2813
+ }
2814
+ lead++;
2815
+ }
2816
+ return matr;
2817
+ },
2818
+ solve: function(matr_A, matr_B) {
2819
+ if(Chalkboard.matr.rows(matr_A) === Chalkboard.matr.cols(matr_A)) {
2820
+ if(Chalkboard.matr.rows(matr_A) === Chalkboard.matr.rows(matr_B)) {
2821
+ if(Chalkboard.matr.det(matr_A) !== 0) {
2822
+ return Chalkboard.matr.mul(Chalkboard.matr.invert(matr_A), matr_B);
2823
+ } else {
2824
+ return undefined;
2825
+ }
2826
+ } else {
2827
+ return undefined;
2828
+ }
2829
+ } else {
2830
+ return undefined;
2831
+ }
2832
+ },
2833
+ toVector: function(matr, vec, type, rowORcol) {
2834
+ type = type || "col";
2835
+ rowORcol = rowORcol || 1;
2836
+ rowORcol -= 1;
2837
+ if(vec === "vec2") {
2838
+ if(type === "col") {
2839
+ return Chalkboard.vec2.new(matr[0][rowORcol], matr[1][rowORcol]);
2840
+ } else if(type === "row") {
2841
+ return Chalkboard.vec2.new(matr[rowORcol][0], matr[rowORcol][1]);
2842
+ } else {
2843
+ return "TypeError: Parameter \"type\" should be \"row\" or \"col\".";
2844
+ }
2845
+ } else if(vec === "vec3") {
2846
+ if(type === "col") {
2847
+ return Chalkboard.vec3.new(matr[0][rowORcol], matr[1][rowORcol], matr[2][rowORcol]);
2848
+ } else if(type === "row") {
2849
+ return Chalkboard.vec3.new(matr[rowORcol][0], matr[rowORcol][1], matr[rowORcol][2]);
2850
+ } else {
2851
+ return "TypeError: Parameter \"type\" should be \"row\" or \"col\".";
2852
+ }
2853
+ } else if(vec === "vec4") {
2854
+ if(type === "col") {
2855
+ return Chalkboard.vec4.new(matr[0][rowORcol], matr[1][rowORcol], matr[2][rowORcol], matr[3][rowORcol]);
2856
+ } else if(type === "row") {
2857
+ return Chalkboard.vec4.new(matr[rowORcol][0], matr[rowORcol][1], matr[rowORcol][2], matr[rowORcol][3]);
2858
+ } else {
2859
+ return "TypeError: Parameter \"type\" should be \"row\" or \"col\".";
2860
+ }
2861
+ } else {
2862
+ return "TypeError: Parameter \"vec\" should be \"vec2\", \"vec3\", or \"vec4\".";
2863
+ }
2864
+ },
2865
+ toArray: function(matr) {
2866
+ var result = [];
2867
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2868
+ for(var j = 0; j < Chalkboard.matr.cols(matr); j++) {
2869
+ result.push(matr[i][j]);
2870
+ }
2871
+ }
2872
+ return result;
2873
+ },
2874
+ toString: function(matr) {
2875
+ var result = "";
2876
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2877
+ result += "[ ";
2878
+ for(var j = 0; j < Chalkboard.matr.cols(matr); j++) {
2879
+ result += matr[i][j].toString() + " ";
2880
+ }
2881
+ result = result.trimEnd() + " ]\n";
2882
+ }
2883
+ return result;
2884
+ },
2885
+ toObject: function(matr) {
2886
+ var result = {};
2887
+ for(var i = 0; i < Chalkboard.matr.rows(matr); i++) {
2888
+ result["i" + (i + 1)] = {};
2889
+ for(var j = 0; j < Chalkboard.matr.cols(matr); j++) {
2890
+ result["i" + (i + 1)]["j" + (j + 1)] = matr[i][j];
2891
+ }
2892
+ }
2893
+ return result;
2894
+ },
2895
+ print: function(matr) {
2896
+ console.log(Chalkboard.matr.toString(matr));
2897
+ }
2898
+ },
2899
+ calc: {
2900
+ lim: function(func, val) {
2901
+ if(func.type === "expl") {
2902
+ if(val === Infinity) {
2903
+ if(Chalkboard.real.val(func, 101) > Chalkboard.real.val(func, 100)) {
2904
+ return Infinity;
2905
+ } else if(Chalkboard.real.val(func, 101) < Chalkboard.real.val(func, 100)) {
2906
+ return -Infinity;
2907
+ }
2908
+ } else if(val === -Infinity) {
2909
+ if(Chalkboard.real.val(func, -101) > Chalkboard.real.val(func, -100)) {
2910
+ return Infinity;
2911
+ } else if(Chalkboard.real.val(func, -101) < Chalkboard.real.val(func, -100)) {
2912
+ return -Infinity;
2913
+ }
2914
+ } else {
2915
+ if(Chalkboard.real.val(func, val - 0.000001).toFixed(4) === Chalkboard.real.val(func, val + 0.000001).toFixed(4)) {
2916
+ if(Chalkboard.real.val(func, val) !== Infinity || Chalkboard.real.val(func, val) !== -Infinity) {
2917
+ return Chalkboard.real.val(func, val);
2918
+ } else {
2919
+ return undefined;
2920
+ }
2921
+ } else {
2922
+ return undefined;
2923
+ }
2924
+ }
2925
+ } else {
2926
+ return "TypeError: Parameter \"func\" must be of type \"expl\".";
2927
+ }
2928
+ },
2929
+ dfdx: function(func, val) {
2930
+ var h = 0.000000001;
2931
+ if(func.type === "expl") {
2932
+ var f = Chalkboard.real.parse("x => " + func.definition);
2933
+ return (f(val + h) - f(val)) / h;
2934
+ } else if(func.type === "pola") {
2935
+ var r = Chalkboard.real.parse("O => " + func.definition);
2936
+ return (r(val + h) - r(val)) / h;
2937
+ } else if(func.type === "curv") {
2938
+ if(func.definition.length === 2) {
2939
+ var x = Chalkboard.real.parse("t => " + func.definition[0]),
2940
+ y = Chalkboard.real.parse("t => " + func.definition[1]);
2941
+ return Chalkboard.vec2.new((x(val + h) - x(val)) / h, (y(val + h) - y(val)) / h);
2942
+ } else if(func.definition.length === 3) {
2943
+ var x = Chalkboard.real.parse("t => " + func.definition[0]),
2944
+ y = Chalkboard.real.parse("t => " + func.definition[1]),
2945
+ z = Chalkboard.real.parse("t => " + func.definition[2]);
2946
+ return Chalkboard.vec3.new((x(val + h) - x(val)) / h, (y(val + h) - y(val)) / h, (z(val + h) - z(val)) / h);
2947
+ }
2948
+ } else {
2949
+ return "TypeError: Parameter \"func\" must be of type \"expl\", \"pola\", or \"curv\".";
2950
+ }
2951
+ },
2952
+ d2fdx2: function(func, val) {
2953
+ var h = 0.00001;
2954
+ if(func.type === "expl") {
2955
+ var f = Chalkboard.real.parse("x => " + func.definition);
2956
+ return (f(val + h) - 2 * f(val) + f(val - h)) / (h * h);
2957
+ } else if(func.type === "pola") {
2958
+ var r = Chalkboard.real.parse("O => " + func.definition);
2959
+ return (r(val + h) - 2 * r(val) + r(val - h)) / (h * h);
2960
+ } else if(func.type === "curv") {
2961
+ if(func.definition.length === 2) {
2962
+ var x = Chalkboard.real.parse("t => " + func.definition[0]),
2963
+ y = Chalkboard.real.parse("t => " + func.definition[1]);
2964
+ return Chalkboard.vec2.new((x(val + h) - 2 * x(val) + x(val - h)) / (h * h), (y(val + h) - 2 * y(val) + y(val - h)) / (h * h));
2965
+ } else if(func.definition.length === 3) {
2966
+ var x = Chalkboard.real.parse("t => " + func.definition[0]),
2967
+ y = Chalkboard.real.parse("t => " + func.definition[1]),
2968
+ z = Chalkboard.real.parse("t => " + func.definition[2]);
2969
+ return Chalkboard.vec3.new((x(val + h) - 2 * x(val) + x(val - h)) / (h * h), (y(val + h) - 2 * y(val) + y(val - h)) / (h * h), (z(val + h) - 2 * z(val) + z(val - h)) / (h * h));
2970
+ }
2971
+ } else {
2972
+ return "TypeError: Parameter \"func\" must be of type \"expl\", \"pola\", or \"curv\".";
2973
+ }
2974
+ },
2975
+ tangent: function(func, val) {
2976
+ if(func.type === "curv") {
2977
+ if(func.definition.length === 2) {
2978
+ return Chalkboard.vec2.normalize(Chalkboard.calc.dfdx(func, val));
2979
+ } else if(func.definition.length === 3) {
2980
+ return Chalkboard.vec3.normalize(Chalkboard.calc.dfdx(func, val));
2981
+ }
2982
+ } else {
2983
+ return "TypeError: Parameter \"func\" must be of type \"curv\".";
2984
+ }
2985
+ },
2986
+ normal: function(func, val) {
2987
+ if(func.type === "curv") {
2988
+ if(func.definition.length === 2) {
2989
+ return Chalkboard.vec2.normalize(Chalkboard.calc.d2fdx2(func, val));
2990
+ } else if(func.definition.length === 3) {
2991
+ return Chalkboard.vec3.normalize(Chalkboard.calc.d2fdx2(func, val));
2992
+ }
2993
+ } else {
2994
+ return "TypeError: Parameter \"func\" must be of type \"curv\".";
2995
+ }
2996
+ },
2997
+ binormal: function(func, val) {
2998
+ if(func.type === "curv") {
2999
+ if(func.definition.length === 2) {
3000
+ return Chalkboard.vec2.cross(Chalkboard.calc.tangent(func, val), Chalkboard.calc.normal(func, val));
3001
+ } else if(func.definition.length === 3) {
3002
+ return Chalkboard.vec3.cross(Chalkboard.calc.tangent(func, val), Chalkboard.calc.normal(func, val));
3003
+ }
3004
+ } else {
3005
+ return "TypeError: Parameter \"func\" must be of type \"curv\".";
3006
+ }
3007
+ },
3008
+ dfdv: function(func, vec2_pos, vec2_dir) {
3009
+ if(func.type === "mult") {
3010
+ return Chalkboard.vec2.dot(Chalkboard.calc.grad(func, vec2_pos), Chalkboard.vec2.normalize(vec2_dir));
3011
+ } else {
3012
+ return "TypeError: Parameter \"func\" must be of type \"mult\".";
3013
+ }
3014
+ },
3015
+ dfrdt: function(func_1, func_2, val) {
3016
+ if(func_1.type === "mult") {
3017
+ if(func_2.type === "curv") {
3018
+ if(func_2.definition.length === 2) {
3019
+ var dfdx = Chalkboard.calc.grad(func_1, Chalkboard.real.val(func_2, val)).x,
3020
+ dfdy = Chalkboard.calc.grad(func_1, Chalkboard.real.val(func_2, val)).y,
3021
+ dxdt = Chalkboard.calc.dfdx(func_2, val).x,
3022
+ dydt = Chalkboard.calc.dfdx(func_2, val).y;
3023
+ return dfdx * dxdt + dfdy * dydt;
3024
+ }
3025
+ } else {
3026
+ return "TypeError: Parameter \"func_2\" must be of type \"curv\".";
3027
+ }
3028
+ } else {
3029
+ return "TypeError: Parameter \"func_1\" must be of type \"mult\".";
3030
+ }
3031
+ },
3032
+ grad: function(funcORvecfield, vec) {
3033
+ var h = 0.000000001;
3034
+ if(funcORvecfield.type === "surf") {
3035
+ var x = Chalkboard.real.parse("(s, t) => " + funcORvecfield.definition[0]),
3036
+ y = Chalkboard.real.parse("(s, t) => " + funcORvecfield.definition[1]),
3037
+ z = Chalkboard.real.parse("(s, t) => " + funcORvecfield.definition[2]);
3038
+ var dxds = (x(vec.x + h, vec.y) - x(vec.x, vec.y)) / h,
3039
+ dxdt = (x(vec.x, vec.y + h) - x(vec.x, vec.y)) / h,
3040
+ dyds = (y(vec.x + h, vec.y) - y(vec.x, vec.y)) / h,
3041
+ dydt = (y(vec.x, vec.y + h) - y(vec.x, vec.y)) / h,
3042
+ dzds = (z(vec.x + h, vec.y) - z(vec.x, vec.y)) / h,
3043
+ dzdt = (z(vec.x, vec.y + h) - z(vec.x, vec.y)) / h;
3044
+ return Chalkboard.matr.new([dxds, dxdt],
3045
+ [dyds, dydt],
3046
+ [dzds, dzdt]);
3047
+ } else if(funcORvecfield.type === "mult") {
3048
+ var f = Chalkboard.real.parse("(x, y) => " + funcORvecfield.definition);
3049
+ var dfdx = (f(vec.x + h, vec.y) - f(vec.x, vec.y)) / h,
3050
+ dfdy = (f(vec.x, vec.y + h) - f(vec.x, vec.y)) / h;
3051
+ return Chalkboard.vec2.new(dfdx, dfdy);
3052
+ } else if(funcORvecfield.type === "vec2field") {
3053
+ var p = Chalkboard.real.parse("(x, y) => " + funcORvecfield.p),
3054
+ q = Chalkboard.real.parse("(x, y) => " + funcORvecfield.q);
3055
+ var dpdx = (p(vec.x + h, vec.y) - p(vec.x, vec.y)) / h,
3056
+ dpdy = (p(vec.x, vec.y + h) - p(vec.x, vec.y)) / h,
3057
+ dqdx = (q(vec.x + h, vec.y) - q(vec.x, vec.y)) / h,
3058
+ dqdy = (q(vec.x, vec.y + h) - q(vec.x, vec.y)) / h;
3059
+ return Chalkboard.matr.new([dpdx, dpdy],
3060
+ [dqdx, dqdy]);
3061
+ } else if(funcORvecfield.type === "vec3field") {
3062
+ var p = Chalkboard.real.parse("(x, y, z) => " + funcORvecfield.p),
3063
+ q = Chalkboard.real.parse("(x, y, z) => " + funcORvecfield.q),
3064
+ r = Chalkboard.real.parse("(x, y, z) => " + funcORvecfield.r);
3065
+ var dpdx = (p(vec.x + h, vec.y, vec.z) - p(vec.x, vec.y, vec.z)) / h,
3066
+ dpdy = (p(vec.x, vec.y + h, vec.z) - p(vec.x, vec.y, vec.z)) / h,
3067
+ dpdz = (p(vec.x, vec.y, vec.z + h) - p(vec.x, vec.y, vec.z)) / h,
3068
+ dqdx = (q(vec.x + h, vec.y, vec.z) - q(vec.x, vec.y, vec.z)) / h,
3069
+ dqdy = (q(vec.x, vec.y + h, vec.z) - q(vec.x, vec.y, vec.z)) / h,
3070
+ dqdz = (q(vec.x, vec.y, vec.z + h) - q(vec.x, vec.y, vec.z)) / h,
3071
+ drdx = (r(vec.x + h, vec.y, vec.z) - r(vec.x, vec.y, vec.z)) / h,
3072
+ drdy = (r(vec.x, vec.y + h, vec.z) - r(vec.x, vec.y, vec.z)) / h,
3073
+ drdz = (r(vec.x, vec.y, vec.z + h) - r(vec.x, vec.y, vec.z)) / h;
3074
+ return Chalkboard.matr.new([dpdx, dpdy, dpdz],
3075
+ [dqdx, dqdy, dqdz],
3076
+ [drdx, drdy, drdz]);
3077
+ } else if(funcORvecfield.type === "vec4field") {
3078
+ var p = Chalkboard.real.parse("(x, y, z, w) => " + funcORvecfield.p),
3079
+ q = Chalkboard.real.parse("(x, y, z, w) => " + funcORvecfield.q),
3080
+ r = Chalkboard.real.parse("(x, y, z, w) => " + funcORvecfield.r),
3081
+ s = Chalkboard.real.parse("(x, y, z, w) => " + funcORvecfield.s);
3082
+ var dpdx = (p(vec.x + h, vec.y, vec.z, vec.w) - p(vec.x, vec.y, vec.z, vec.w)) / h,
3083
+ dpdy = (p(vec.x, vec.y + h, vec.z, vec.w) - p(vec.x, vec.y, vec.z, vec.w)) / h,
3084
+ dpdz = (p(vec.x, vec.y, vec.z + h, vec.w) - p(vec.x, vec.y, vec.z, vec.w)) / h,
3085
+ dpdw = (p(vec.x, vec.y, vec.z, vec.w + h) - p(vec.x, vec.y, vec.z, vec.w)) / h,
3086
+ dqdx = (q(vec.x + h, vec.y, vec.z, vec.w) - q(vec.x, vec.y, vec.z, vec.w)) / h,
3087
+ dqdy = (q(vec.x, vec.y + h, vec.z, vec.w) - q(vec.x, vec.y, vec.z, vec.w)) / h,
3088
+ dqdz = (q(vec.x, vec.y, vec.z + h, vec.w) - q(vec.x, vec.y, vec.z, vec.w)) / h,
3089
+ dqdw = (q(vec.x, vec.y, vec.z, vec.w + h) - q(vec.x, vec.y, vec.z, vec.w)) / h,
3090
+ drdx = (r(vec.x + h, vec.y, vec.z, vec.w) - r(vec.x, vec.y, vec.z, vec.w)) / h,
3091
+ drdy = (r(vec.x, vec.y + h, vec.z, vec.w) - r(vec.x, vec.y, vec.z, vec.w)) / h,
3092
+ drdz = (r(vec.x, vec.y, vec.z + h, vec.w) - r(vec.x, vec.y, vec.z, vec.w)) / h,
3093
+ drdw = (r(vec.x, vec.y, vec.z, vec.w + h) - r(vec.x, vec.y, vec.z, vec.w)) / h,
3094
+ dsdx = (s(vec.x + h, vec.y, vec.z, vec.w) - s(vec.x, vec.y, vec.z, vec.w)) / h,
3095
+ dsdy = (s(vec.x, vec.y + h, vec.z, vec.w) - s(vec.x, vec.y, vec.z, vec.w)) / h,
3096
+ dsdz = (s(vec.x, vec.y, vec.z + h, vec.w) - s(vec.x, vec.y, vec.z, vec.w)) / h,
3097
+ dsdw = (s(vec.x, vec.y, vec.z, vec.w + h) - s(vec.x, vec.y, vec.z, vec.w)) / h;
3098
+ return Chalkboard.matr.new([dpdx, dpdy, dpdz, dpdw],
3099
+ [dqdx, dqdy, dqdz, dqdw],
3100
+ [drdx, drdy, drdz, drdw],
3101
+ [dsdx, dsdy, dsdz, dsdw]);
3102
+ } else {
3103
+ return "TypeError: Parameter \"funcORvecfield\" must be of type \"surf\", \"mult\", \"vec2field\", \"vec3field\", or \"vec4field\".";
3104
+ }
3105
+ },
3106
+ grad2: function(funcORvecfield, vec) {
3107
+ var h = 0.00001;
3108
+ if(funcORvecfield.type === "surf") {
3109
+ var x = Chalkboard.real.parse("(s, t) => " + funcORvecfield.definition[0]),
3110
+ y = Chalkboard.real.parse("(s, t) => " + funcORvecfield.definition[1]),
3111
+ z = Chalkboard.real.parse("(s, t) => " + funcORvecfield.definition[2]);
3112
+ var d2xds2 = (x(vec.x + h, vec.y) - 2 * x(vec.x, vec.y) + x(vec.x - h, vec.y)) / (h * h),
3113
+ d2xdt2 = (x(vec.x, vec.y + h) - 2 * x(vec.x, vec.y) + x(vec.x, vec.y - h)) / (h * h),
3114
+ d2yds2 = (y(vec.x + h, vec.y) - 2 * y(vec.x, vec.y) + y(vec.x - h, vec.y)) / (h * h),
3115
+ d2ydt2 = (y(vec.x, vec.y + h) - 2 * y(vec.x, vec.y) + y(vec.x, vec.y - h)) / (h * h),
3116
+ d2zds2 = (z(vec.x + h, vec.y) - 2 * z(vec.x, vec.y) + z(vec.x - h, vec.y)) / (h * h),
3117
+ d2zdt2 = (z(vec.x, vec.y + h) - 2 * z(vec.x, vec.y) + z(vec.x, vec.y - h)) / (h * h);
3118
+ return Chalkboard.matr.new([d2xds2, d2xdt2],
3119
+ [d2yds2, d2ydt2],
3120
+ [d2zds2, d2zdt2]);
3121
+ } else if(funcORvecfield.type === "mult") {
3122
+ var f = Chalkboard.real.parse("(x, y) => " + funcORvecfield.definition);
3123
+ var d2fdx2 = (f(vec.x + h, vec.y) - 2 * f(vec.x, vec.y) + f(vec.x - h, vec.y)) / (h * h),
3124
+ d2fdy2 = (f(vec.x, vec.y + h) - 2 * f(vec.x, vec.y) + f(vec.x, vec.y - h)) / (h * h),
3125
+ d2fdxdy = (f(vec.x + h, vec.y + h) - f(vec.x + h, vec.y) - f(vec.x, vec.y + h) + f(vec.x, vec.y)) / (h * h),
3126
+ d2fdydx = (f(vec.x + h, vec.y + h) - f(vec.x, vec.y + h) - f(vec.x + h, vec.y) + f(vec.x, vec.y)) / (h * h);
3127
+ return Chalkboard.matr.new([d2fdx2, d2fdxdy],
3128
+ [d2fdydx, d2fdy2]);
3129
+ } else if(funcORvecfield.type === "vec2field") {
3130
+ var p = Chalkboard.real.parse("(x, y) => " + funcORvecfield.p),
3131
+ q = Chalkboard.real.parse("(x, y) => " + funcORvecfield.q);
3132
+ var d2pdx2 = (p(vec.x + h, vec.y) - 2 * p(vec.x, vec.y) + p(vec.x - h, vec.y)) / (h * h),
3133
+ d2pdy2 = (p(vec.x, vec.y + h) - 2 * p(vec.x, vec.y) + p(vec.x, vec.y - h)) / (h * h),
3134
+ d2qdx2 = (q(vec.x + h, vec.y) - 2 * q(vec.x, vec.y) + q(vec.x - h, vec.y)) / (h * h),
3135
+ d2qdy2 = (q(vec.x, vec.y + h) - 2 * q(vec.x, vec.y) + q(vec.x, vec.y - h)) / (h * h);
3136
+ return Chalkboard.matr.new([d2pdx2, d2pdy2],
3137
+ [d2qdx2, d2qdy2]);
3138
+ } else if(funcORvecfield.type === "vec3field") {
3139
+ var p = Chalkboard.real.parse("(x, y, z) => " + funcORvecfield.p),
3140
+ q = Chalkboard.real.parse("(x, y, z) => " + funcORvecfield.q),
3141
+ r = Chalkboard.real.parse("(x, y, z) => " + funcORvecfield.r);
3142
+ var d2pdx2 = (p(vec.x + h, vec.y, vec.z) - 2 * p(vec.x, vec.y, vec.z) + p(vec.x - h, vec.y, vec.z)) / (h * h),
3143
+ d2pdy2 = (p(vec.x, vec.y + h, vec.z) - 2 * p(vec.x, vec.y, vec.z) + p(vec.x, vec.y - h, vec.z)) / (h * h),
3144
+ d2pdz2 = (p(vec.x, vec.y, vec.z + h) - 2 * p(vec.x, vec.y, vec.z) + p(vec.x, vec.y, vec.z - h)) / (h * h),
3145
+ d2qdx2 = (q(vec.x + h, vec.y, vec.z) - 2 * q(vec.x, vec.y, vec.z) + q(vec.x - h, vec.y, vec.z)) / (h * h),
3146
+ d2qdy2 = (q(vec.x, vec.y + h, vec.z) - 2 * q(vec.x, vec.y, vec.z) + q(vec.x, vec.y - h, vec.z)) / (h * h),
3147
+ d2qdz2 = (q(vec.x, vec.y, vec.z + h) - 2 * q(vec.x, vec.y, vec.z) + q(vec.x, vec.y, vec.z - h)) / (h * h),
3148
+ d2rdx2 = (r(vec.x + h, vec.y, vec.z) - 2 * r(vec.x, vec.y, vec.z) + r(vec.x - h, vec.y, vec.z)) / (h * h),
3149
+ d2rdy2 = (r(vec.x, vec.y + h, vec.z) - 2 * r(vec.x, vec.y, vec.z) + r(vec.x, vec.y - h, vec.z)) / (h * h),
3150
+ d2rdz2 = (r(vec.x, vec.y, vec.z + h) - 2 * r(vec.x, vec.y, vec.z) + r(vec.x, vec.y, vec.z - h)) / (h * h);
3151
+ return Chalkboard.matr.new([d2pdx2, d2pdy2, d2pdz2],
3152
+ [d2qdx2, d2qdy2, d2qdz2],
3153
+ [d2rdx2, d2rdy2, d2rdz2]);
3154
+ } else if(funcORvecfield.type === "vec4field") {
3155
+ var p = Chalkboard.real.parse("(x, y, z, w) => " + funcORvecfield.p),
3156
+ q = Chalkboard.real.parse("(x, y, z, w) => " + funcORvecfield.q),
3157
+ r = Chalkboard.real.parse("(x, y, z, w) => " + funcORvecfield.r),
3158
+ s = Chalkboard.real.parse("(x, y, z, w) => " + funcORvecfield.s);
3159
+ var d2pdx2 = (p(vec.x + h, vec.y, vec.z, vec.w) - 2 * p(vec.x, vec.y, vec.z, vec.w) + p(vec.x - h, vec.y, vec.z, vec.w)) / (h * h),
3160
+ d2pdy2 = (p(vec.x, vec.y + h, vec.z, vec.w) - 2 * p(vec.x, vec.y, vec.z, vec.w) + p(vec.x, vec.y - h, vec.z, vec.w)) / (h * h),
3161
+ d2pdz2 = (p(vec.x, vec.y, vec.z + h, vec.w) - 2 * p(vec.x, vec.y, vec.z, vec.w) + p(vec.x, vec.y, vec.z - h, vec.w)) / (h * h),
3162
+ d2pdw2 = (p(vec.x, vec.y, vec.z, vec.w + h) - 2 * p(vec.x, vec.y, vec.z, vec.w) + p(vec.x, vec.y, vec.z, vec.w - h)) / (h * h),
3163
+ d2qdx2 = (q(vec.x + h, vec.y, vec.z, vec.w) - 2 * q(vec.x, vec.y, vec.z, vec.w) + q(vec.x - h, vec.y, vec.z, vec.w)) / (h * h),
3164
+ d2qdy2 = (q(vec.x, vec.y + h, vec.z, vec.w) - 2 * q(vec.x, vec.y, vec.z, vec.w) + q(vec.x, vec.y - h, vec.z, vec.w)) / (h * h),
3165
+ d2qdz2 = (q(vec.x, vec.y, vec.z + h, vec.w) - 2 * q(vec.x, vec.y, vec.z, vec.w) + q(vec.x, vec.y, vec.z - h, vec.w)) / (h * h),
3166
+ d2qdw2 = (q(vec.x, vec.y, vec.z, vec.w + h) - 2 * q(vec.x, vec.y, vec.z, vec.w) + q(vec.x, vec.y, vec.z, vec.w - h)) / (h * h),
3167
+ d2rdx2 = (r(vec.x + h, vec.y, vec.z, vec.w) - 2 * r(vec.x, vec.y, vec.z, vec.w) + r(vec.x - h, vec.y, vec.z, vec.w)) / (h * h),
3168
+ d2rdy2 = (r(vec.x, vec.y + h, vec.z, vec.w) - 2 * r(vec.x, vec.y, vec.z, vec.w) + r(vec.x, vec.y - h, vec.z, vec.w)) / (h * h),
3169
+ d2rdz2 = (r(vec.x, vec.y, vec.z + h, vec.w) - 2 * r(vec.x, vec.y, vec.z, vec.w) + r(vec.x, vec.y, vec.z - h, vec.w)) / (h * h),
3170
+ d2rdw2 = (r(vec.x, vec.y, vec.z, vec.w + h) - 2 * r(vec.x, vec.y, vec.z, vec.w) + r(vec.x, vec.y, vec.z, vec.w - h)) / (h * h),
3171
+ d2sdx2 = (s(vec.x + h, vec.y, vec.z, vec.w) - 2 * s(vec.x, vec.y, vec.z, vec.w) + s(vec.x - h, vec.y, vec.z, vec.w)) / (h * h),
3172
+ d2sdy2 = (s(vec.x, vec.y + h, vec.z, vec.w) - 2 * s(vec.x, vec.y, vec.z, vec.w) + s(vec.x, vec.y - h, vec.z, vec.w)) / (h * h),
3173
+ d2sdz2 = (s(vec.x, vec.y, vec.z + h, vec.w) - 2 * s(vec.x, vec.y, vec.z, vec.w) + s(vec.x, vec.y, vec.z - h, vec.w)) / (h * h),
3174
+ d2sdw2 = (s(vec.x, vec.y, vec.z, vec.w + h) - 2 * s(vec.x, vec.y, vec.z, vec.w) + s(vec.x, vec.y, vec.z, vec.w - h)) / (h * h);
3175
+ return Chalkboard.matr.new([d2pdx2, d2pdy2, d2pdz2, d2pdw2],
3176
+ [d2qdx2, d2qdy2, d2qdz2, d2qdw2],
3177
+ [d2rdx2, d2rdy2, d2rdz2, d2rdw2],
3178
+ [d2sdx2, d2sdy2, d2sdz2, d2sdw2]);
3179
+ } else {
3180
+ return "TypeError: Parameter \"funcORvecfield\" must be of type \"surf\", \"mult\", \"vec2field\", \"vec3field\", or \"vec4field\".";
3181
+ }
3182
+ },
3183
+ div: function(vecfield, vec) {
3184
+ if(vecfield.type === "vec2field" || vecfield.type === "vec3field" || vecfield.type === "vec4field") {
3185
+ return Chalkboard.matr.trace(Chalkboard.calc.grad(vecfield, vec));
3186
+ } else {
3187
+ return "TypeError: Parameter \"vecfield\" must be of type \"vec2field\", \"vec3field\", or \"vec4field\".";
3188
+ }
3189
+ },
3190
+ curl: function(vecfield, vec) {
3191
+ var h = 0.000000001;
3192
+ if(vecfield.type === "vec2field") {
3193
+ var p = Chalkboard.real.parse("(x, y) => " + vecfield.p),
3194
+ q = Chalkboard.real.parse("(x, y) => " + vecfield.q);
3195
+ var dpdy = (p(vec.x, vec.y + h) - p(vec.x, vec.y)) / h,
3196
+ dqdx = (q(vec.x + h, vec.y) - q(vec.x, vec.y)) / h;
3197
+ return Chalkboard.vec3.new(0, 0, dqdx - dpdy);
3198
+ } else if(vecfield.type === "vec3field") {
3199
+ var p = Chalkboard.real.parse("(x, y, z) => " + vecfield.p),
3200
+ q = Chalkboard.real.parse("(x, y, z) => " + vecfield.q),
3201
+ r = Chalkboard.real.parse("(x, y, z) => " + vecfield.r);
3202
+ var dpdy = (p(vec.x, vec.y + h, vec.z) - p(vec.x, vec.y, vec.z)) / h,
3203
+ dpdz = (p(vec.x, vec.y, vec.z + h) - p(vec.x, vec.y, vec.z)) / h,
3204
+ dqdx = (q(vec.x + h, vec.y, vec.z) - q(vec.x, vec.y, vec.z)) / h,
3205
+ dqdz = (q(vec.x, vec.y, vec.z + h) - q(vec.x, vec.y, vec.z)) / h,
3206
+ drdx = (r(vec.x + h, vec.y, vec.z) - r(vec.x, vec.y, vec.z)) / h,
3207
+ drdy = (r(vec.x, vec.y + h, vec.z) - r(vec.x, vec.y, vec.z)) / h;
3208
+ return Chalkboard.vec3.new(drdy - dqdz, dpdz - drdx, dqdx - dpdy);
3209
+ } else {
3210
+ return "TypeError: Parameter \"vecfield\" must be of type \"vec2field\" or \"vec3field\".";
3211
+ }
3212
+ },
3213
+ dfdz: function(func, comp) {
3214
+ var h = 0.000000001;
3215
+ if(func.type === "comp") {
3216
+ var u = Chalkboard.comp.parse("(a, b) => " + func.definition[0]),
3217
+ v = Chalkboard.comp.parse("(a, b) => " + func.definition[1]);
3218
+ var duda = (u(comp.a + h, comp.b) - u(comp.a, comp.b)) / h,
3219
+ dudb = (u(comp.a, comp.b + h) - u(comp.a, comp.b)) / h,
3220
+ dvda = (v(comp.a + h, comp.b) - v(comp.a, comp.b)) / h,
3221
+ dvdb = (v(comp.a, comp.b + h) - v(comp.a, comp.b)) / h;
3222
+ return {a: Chalkboard.comp.new(duda, dvda), b: Chalkboard.comp.new(dudb, dvdb)};
3223
+ } else {
3224
+ return "TypeError: Parameter \"func\" must be of type \"comp\".";
3225
+ }
3226
+ },
3227
+ df2dz2: function(func, comp) {
3228
+ var h = 0.00001;
3229
+ if(func.type === "comp") {
3230
+ var u = Chalkboard.comp.parse("(a, b) => " + func.definition[0]),
3231
+ v = Chalkboard.comp.parse("(a, b) => " + func.definition[1]);
3232
+ var d2uda2 = (u(comp.a + h, comp.b) - 2 * u(comp.a, comp.b) + u(comp.a - h, comp.b)) / (h * h),
3233
+ d2udb2 = (u(comp.a, comp.b + h) - 2 * u(comp.a, comp.b) + u(comp.a, comp.b - h)) / (h * h),
3234
+ d2vda2 = (v(comp.a + h, comp.b) - 2 * v(comp.a, comp.b) + v(comp.a - h, comp.b)) / (h * h),
3235
+ d2vdb2 = (v(comp.a, comp.b + h) - 2 * v(comp.a, comp.b) + v(comp.a, comp.b - h)) / (h * h);
3236
+ return {a: Chalkboard.comp.new(d2uda2, d2vda2), b: Chalkboard.comp.new(d2udb2, d2vdb2)};
3237
+ } else {
3238
+ return "TypeError: Parameter \"func\" must be of type \"comp\".";
3239
+ }
3240
+ },
3241
+ fxdx: function(func, a, b) {
3242
+ if(func.type === "expl" || func.type === "pola") {
3243
+ var f;
3244
+ if(func.type === "expl") {
3245
+ f = Chalkboard.real.parse("x => " + func.definition);
3246
+ } else if(func.type === "pola") {
3247
+ f = Chalkboard.real.parse("O => " + "((" + func.definition + ") * (" + func.definition + ")) / 2");
3248
+ }
3249
+ var fx = f(a) + f(b);
3250
+ var dx = (b - a) / 1000000;
3251
+ for(var i = 1; i < 1000000; i++) {
3252
+ fx += i % 2 === 0 ? 2 * f(a + i * dx) : 4 * f(a + i * dx);
3253
+ }
3254
+ return (fx * dx) / 3;
3255
+ } else if(func.type === "curv") {
3256
+ if(func.definition.length === 2) {
3257
+ var x = Chalkboard.real.parse("t => " + func.definition[0]),
3258
+ y = Chalkboard.real.parse("t => " + func.definition[1]);
3259
+ var xt = x(a) + x(b),
3260
+ yt = y(a) + y(b);
3261
+ var dt = (b - a) / 1000000;
3262
+ for(var i = 1; i < 1000000; i++) {
3263
+ xt += i % 2 === 0 ? 2 * x(a + i * dt) : 4 * x(a + i * dt);
3264
+ yt += i % 2 === 0 ? 2 * y(a + i * dt) : 4 * y(a + i * dt);
3265
+ }
3266
+ return Chalkboard.vec2.new((xt * dt) / 3, (yt * dt) / 3);
3267
+ } else if(func.definition.length === 3) {
3268
+ var x = Chalkboard.real.parse("t => " + func.definition[0]),
3269
+ y = Chalkboard.real.parse("t => " + func.definition[1]),
3270
+ z = Chalkboard.real.parse("t => " + func.definition[2]);
3271
+ var xt = x(a) + x(b),
3272
+ yt = y(a) + y(b),
3273
+ zt = z(a) + z(b);
3274
+ var dt = (b - a) / 1000000;
3275
+ for(var i = 1; i < 1000000; i++) {
3276
+ xt += i % 2 === 0 ? 2 * x(a + i * dt) : 4 * x(a + i * dt);
3277
+ yt += i % 2 === 0 ? 2 * y(a + i * dt) : 4 * y(a + i * dt);
3278
+ zt += i % 2 === 0 ? 2 * z(a + i * dt) : 4 * z(a + i * dt);
3279
+ }
3280
+ return Chalkboard.vec3.new((xt * dt) / 3, (yt * dt) / 3, (zt * dt) / 3);
3281
+ }
3282
+ } else {
3283
+ return "TypeError: Parameter \"func\" must be of type \"expl\", \"pola\", or \"curv\".";
3284
+ }
3285
+ },
3286
+ fxydxdy: function(func, a, b, c, d) {
3287
+ if(func.type === "mult") {
3288
+ var f = Chalkboard.real.parse("(x, y) => " + func.definition);
3289
+ var result = 0;
3290
+ var dx = (b - a) / 10000,
3291
+ dy = (d - c) / 10000;
3292
+ for(var x = a; x <= b; x += dx) {
3293
+ for(var y = c; y <= d; y += dy) {
3294
+ result += f(x, y);
3295
+ }
3296
+ }
3297
+ return result * dx * dy;
3298
+ } else {
3299
+ return "TypeError: Parameter \"func\" must be of type \"mult\".";
3300
+ }
3301
+ },
3302
+ fds: function(func, a, b, c, d) {
3303
+ var result = 0;
3304
+ var drdt, drds;
3305
+ if(func.type === "curv") {
3306
+ var dt = (b - a) / 10000;
3307
+ if(func.definition.length === 2) {
3308
+ for(var t = a; t <= b; t += dt) {
3309
+ drdt = Chalkboard.calc.dfdx(func, t);
3310
+ result += Chalkboard.vec2.mag(drdt);
3311
+ }
3312
+ return result * dt;
3313
+ } else if(func.definition.length === 3) {
3314
+ for(var t = a; t <= b; t += dt) {
3315
+ drdt = Chalkboard.calc.dfdx(func, t);
3316
+ result += Chalkboard.vec3.mag(drdt);
3317
+ }
3318
+ return result * dt;
3319
+ }
3320
+ } else if(func.type === "surf") {
3321
+ var dt = (b - a) / 100,
3322
+ ds = (d - c) / 100;
3323
+ for(var s = c; s <= d; s += ds) {
3324
+ for(var t = a; t <= b; t += dt) {
3325
+ drds = Chalkboard.matr.toVector(Chalkboard.calc.grad(func, Chalkboard.vec2.new(s, t)), "vec3", "col", 1);
3326
+ drdt = Chalkboard.matr.toVector(Chalkboard.calc.grad(func, Chalkboard.vec2.new(s, t)), "vec3", "col", 2);
3327
+ result += Chalkboard.vec3.mag(Chalkboard.vec3.cross(drds, drdt));
3328
+ }
3329
+ }
3330
+ return result * ds * dt;
3331
+ } else {
3332
+ return "TypeError: Parameter \"func\" must be of type \"curv\" or \"surf\".";
3333
+ }
3334
+ },
3335
+ frds: function(funcORvecfield, func, a, b) {
3336
+ if(func.type === "curv") {
3337
+ var result = 0;
3338
+ var dt = (b - a) / 10000;
3339
+ if(funcORvecfield.type === "mult") {
3340
+ for(var t = a; t <= b; t += dt) {
3341
+ result += Chalkboard.real.val(funcORvecfield, Chalkboard.vec2.toArray(Chalkboard.real.val(func, t))) * Chalkboard.vec2.mag(Chalkboard.calc.dfdx(func, t));
3342
+ }
3343
+ return result * dt;
3344
+ } else if(funcORvecfield.type === "vec2field") {
3345
+ for(var t = a; t <= b; t += dt) {
3346
+ result += Chalkboard.vec2.dot(Chalkboard.vec2.fromField(funcORvecfield, Chalkboard.real.val(func, t)), Chalkboard.calc.dfdx(func, t));
3347
+ }
3348
+ return result * dt;
3349
+ } else if(funcORvecfield.type === "vec3field") {
3350
+ for(var t = a; t <= b; t += dt) {
3351
+ result += Chalkboard.vec3.dot(Chalkboard.vec3.fromField(funcORvecfield, Chalkboard.real.val(func, t)), Chalkboard.calc.dfdx(func, t));
3352
+ }
3353
+ return result * dt;
3354
+ } else {
3355
+ return "TypeError: Parameter \"funcORvecfield\" must be of type \"mult\", \"vec2field\", or \"vec3field\".";
3356
+ }
3357
+ } else {
3358
+ return "TypeError: Parameter \"func\" must be of type \"curv\".";
3359
+ }
3360
+ },
3361
+ fnds: function(vecfield, func, a, b, c, d) {
3362
+ var result = 0;
3363
+ var drdt, drds;
3364
+ if(func.type === "curv") {
3365
+ var dt = (b - a) / 10000;
3366
+ if(func.definition.length === 2) {
3367
+ for(var t = a; t <= b; t += dt) {
3368
+ drdt = Chalkboard.calc.dfdx(func, t);
3369
+ result += Chalkboard.vec2.dot(Chalkboard.vec2.fromField(vecfield, Chalkboard.real.val(func, t)), Chalkboard.vec2.new(-drdt.y, drdt.x)) * Chalkboard.vec2.mag(drdt);
3370
+ }
3371
+ return result * dt;
3372
+ } else if(func.definition.length === 3) {
3373
+ for(var t = a; t <= b; t += dt) {
3374
+ drdt = Chalkboard.calc.dfdx(func, t);
3375
+ result += Chalkboard.vec3.dot(Chalkboard.vec3.fromField(vecfield, Chalkboard.real.val(func, t)), Chalkboard.calc.normal(func, t)) * Chalkboard.vec3.mag(drdt);
3376
+ }
3377
+ return result * dt;
3378
+ }
3379
+ } else if(func.type === "surf") {
3380
+ var dt = (b - a) / 100,
3381
+ ds = (d - c) / 100;
3382
+ for(var s = c; s <= d; s += ds) {
3383
+ for(var t = a; t <= b; t += dt) {
3384
+ drds = Chalkboard.matr.toVector(Chalkboard.calc.grad(func, Chalkboard.vec2.new(s, t)), "vec3", "col", 1);
3385
+ drdt = Chalkboard.matr.toVector(Chalkboard.calc.grad(func, Chalkboard.vec2.new(s, t)), "vec3", "col", 2);
3386
+ result += Chalkboard.vec3.scalarTriple(Chalkboard.vec3.fromField(vecfield, Chalkboard.real.val(func, Chalkboard.vec2.new(s, t))), drds, drdt);
3387
+ }
3388
+ }
3389
+ return result * ds * dt;
3390
+ } else {
3391
+ return "TypeError: Parameter \"func\" must be of type \"curv\" or \"surf\".";
3392
+ }
3393
+ },
3394
+ fzdz: function(func_1, func_2, a, b) {
3395
+ if(func_1.type === "comp") {
3396
+ if(func_2.type === "curv") {
3397
+ var result = Chalkboard.comp.new(0, 0);
3398
+ var dt = (b - a) / 10000;
3399
+ for(var t = a; t <= b; t += dt) {
3400
+ var fz = Chalkboard.comp.val(func_1, Chalkboard.vec2.toComplex(Chalkboard.real.val(func_2, t)));
3401
+ var rt = Chalkboard.calc.dfdx(func_2, t);
3402
+ result = Chalkboard.comp.add(result, Chalkboard.comp.new((fz.a * rt.x) - (fz.b * rt.y), (fz.b * rt.x) + (fz.a * rt.y)));
3403
+ }
3404
+ return Chalkboard.comp.scl(result, dt);
3405
+ } else {
3406
+ return "TypeError: Parameter \"func_2\" must be of type \"curv\".";
3407
+ }
3408
+ } else {
3409
+ return "TypeError: Parameter \"func_1\" must be of type \"comp\".";
3410
+ }
3411
+ },
3412
+ extrema: function(func, domain) {
3413
+ var result = [];
3414
+ for(var i = domain[0]; i <= domain[1]; i++) {
3415
+ if(Math.round(Chalkboard.calc.dfdx(func, i)) === 0) {
3416
+ result.push(i);
3417
+ }
3418
+ }
3419
+ return result;
3420
+ },
3421
+ mean: function(func, a, b) {
3422
+ return (Chalkboard.calc.fxdx(func, a, b)) / (b - a);
3423
+ },
3424
+ curvature: function(func, val) {
3425
+ if(func.type === "curv") {
3426
+ if(func.definition.length === 2) {
3427
+ var dxdt = Chalkboard.calc.dfdx(func, val).x,
3428
+ dydt = Chalkboard.calc.dfdx(func, val).y,
3429
+ d2xdt2 = Chalkboard.calc.d2fdx2(func, val).x,
3430
+ d2ydt2 = Chalkboard.calc.d2fdx2(func, val).y;
3431
+ return Math.abs(dxdt * d2ydt2 - dydt * d2xdt2) / Math.sqrt((dxdt * dxdt + dydt * dydt) * (dxdt * dxdt + dydt * dydt) * (dxdt * dxdt + dydt * dydt));
3432
+ } else if(func.definition.length === 3) {
3433
+ return Chalkboard.vec3.mag(Chalkboard.calc.normal(func, val)) / Chalkboard.vec3.mag(Chalkboard.calc.dfdx(func, val));
3434
+ }
3435
+ } else {
3436
+ return "TypeError: Parameter \"func\" must be of type \"curv\".";
3437
+ }
3438
+ },
3439
+ convolution: function(func_1, func_2, val) {
3440
+ return Chalkboard.calc.fxdx(Chalkboard.real.function("(" + func_1.definition + ") * (" + func_2.definition.replace(/x/g, "(" + val + " - x)") + ")"), -100, 100);
3441
+ },
3442
+ correlation: function(func_1, func_2, val) {
3443
+ return Chalkboard.calc.fxdx(Chalkboard.real.function("(" + func_1.definition + ") * (" + func_2.definition.replace(/x/g, "(" + val + " + x)") + ")"), -100, 100);
3444
+ },
3445
+ autocorrelation: function(func, val) {
3446
+ return Chalkboard.calc.correlation(func, func, val);
3447
+ },
3448
+ Taylor: function(func, val, n, a) {
3449
+ if(func.type === "expl") {
3450
+ if(n === 0) {
3451
+ return Chalkboard.real.val(func, a);
3452
+ } else if(n === 1) {
3453
+ return Chalkboard.real.val(func, a) + Chalkboard.calc.dfdx(func, a) * (val - a);
3454
+ } else if(n === 2) {
3455
+ return Chalkboard.real.val(func, a) + Chalkboard.calc.dfdx(func, a) * (val - a) + (Chalkboard.calc.d2fdx2(func, a) * (val - a) * (val - a)) / 2;
3456
+ }
3457
+ } else {
3458
+ return "TypeError: Parameter \"func\" must be of type \"expl\".";
3459
+ }
3460
+ },
3461
+ Laplace: function(func, val) {
3462
+ if(val > 0) {
3463
+ return Chalkboard.calc.fxdx(Chalkboard.real.function("(" + func.definition + ") * Math.exp(-" + val + " * x)"), 0, 10);
3464
+ } else {
3465
+ return undefined;
3466
+ }
3467
+ },
3468
+ Fourier: function(func, val) {
3469
+ return (2 * Chalkboard.calc.fxdx(Chalkboard.real.function("(" + func.definition + ") * Math.cos(" + val + " * x)"), 0, 10)) / Chalkboard.PI();
3470
+ },
3471
+ Newton: function(func, domain) {
3472
+ domain = domain || [-1, 1];
3473
+ var x = Chalkboard.numb.random(domain[0], domain[1]);
3474
+ for(var i = 0; i < 10; i++) {
3475
+ x = x - Chalkboard.real.val(func, x) / Chalkboard.calc.dfdx(func, x);
3476
+ }
3477
+ return x;
3478
+ }
3479
+ }
3480
+ };
3481
+ module.exports = Chalkboard;