@carbonenginejs/core-math 0.1.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.
package/src/num.js ADDED
@@ -0,0 +1,735 @@
1
+ export const num = {};
2
+
3
+ num.EPSILON = 0.000001;
4
+ num.RAD2DEG = 180 / Math.PI;
5
+ num.DEG2RAD = Math.PI / 180;
6
+ num.TWO_PI = Math.PI * 2;
7
+ num.PI = Math.PI;
8
+ num.INV_TWO_PI = 1 / num.TWO_PI;
9
+
10
+ /**
11
+ * biCumulative
12
+ *
13
+ * @param {number} t
14
+ * @param {number} order
15
+ * @returns {number}
16
+ */
17
+ num.biCumulative = function (t, order)
18
+ {
19
+ if (order === 1)
20
+ {
21
+ const some = (1.0 - t);
22
+ return 1.0 - some * some * some;
23
+ }
24
+ else if (order === 2)
25
+ {
26
+ return 3.0 * t * t - 2.0 * t * t * t;
27
+ }
28
+ else
29
+ {
30
+ return t * t * t;
31
+ }
32
+ };
33
+
34
+ /**
35
+ * @alias Math.ceil
36
+ */
37
+ num.ceil = Math.ceil;
38
+
39
+ /**
40
+ * Clamps a number
41
+ *
42
+ * @param {number} a
43
+ * @param {number} min
44
+ * @param {number} max
45
+ * @returns {number}
46
+ */
47
+ num.clamp = function (a, min, max)
48
+ {
49
+ return Math.max(min, Math.min(max, a));
50
+ };
51
+
52
+ /**
53
+ * Returns how many decimal places a number has
54
+ *
55
+ * @param {number} a
56
+ * @returns {number}
57
+ */
58
+ num.decimalPlaces = function (a)
59
+ {
60
+ let match = ("" + a).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
61
+ return match ? Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0)) : 0;
62
+ };
63
+
64
+ /**
65
+ * Converts from radians to degrees
66
+ *
67
+ * @param {number} a
68
+ * @returns {number}
69
+ */
70
+ num.degrees = function (a)
71
+ {
72
+ return a * num.RAD2DEG;
73
+ };
74
+
75
+ /**
76
+ * Converts from radians to unwrapped degrees
77
+ *
78
+ * @param {number} a
79
+ * @returns {number}
80
+ */
81
+ num.degreesUnwrapped = function (a)
82
+ {
83
+ return num.unwrapDegrees(a * num.RAD2DEG);
84
+ };
85
+
86
+ /**
87
+ * Converts a Dword to Float
88
+ * @param value
89
+ * @return {Number}
90
+ */
91
+ num.dwordToFloat = function (value)
92
+ {
93
+ const
94
+ b4 = (value & 0xff),
95
+ b3 = (value & 0xff00) >> 8,
96
+ b2 = (value & 0xff0000) >> 16,
97
+ b1 = (value & 0xff000000) >> 24,
98
+ sign = 1 - (2 * (b1 >> 7)), // sign = bit 0
99
+ exp = (((b1 << 1) & 0xff) | (b2 >> 7)) - 127, // exponent = bits 1..8
100
+ sig = ((b2 & 0x7f) << 16) | (b3 << 8) | b4; // significand = bits 9..31
101
+
102
+ if (sig === 0 && exp === -127) return 0.0;
103
+ return sign * (1 + sig * Math.pow(2, -23)) * Math.pow(2, exp);
104
+ };
105
+
106
+ /**
107
+ * Checks if a number equals another
108
+ *
109
+ * @param a
110
+ * @param b
111
+ * @returns {boolean}
112
+ */
113
+ num.equals = function (a, b)
114
+ {
115
+ return Math.abs(a - b) <= num.EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b));
116
+ };
117
+
118
+ /**
119
+ * Checks if a number exactly equals another
120
+ * - included for library consistency
121
+ *
122
+ * @param {number} a
123
+ * @param {number} b
124
+ * @returns {boolean}
125
+ */
126
+ num.exactEquals = function (a, b)
127
+ {
128
+ return a === b;
129
+ };
130
+
131
+ /**
132
+ * Exponential decay
133
+ *
134
+ * @param {number} omega0
135
+ * @param {number} torque
136
+ * @param {number} I - inertia
137
+ * @param {number} d - drag
138
+ * @param {number} time - time
139
+ * @returns {number}
140
+ */
141
+ num.exponentialDecay = function (omega0, torque, I, d, time)
142
+ {
143
+ return torque * time / d + I * (omega0 * d - torque) / (d * d) * (1.0 - Math.pow(Math.E, -d * time / I));
144
+ };
145
+
146
+ /**
147
+ * Gets the fractional components of a number
148
+ *
149
+ * @param {number} a
150
+ * @returns {number}
151
+ */
152
+ num.fract = function (a)
153
+ {
154
+ return a - Math.floor(a);
155
+ };
156
+
157
+ /**
158
+ * Gets a value from a half float
159
+ * @author Babylon
160
+ * @param {number} a
161
+ * @returns {number}
162
+ */
163
+ num.fromHalfFloat = function (a)
164
+ {
165
+ const
166
+ s = (a & 0x8000) >> 15,
167
+ e = (a & 0x7C00) >> 10,
168
+ f = a & 0x03FF;
169
+
170
+ if (e === 0)
171
+ {
172
+ return (s ? -1 : 1) * Math.pow(2, -14) * (f / Math.pow(2, 10));
173
+ }
174
+ else if (e === 0x1F)
175
+ {
176
+ return f ? NaN : ((s ? -1 : 1) * Infinity);
177
+ }
178
+
179
+ return (s ? -1 : 1) * Math.pow(2, e - 15) * (1 + (f / Math.pow(2, 10)));
180
+ };
181
+
182
+ /**
183
+ * @alias Math.floor
184
+ */
185
+ num.floor = Math.floor;
186
+
187
+ /**
188
+ * Gets long word order
189
+ * @author Babylon
190
+ * @param {number} a
191
+ * @returns {number}
192
+ */
193
+ num.getLongWordOrder = function (a)
194
+ {
195
+ return (a === 0 || a === 255 || a === -16777216) ? 0 : 1 + num.getLongWordOrder(a >> 8);
196
+ };
197
+
198
+ /**
199
+ *
200
+ *
201
+ * @param {number} a
202
+ * @param {number} b
203
+ * @returns {number}
204
+ */
205
+ num.greaterThan = function (a, b)
206
+ {
207
+ return a > b ? 1 : 0;
208
+ };
209
+
210
+ /**
211
+ *
212
+ *
213
+ * @param {number} a
214
+ * @param {number} b
215
+ * @returns {number}
216
+ */
217
+ num.greaterThanEqual = function (a, b)
218
+ {
219
+ return num.isEqual(a, b) || a > b ? 1 : 0;
220
+ };
221
+
222
+ /**
223
+ *
224
+ * - included for library consistency
225
+ *
226
+ * @param {number} a
227
+ * @param {number} b
228
+ * @returns {number}
229
+ */
230
+ num.greaterThanExactEqual = function (a, b)
231
+ {
232
+ return a >= b ? 1 : 0;
233
+ };
234
+
235
+
236
+ /**
237
+ * Checks if a number is even
238
+ *
239
+ * @param {number} a
240
+ * @returns {boolean}
241
+ */
242
+ num.isEven = function (a)
243
+ {
244
+ return Math.abs(a) % 2 === 0;
245
+ };
246
+
247
+ /**
248
+ * Checks if a number is a float
249
+ *
250
+ * @param {number} a
251
+ * @returns {boolean}
252
+ */
253
+ num.isFloat = function (a)
254
+ {
255
+ return a % 1 !== 0;
256
+ };
257
+
258
+ /**
259
+ * @alias Number.isFinite
260
+ */
261
+ num.isFinite = Number.isFinite;
262
+ // return (typeof v === "number" && !isNaN(v) && v !== Infinity && v !== -Infinity);
263
+
264
+ /**
265
+ * Checks if a number is an integer
266
+ *
267
+ * @param {number} a
268
+ * @returns {boolean}
269
+ */
270
+ num.isInt = function (a)
271
+ {
272
+ return a % 1 === 0;
273
+ };
274
+
275
+ /**
276
+ * @alias Number.isNaN
277
+ */
278
+ num.isNaN = Number.isNaN;
279
+
280
+ /**
281
+ * Checks if a number is odd
282
+ *
283
+ * @param {number} a
284
+ * @returns {boolean}
285
+ */
286
+ num.isOdd = function (a)
287
+ {
288
+ return Math.abs(a) % 2 === 1;
289
+ };
290
+
291
+ /**
292
+ * Checks if a number is to the power of two
293
+ *
294
+ * @param {number} a
295
+ * @returns {boolean}
296
+ */
297
+ num.isPowerOfTwo = function (a)
298
+ {
299
+ return (a & (a - 1)) === 0 && a !== 0;
300
+ };
301
+
302
+ /**
303
+ *
304
+ *
305
+ * @param {number} a
306
+ * @param {number} b
307
+ * @returns {number}
308
+ */
309
+ num.lessThan = function (a, b)
310
+ {
311
+ return a < b ? 1 : 0;
312
+ };
313
+
314
+ /**
315
+ *
316
+ *
317
+ * @param {number} a
318
+ * @param {number} b
319
+ * @returns {number}
320
+ */
321
+ num.lessThanEqual = function (a, b)
322
+ {
323
+ return num.isEqual(a, b) || a < b ? 1 : 0;
324
+ };
325
+
326
+ /**
327
+ *
328
+ * - included for library consistency
329
+ *
330
+ * @param {number} a
331
+ * @param {number} b
332
+ * @returns {number}
333
+ */
334
+ num.lessThanExactEqual = function (a, b)
335
+ {
336
+ return a <= b ? 1 : 0;
337
+ };
338
+
339
+ /**
340
+ * Gets the log2 of a number
341
+ * @param {number} a
342
+ * @returns {number}
343
+ */
344
+ num.log2 = function (a)
345
+ {
346
+ return Math.log(a) * Math.LOG2E;
347
+ };
348
+
349
+ /**
350
+ * @alias Math.max
351
+ */
352
+ num.max = Math.max;
353
+
354
+ /**
355
+ * @alias Math.min
356
+ */
357
+ num.min = Math.min;
358
+
359
+
360
+ /**
361
+ * Gets the nearest power of two value to a number
362
+ *
363
+ * @param {number} a
364
+ * @returns {number}
365
+ */
366
+ num.nearestPowerOfTwo = function (a)
367
+ {
368
+ return Math.pow(2, Math.round(Math.log(a) / Math.LN2));
369
+ };
370
+
371
+ /**
372
+ *
373
+ *
374
+ * @param {number} value
375
+ * @param {number} start
376
+ * @param {number} end
377
+ * @param {number} precision
378
+ * @returns {number}
379
+ */
380
+ num.normalizeInt = function (value, start, end, precision)
381
+ {
382
+ let width = end - start;
383
+ let offsetValue = value - start;
384
+ let result = (offsetValue - ((offsetValue / width) * width)) + start;
385
+ return precision === undefined ? result : Number(result.toFixed(precision));
386
+ };
387
+
388
+ /**
389
+ *
390
+ *
391
+ * @param {number} value
392
+ * @param {number} start
393
+ * @param {number} end
394
+ * @param {number} precision
395
+ * @returns {number}
396
+ */
397
+ num.normalizeFloat = function (value, start, end, precision)
398
+ {
399
+ let width = end - start;
400
+ let offsetValue = value - start;
401
+ let result = (offsetValue - (Math.floor(offsetValue / width) * width)) + start;
402
+ return precision === undefined ? result : Number(result.toFixed(precision));
403
+ };
404
+
405
+
406
+ /**
407
+ * Converts from degrees to radians
408
+ *
409
+ * @param {number} a
410
+ * @returns {number}
411
+ */
412
+ num.radians = function (a)
413
+ {
414
+ return a * num.DEG2RAD;
415
+ };
416
+
417
+ /**
418
+ * Converts from degrees to unwrapped radians
419
+ *
420
+ * @param {number} a
421
+ * @returns {number}
422
+ */
423
+ num.radiansUnwrapped = function (a)
424
+ {
425
+ return num.unwrapRadians(a *= num.DEG2RAD);
426
+ };
427
+
428
+ /**
429
+ * Creates a random integer
430
+ *
431
+ * @param {number} low
432
+ * @param {number} high
433
+ * @returns {number}
434
+ */
435
+ num.randomInt = function (low, high)
436
+ {
437
+ return low + Math.floor(Math.random() * (high - low + 1));
438
+ };
439
+
440
+ /**
441
+ * Creates a random float
442
+ *
443
+ * @param {number} low
444
+ * @param {number} high
445
+ * @returns {number}
446
+ */
447
+ num.randomFloat = function (low, high)
448
+ {
449
+ return low + Math.random() * (high - low);
450
+ };
451
+
452
+ /**
453
+ * @alias for Math.round
454
+ */
455
+ num.round = Math.round;
456
+
457
+ /**
458
+ * Rounds a number to the closest zero
459
+ *
460
+ * @param {number} a
461
+ * @returns {number}
462
+ */
463
+ num.roundToZero = function (a)
464
+ {
465
+ return a < 0 ? Math.ceil(a) : Math.floor(a);
466
+ };
467
+
468
+ /**
469
+ * @alias for num.greaterThan
470
+ */
471
+ num.step = num.greaterThan;
472
+
473
+ /**
474
+ * Force positive number (excluding 0)
475
+ * @param {Number} s
476
+ * @returns {Number}
477
+ */
478
+ num.strictPositive = function (s)
479
+ {
480
+ return Math.max(num.EPSILON, Math.abs(s));
481
+ };
482
+
483
+ /**
484
+ * Force negative number (excluding 0)
485
+ * @param {Number} s
486
+ * @returns {Number}
487
+ */
488
+ num.strictNegative = function (s)
489
+ {
490
+ return -Math.max(num.EPSILON, Math.abs(s));
491
+ };
492
+
493
+
494
+ /**
495
+ *
496
+ * @param a
497
+ * @param min
498
+ * @param max
499
+ * @returns {number}
500
+ */
501
+ num.smoothStep = function (a, min, max)
502
+ {
503
+ if (a <= min) return 0;
504
+ if (a >= max) return 1;
505
+ a = (a - min) / (max - min);
506
+ return a * a * (3 - 2 * a);
507
+ };
508
+
509
+ /**
510
+ *
511
+ * @param a
512
+ * @param min
513
+ * @param max
514
+ * @returns {number}
515
+ */
516
+ num.smootherStep = function (a, min, max)
517
+ {
518
+ if (a <= min) return 0;
519
+ if (a >= max) return 1;
520
+ a = (a - min) / (max - min);
521
+ return a * a * a * (a * (a * 6 - 15) + 10);
522
+ };
523
+
524
+ /**
525
+ * Converts a number to a half float
526
+ * @author http://stackoverflow.com/questions/32633585/how-do-you-convert-to-half-floats-in-javascript
527
+ * @param {number} a
528
+ * @returns {number}
529
+ */
530
+ num.toHalfFloat = (function ()
531
+ {
532
+ let floatView, int32View;
533
+
534
+ return function (a)
535
+ {
536
+ if (!floatView)
537
+ {
538
+ floatView = new Float32Array(1);
539
+ int32View = new Int32Array(floatView.buffer);
540
+ }
541
+
542
+ floatView[0] = a;
543
+ const x = int32View[0];
544
+
545
+ let bits = (x >> 16) & 0x8000;
546
+ /* Get the sign */
547
+ let m = (x >> 12) & 0x07ff;
548
+ /* Keep one extra bit for rounding */
549
+ let e = (x >> 23) & 0xff;
550
+ /* Using int is faster here */
551
+
552
+ /* If zero, or denormal, or exponent underflows too much for a denormal half, return signed zero. */
553
+ if (e < 103)
554
+ {
555
+ return bits;
556
+ }
557
+
558
+ /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
559
+ if (e > 142)
560
+ {
561
+ bits |= 0x7c00;
562
+ /* If exponent was 0xff and one mantissa bit was set, it means NaN,
563
+ * not Inf, so make sure we set one mantissa bit too. */
564
+ bits |= ((e === 255) ? 0 : 1) && (x & 0x007fffff);
565
+ return bits;
566
+ }
567
+
568
+ /* If exponent underflows but not too much, return a denormal */
569
+ if (e < 113)
570
+ {
571
+ m |= 0x0800;
572
+ /* Extra rounding may overflow and set mantissa to 0 and exponent to 1, which is OK. */
573
+ bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);
574
+ return bits;
575
+ }
576
+
577
+ bits |= ((e - 112) << 10) | (m >> 1);
578
+ /* Extra rounding. An overflow will set mantissa to 0 and increment the exponent, which is OK. */
579
+ bits += m & 1;
580
+ return bits;
581
+ };
582
+
583
+ }());
584
+
585
+ /**
586
+ * Converts linear color to rgba/rgb color
587
+ * @param {Number} a
588
+ * @returns {Number}
589
+ */
590
+ num.colorFromLinear = function (a)
591
+ {
592
+ return Math.min(Math.floor(a * 255), 255);
593
+ };
594
+
595
+ /**
596
+ * Converts linear color to rgba/rgb color
597
+ * @param {Number} a
598
+ * @returns {Number}
599
+ */
600
+ num.linearFromColor = function (a)
601
+ {
602
+ return a / 255;
603
+ };
604
+
605
+ /**
606
+ * Converts linear color to hex string
607
+ * @param {Number} a
608
+ * @returns {String}
609
+ */
610
+ num.hexFromLinear = function (a)
611
+ {
612
+ return num.hexFromColor(num.colorFromLinear(a));
613
+ };
614
+
615
+ /**
616
+ * Converts rgb/rgba color to hex string
617
+ * @param {Number} a
618
+ * @returns {String}
619
+ */
620
+ num.hexFromColor = function (a)
621
+ {
622
+ return (a | 1 << 8).toString(16).slice(1);
623
+ };
624
+
625
+ /**
626
+ * Unwraps degrees
627
+ *
628
+ * @param {number} d
629
+ * @returns {number}
630
+ */
631
+ num.unwrapDegrees = function (d)
632
+ {
633
+ d = d % 360;
634
+ if (d > 180) d -= 360;
635
+ if (d < -180) d += 360;
636
+ return d;
637
+ };
638
+
639
+ /**
640
+ * Unwraps radians
641
+ *
642
+ * @param {number} r
643
+ * @returns {number}
644
+ */
645
+ num.unwrapRadians = function (r)
646
+ {
647
+ r = r % num.TWO_PI;
648
+ if (r > num.PI) r -= num.TWO_PI;
649
+ if (r < -num.PI) r += num.TWO_PI;
650
+ return r;
651
+ };
652
+
653
+ /**
654
+ * Converts srgb to linear colour
655
+ * @param {Number} a
656
+ * @returns {Number}
657
+ */
658
+ num.linearFromSRGB = function (a)
659
+ {
660
+ return (a < 0.04045) ? a * 0.0773993808 : Math.pow(a * 0.9478672986 + 0.0521327014, 2.4);
661
+ };
662
+
663
+ /**
664
+ * Converts linear colour to srgb
665
+ * @param {Number} a
666
+ * @returns {Number}
667
+ */
668
+ num.srgbFromLinear = function (a)
669
+ {
670
+ return (a < 0.0031308)
671
+ ? a * 12.92
672
+ : 1.055 * Math.pow(a, 1.0 / 2.4) - 0.055;
673
+ };
674
+
675
+ export const {
676
+ EPSILON,
677
+ RAD2DEG,
678
+ DEG2RAD,
679
+ TWO_PI,
680
+ PI,
681
+ INV_TWO_PI,
682
+ biCumulative,
683
+ ceil,
684
+ clamp,
685
+ decimalPlaces,
686
+ degrees,
687
+ degreesUnwrapped,
688
+ dwordToFloat,
689
+ equals,
690
+ exactEquals,
691
+ exponentialDecay,
692
+ fract,
693
+ fromHalfFloat,
694
+ floor,
695
+ getLongWordOrder,
696
+ greaterThan,
697
+ greaterThanEqual,
698
+ greaterThanExactEqual,
699
+ isEven,
700
+ isFloat,
701
+ isFinite,
702
+ isInt,
703
+ isNaN,
704
+ isOdd,
705
+ isPowerOfTwo,
706
+ lessThan,
707
+ lessThanEqual,
708
+ lessThanExactEqual,
709
+ log2,
710
+ max,
711
+ min,
712
+ nearestPowerOfTwo,
713
+ normalizeInt,
714
+ normalizeFloat,
715
+ radians,
716
+ radiansUnwrapped,
717
+ randomInt,
718
+ randomFloat,
719
+ round,
720
+ roundToZero,
721
+ step,
722
+ strictPositive,
723
+ strictNegative,
724
+ smoothStep,
725
+ smootherStep,
726
+ toHalfFloat,
727
+ colorFromLinear,
728
+ linearFromColor,
729
+ hexFromLinear,
730
+ hexFromColor,
731
+ unwrapDegrees,
732
+ unwrapRadians,
733
+ linearFromSRGB,
734
+ srgbFromLinear
735
+ } = num;