@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/sph3.js ADDED
@@ -0,0 +1,718 @@
1
+ import { vec3 } from "./vec3.js";
2
+ import { vec4 } from "./vec4.js";
3
+ import { mat4 } from "./mat4.js";
4
+ import { pln } from "./pln.js";
5
+ import { box3 } from "./box3.js";
6
+
7
+ /**
8
+ * 3D Sphere
9
+ * @typedef {Float32Array} sph3
10
+ */
11
+
12
+ export const sph3 = {};
13
+
14
+ // Scratch
15
+ let sph3_0 = null;
16
+ let box3_0 = null;
17
+
18
+ /**
19
+ * Allocates a pooled sph3
20
+ * @returns {Float32Array|sph3}
21
+ */
22
+ sph3.alloc = vec4.alloc;
23
+
24
+ /**
25
+ * Unallocates a pooled sph3
26
+ * @param {sph3|Float32Array} a
27
+ */
28
+ sph3.unalloc = vec4.unalloc;
29
+
30
+ /**
31
+ * Returns a subarray containing the position component of the sph3
32
+ * - Why does webpack fail to resolve this if referencing pln.normal?
33
+ *
34
+ * @param {sph3} a
35
+ * @returns {sph3}
36
+ */
37
+ sph3.$position = pln.$normal;
38
+
39
+ /**
40
+ * Clones a sphere
41
+ *
42
+ * @param {sph3} a
43
+ * @returns {sph3}
44
+ */
45
+ sph3.clone = vec4.clone;
46
+
47
+ /**
48
+ * Checks if a sphere contains a point
49
+ *
50
+ * @param {sph3} a
51
+ * @param {vec3} p
52
+ * @returns {boolean}
53
+ */
54
+ sph3.containsPoint = function(a, p)
55
+ {
56
+ let x = p[0] - a[0],
57
+ y = p[1] - a[1],
58
+ z = p[2] - a[2];
59
+
60
+ return (x * x + y * y + z * z) <= (a[3] * a[3]);
61
+ };
62
+
63
+ /**
64
+ * Copies a sphere
65
+ *
66
+ * @param {sph3} a
67
+ * @param {sph3} b
68
+ * @returns {sph3}
69
+ */
70
+ sph3.copy = vec4.copy;
71
+
72
+ /**
73
+ * Creates a sphere
74
+ *
75
+ * @returns {sph3}
76
+ */
77
+ sph3.create = function()
78
+ {
79
+ return new Float32Array([ 0, 0, 0, 0 ]);
80
+ };
81
+
82
+ /**
83
+ * Returns the distance between two spheres
84
+ *
85
+ * @param {sph3} a
86
+ * @param {sph3} b
87
+ * @returns {number}
88
+ */
89
+ sph3.distance = function(a, b)
90
+ {
91
+ let x = b[0] - a[0],
92
+ y = b[1] - a[1],
93
+ z = b[2] - a[2],
94
+ rii = b[3] + a[3];
95
+
96
+ return Math.sqrt(x * x + y * y + z * z) - rii;
97
+ };
98
+
99
+ /**
100
+ * Returns the distance from a sphere to a given point
101
+ *
102
+ * @param {sph3} a
103
+ * @param {vec3} p
104
+ * @returns {number}
105
+ */
106
+ sph3.distanceToPoint = function(a, p)
107
+ {
108
+ let x = p[0] - a[0],
109
+ y = p[1] - a[1],
110
+ z = p[2] - a[2];
111
+
112
+ return Math.sqrt(x * x + y * y + z * z) - a[3];
113
+ };
114
+
115
+ /**
116
+ * Empties a sphere
117
+ * @param {sph3} a
118
+ * @returns {sph3} a
119
+ */
120
+ sph3.empty = function(a)
121
+ {
122
+ a[0] = 0;
123
+ a[1] = 0;
124
+ a[2] = 0;
125
+ a[3] = 0;
126
+ return a;
127
+ };
128
+
129
+ /**
130
+ * Compares two sphere's for equality
131
+ *
132
+ * @param {sph3} a
133
+ * @param {sph3} b
134
+ * @returns {boolean}
135
+ */
136
+ sph3.equals = vec4.equals;
137
+
138
+ /**
139
+ * Compares a sphere to spherical components for equality
140
+ *
141
+ * @param {sph3} a
142
+ * @param {vec3} position
143
+ * @param {number} radius
144
+ * @returns {boolean}
145
+ */
146
+ sph3.equalsPositionRadius = pln.equalsNormalConstant;
147
+
148
+ /**
149
+ * Compares two sphere for exact equality
150
+ *
151
+ * @param {sph3} a
152
+ * @param {sph3} b
153
+ * @returns {boolean}
154
+ */
155
+ sph3.exactEquals = vec4.exactEquals;
156
+
157
+ /**
158
+ * Compares a sphere to spherical components for exact equality
159
+ *
160
+ * @param {sph3} a
161
+ * @param {vec3} position
162
+ * @param {number} radius
163
+ * @returns {boolean}
164
+ */
165
+ sph3.exactEqualsPositionRadius = pln.exactEqualsNormalConstant;
166
+
167
+ /**
168
+ * Extracts a spheres's components
169
+ *
170
+ * @param {sph3} a
171
+ * @param {vec3} outPosition
172
+ * @returns {number}
173
+ */
174
+ sph3.extract = pln.extract;
175
+
176
+ /**
177
+ * Sets a sphere from a box3
178
+ *
179
+ * @param {sph3} out
180
+ * @param {box3} b
181
+ * @return {sph3} out
182
+ */
183
+ sph3.fromBox3 = function(out, b)
184
+ {
185
+ let sX = b[3] - b[0],
186
+ sY = b[4] - b[1],
187
+ sZ = b[5] - b[2];
188
+
189
+ out[0] = (b[0] + b[3]) * 0.5;
190
+ out[1] = (b[1] + b[4]) * 0.5;
191
+ out[2] = (b[2] + b[5]) * 0.5;
192
+
193
+ out[3] = Math.sqrt(sX * sX + sY * sY + sZ * sZ) * 0.5;
194
+ return out;
195
+ };
196
+
197
+ /**
198
+ * Sets a sphere from a box's bounds
199
+ *
200
+ * @param {sph3} out
201
+ * @param {vec3} min
202
+ * @param {vec3} max
203
+ * @returns {sph3}
204
+ */
205
+ sph3.fromBounds = function(out, min, max)
206
+ {
207
+ let sX = max[0] - min[0],
208
+ sY = max[1] - min[1],
209
+ sZ = max[2] - min[2];
210
+
211
+ out[0] = (min[0] + max[0]) * 0.5;
212
+ out[1] = (min[1] + max[1]) * 0.5;
213
+ out[2] = (min[2] + max[2]) * 0.5;
214
+
215
+ out[3] = Math.sqrt(sX * sX + sY * sY + sZ * sZ) * 0.5;
216
+ return out;
217
+ };
218
+
219
+ /**
220
+ * Sets a sphere from position and radius
221
+ *
222
+ * @param {sph3} out
223
+ * @param {vec3} p
224
+ * @param {number} r
225
+ * @returns {sph3} out
226
+ */
227
+ sph3.fromPositionRadius = pln.fromNormalConstant;
228
+
229
+ sph3.from = sph3.fromPositionRadius;
230
+
231
+ /**
232
+ * Sets a sphere from a mat4's translation and a given radius
233
+ *
234
+ * @param {sph3} out
235
+ * @param {(mat4|vec3)} a
236
+ * @param {number} radius
237
+ * @returns {sph3} out
238
+ */
239
+ sph3.fromTranslationRadius = function(out, a, radius)
240
+ {
241
+ out[0] = a[12];
242
+ out[1] = a[13];
243
+ out[2] = a[14];
244
+ out[3] = radius;
245
+ return out;
246
+ };
247
+
248
+ /**
249
+ * Gets a sphere from a mat4's translation and max axis scale
250
+ *
251
+ * @param {sph3} out
252
+ * @param {mat4} m
253
+ * @returns {sph3} out
254
+ */
255
+ sph3.fromMat4 = function(out, m)
256
+ {
257
+ out[0] = m[12];
258
+ out[1] = m[13];
259
+ out[2] = m[14];
260
+ out[3] = mat4.maxScaleOnAxis(m);
261
+ return out;
262
+ };
263
+
264
+ let aPosition,
265
+ bPosition,
266
+ toAPosition,
267
+ toBPosition,
268
+ center;
269
+
270
+ /**
271
+ * Gets the union of two spheres
272
+ * @param {sph3} out
273
+ * @param {sph3} a
274
+ * @param {sph3} b
275
+ * @returns {sph3} out
276
+ */
277
+ sph3.union = function(out, a, b)
278
+ {
279
+ if (!aPosition)
280
+ {
281
+ aPosition = vec3.create();
282
+ bPosition = vec3.create();
283
+ toAPosition = vec3.create();
284
+ toBPosition = vec3.create();
285
+ }
286
+
287
+ const
288
+ aRadius = sph3.extract(a, aPosition),
289
+ bRadius = sph3.extract(b, bPosition);
290
+
291
+ vec3.subtract(toBPosition, bPosition, aPosition);
292
+ const separation = vec3.length(toBPosition);
293
+
294
+ if (aRadius >= separation + bRadius)
295
+ {
296
+ return out === a ? out : sph3.copy(out, a);
297
+ }
298
+
299
+ if (bRadius >= separation + aRadius)
300
+ {
301
+ return out === b ? out : sph3.copy(out, b);
302
+ }
303
+
304
+ if (!center) center = vec3.create();
305
+ const halfDistance = (aRadius + separation + bRadius) * 0.5;
306
+ vec3.scale(center, toBPosition, (-aRadius + halfDistance) / separation);
307
+ vec3.add(center, aPosition, center);
308
+ return sph3.fromPositionRadius(out, center, halfDistance);
309
+ };
310
+
311
+ /**
312
+ * Gets the union of a sphere and a sphere's components
313
+ * @param {sph3} out
314
+ * @param {sph3} a
315
+ * @param {vec3} position
316
+ * @param {Number} radius
317
+ * @returns {sph3}
318
+ */
319
+ sph3.unionPositionRadius = function(out, a, position, radius)
320
+ {
321
+ if (!sph3_0) sph3_0 = sph3.create();
322
+ return sph3.union(out, a, sph3.fromPositionRadius(sph3_0, position, radius));
323
+ };
324
+
325
+ /**
326
+ * Gets a point clamped to the sphere
327
+ *
328
+ * @author three.js authors (conversion)
329
+ * @param {vec3} out
330
+ * @param {sph3} a
331
+ * @param {vec3} p
332
+ * @returns {vec3} out
333
+ */
334
+ sph3.getClampedPoint = function(out, a, p)
335
+ {
336
+ out[0] = p[0];
337
+ out[1] = p[1];
338
+ out[2] = p[2];
339
+
340
+ let x = a[0] - p[0],
341
+ y = a[1] - p[1],
342
+ z = a[2] - p[2];
343
+
344
+ if ((x * x + y * y + z * z) > (a[3] * a[3]))
345
+ {
346
+ out[0] = out[0] - a[0];
347
+ out[1] = out[1] - a[1];
348
+ out[2] = out[2] - a[2];
349
+
350
+ vec3.normalize(out, out);
351
+
352
+ out[0] = out[0] * a[3] + a[0];
353
+ out[1] = out[1] * a[3] + a[1];
354
+ out[2] = out[2] * a[3] + a[2];
355
+ }
356
+
357
+ return out;
358
+ };
359
+
360
+ /**
361
+ * Gets the position of a point on a sphere from longitude and latitude
362
+ *
363
+ * @param {vec3} out
364
+ * @param {sph3} a
365
+ * @param {number} longitude
366
+ * @param {number} latitude
367
+ * @returns {vec3} out
368
+ */
369
+ sph3.getPointFromLongLat = function(out, a, longitude, latitude)
370
+ {
371
+ out[0] = a[0] + a[3] * Math.sin(latitude) * Math.cos(longitude);
372
+ out[1] = a[1] + a[3] * Math.sin(latitude) * Math.sin(longitude);
373
+ out[2] = a[2] + a[3] * Math.cos(latitude);
374
+ return out;
375
+ };
376
+
377
+ /**
378
+ * Gets the position component of a sph3
379
+ *
380
+ * @param {vec3} out
381
+ * @param {sph3} a
382
+ * @returns {vec3} out
383
+ */
384
+ sph3.getPosition = pln.getNormal;
385
+
386
+ /**
387
+ * Checks for intersection between two sph3s
388
+ *
389
+ * @param {sph3} a
390
+ * @param {sph3} b
391
+ * @returns {boolean}
392
+ */
393
+ sph3.intersectsSph3 = function(a, b)
394
+ {
395
+ let x = b[0] - a[0],
396
+ y = b[1] - a[1],
397
+ z = b[2] - a[2];
398
+ let radii = a[3] + b[3];
399
+
400
+ return (x * x + y * y + z * z) <= (radii * radii);
401
+ };
402
+
403
+ /**
404
+ * Checks for intersection with a box3
405
+ *
406
+ * @param {sph3} a
407
+ * @param {box3} b
408
+ * @returns {boolean}
409
+ */
410
+ sph3.intersectsBox3 = function(a, b)
411
+ {
412
+ return box3.intersectsSph3(b, a);
413
+ };
414
+
415
+ /**
416
+ * Checks sph for intersection with a boxes' bounds
417
+ *
418
+ * @param {sph3} a
419
+ * @param {vec3} min
420
+ * @param {vec3} max
421
+ * @returns {boolean}
422
+ */
423
+ sph3.intersectsBounds = function(a, min, max)
424
+ {
425
+ let x = Math.max(min[0], Math.min(max[0], a[0])) - a[0],
426
+ y = Math.max(min[1], Math.min(max[1], a[1])) - a[1],
427
+ z = Math.max(min[2], Math.min(max[2], a[2])) - a[2];
428
+
429
+ return (x * x + y * y + z * z) <= a[3] * a[3];
430
+ };
431
+
432
+ /**
433
+ * Checks sph for intersection with a sphere's components
434
+ *
435
+ * @param {sph3} a
436
+ * @param {vec3} p
437
+ * @param {number} r
438
+ * @returns {boolean}
439
+ */
440
+ sph3.intersectsPositionRadius = function(a, p, r)
441
+ {
442
+ let x = p[0] - a[0],
443
+ y = p[1] - a[1],
444
+ z = p[2] - a[2];
445
+
446
+ let radii = a[3] + r;
447
+ return (x * x + y * y + z * z) <= (radii * radii);
448
+ };
449
+
450
+ /**
451
+ * Checks for intersection with a Float32Array(4) plane
452
+ *
453
+ * @param {sph3} a
454
+ * @param {pln} p
455
+ * @returns {boolean}
456
+ */
457
+ sph3.intersectsPln = function(a, p)
458
+ {
459
+ return pln.intersectsSph3(p, a);
460
+ };
461
+
462
+ /**
463
+ * Checks for intersection with a plane's components
464
+ *
465
+ * @param {sph3} a - sphere to intersect
466
+ * @param {vec3} n - plane normal
467
+ * @param {number} c - plane constant
468
+ * @returns {boolean}
469
+ */
470
+ sph3.intersectsNormalConstant = function(a, n, c)
471
+ {
472
+ let distance = a[0] * n[0] + a[1] * n[1] + a[2] * n[2] + c;
473
+ return Math.abs(distance) <= a[3];
474
+ };
475
+
476
+ /**
477
+ * Checks if a sph3 is empty
478
+ *
479
+ * @param {sph3} a
480
+ * @returns {boolean}
481
+ */
482
+ sph3.isEmpty = function(a)
483
+ {
484
+ return a[3] <= 0;
485
+ };
486
+
487
+ /**
488
+ * Returns the radius component of the sph3
489
+ *
490
+ * @param {sph3} a
491
+ * @returns {number}
492
+ */
493
+ sph3.radius = pln.constant;
494
+
495
+ /**
496
+ * Sets a sph3 from values
497
+ *
498
+ * @param {sph3} out
499
+ * @param {number} px
500
+ * @param {number} py
501
+ * @param {number} pz
502
+ * @param {number} r
503
+ * @returns {sph3}
504
+ */
505
+ sph3.set = vec4.set;
506
+
507
+ /**
508
+ * Sets a sph3 from an array at an optional offset
509
+ *
510
+ * @param {sph3} out
511
+ * @param {Array} arr
512
+ * @param {number} [index=0]
513
+ * @returns {sph3} out
514
+ */
515
+ sph3.setArray = vec4.setArray;
516
+
517
+ /**
518
+ * Sets a sphere from points, at an optional position vector
519
+ *
520
+ * @param {sph3} out - the receiving sphere
521
+ * @param {Array} points - The points to create the sphere from
522
+ * @param {vec3} [position] - An optional center position
523
+ * @returns {sph3} out - the receiving sphere
524
+ */
525
+ sph3.setPoints = function(out, points, position)
526
+ {
527
+ if (!box3_0) box3_0 = box3.create();
528
+
529
+ if (position)
530
+ {
531
+ out[0] = position[0];
532
+ out[1] = position[1];
533
+ out[2] = position[2];
534
+ }
535
+ else
536
+ {
537
+ box3.setPoints(box3_0, points);
538
+ out[0] = (box3_0[0] + box3_0[3]) * 0.5;
539
+ out[1] = (box3_0[1] + box3_0[4]) * 0.5;
540
+ out[2] = (box3_0[2] + box3_0[5]) * 0.5;
541
+ }
542
+
543
+ let maxSquaredRadius = 0;
544
+
545
+ for (let i = 0; i < points.length; i++)
546
+ {
547
+ let x = out[0] - points[i][0],
548
+ y = out[1] - points[i][1],
549
+ z = out[2] - points[i][2];
550
+
551
+ maxSquaredRadius = Math.max(maxSquaredRadius, x * x + y * y + z * z);
552
+ }
553
+
554
+ out[3] = Math.sqrt(maxSquaredRadius);
555
+ return out;
556
+ };
557
+
558
+ /**
559
+ * Returns the squared distance between two sph3s
560
+ *
561
+ * @param {sph3} a
562
+ * @param {sph3} b
563
+ * @returns {number}
564
+ */
565
+ sph3.squaredDistance = function(a, b)
566
+ {
567
+ let x = b[0] - a[0],
568
+ y = b[1] - a[1],
569
+ z = b[2] - a[2],
570
+ r = b[3] + a[3];
571
+
572
+ return (x * x + y * y + z * z) - (r * r);
573
+ };
574
+
575
+ /**
576
+ * Returns the square distance from a sphere to a given point
577
+ *
578
+ * @param {sph3} a
579
+ * @param {vec3} p
580
+ * @returns {number}
581
+ */
582
+ sph3.squaredDistanceToPoint = function(a, p)
583
+ {
584
+ let x = p[0] - a[0],
585
+ y = p[1] - a[1],
586
+ z = p[2] - a[2];
587
+
588
+ return (x * x + y * y + z * z) - a[3] * a[3];
589
+ };
590
+
591
+ /**
592
+ * Sets an array at an optional offset, with the values of a sph3
593
+ *
594
+ * @param {sph3} a
595
+ * @param {Array} arr
596
+ * @param {number} [offset = 0]
597
+ * @returns {sph3} a
598
+ */
599
+ sph3.toArray = vec4.toArray;
600
+
601
+ /**
602
+ * Converts a sphere to bounds
603
+ *
604
+ * @param {sph3} a
605
+ * @param {vec3} minBounds
606
+ * @param {vec3} maxBounds
607
+ */
608
+ sph3.toBounds = function(a, minBounds, maxBounds)
609
+ {
610
+ if (!box3_0) box3_0 = box3.create();
611
+ box3.fromSph3(box3_0, a);
612
+ box3.toBounds(box3_0, minBounds, maxBounds);
613
+ };
614
+
615
+ /**
616
+ *
617
+ * @param a
618
+ * @param position
619
+ * @returns {*}
620
+ */
621
+ sph3.toPositionRadius = function(a, position)
622
+ {
623
+ position[0] = a[0];
624
+ position[1] = a[1];
625
+ position[2] = a[2];
626
+ return a[3];
627
+ };
628
+
629
+ /**
630
+ * Transforms a sphere with a mat4
631
+ *
632
+ * @author three.js authors (conversion)
633
+ * @param {sph3} out - the receiving sphere
634
+ * @param {sph3} a - the sphere to transform
635
+ * @param {mat4} m - the matrix to transform by
636
+ * @returns {sph3}
637
+ */
638
+ sph3.transformMat4 = function(out, a, m)
639
+ {
640
+ let x = a[0],
641
+ y = a[1],
642
+ z = a[2];
643
+
644
+ let sX = m[0] * m[0] + m[1] * m[1] + m[2] * m[2],
645
+ sY = m[4] * m[4] + m[5] * m[5] + m[6] * m[6],
646
+ sZ = m[8] * m[8] + m[9] * m[9] + m[10] * m[10];
647
+
648
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12];
649
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13];
650
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14];
651
+
652
+ out[3] = a[3] * Math.sqrt(Math.max(sX, sY, sZ));
653
+ return out;
654
+ };
655
+
656
+ /**
657
+ * Returns the result of a sphere translated by a given vector
658
+ *
659
+ * @param {sph3} out - the receiving sphere
660
+ * @param {sph3} a - the sphere to translate
661
+ * @param {vec3} v - the vector to translate with
662
+ * @returns {sph3}
663
+ */
664
+ sph3.translate = function(out, a, v)
665
+ {
666
+ out[0] = a[0] + v[0];
667
+ out[1] = a[1] + v[1];
668
+ out[2] = a[2] + v[2];
669
+ out[3] = a[3];
670
+ return out;
671
+ };
672
+
673
+ export const {
674
+ alloc,
675
+ unalloc,
676
+ $position,
677
+ clone,
678
+ containsPoint,
679
+ copy,
680
+ create,
681
+ distance,
682
+ distanceToPoint,
683
+ empty,
684
+ equals,
685
+ equalsPositionRadius,
686
+ exactEquals,
687
+ exactEqualsPositionRadius,
688
+ extract,
689
+ fromBox3,
690
+ fromBounds,
691
+ fromPositionRadius,
692
+ from,
693
+ fromTranslationRadius,
694
+ fromMat4,
695
+ union,
696
+ unionPositionRadius,
697
+ getClampedPoint,
698
+ getPointFromLongLat,
699
+ getPosition,
700
+ intersectsSph3,
701
+ intersectsBox3,
702
+ intersectsBounds,
703
+ intersectsPositionRadius,
704
+ intersectsPln,
705
+ intersectsNormalConstant,
706
+ isEmpty,
707
+ radius,
708
+ set,
709
+ setArray,
710
+ setPoints,
711
+ squaredDistance,
712
+ squaredDistanceToPoint,
713
+ toArray,
714
+ toBounds,
715
+ toPositionRadius,
716
+ transformMat4,
717
+ translate
718
+ } = sph3;