@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/ray3.js ADDED
@@ -0,0 +1,1056 @@
1
+ import { vec3 } from "./vec3.js";
2
+ import { pln } from "./pln.js";
3
+ import { sph3 } from "./sph3.js";
4
+ import { box3 } from "./box3.js";
5
+ import { tri3 } from "./tri3.js";
6
+ import { mat3 } from "./mat3.js";
7
+
8
+ /**
9
+ * 3D Ray
10
+ * @typedef {Float32Array} ray3
11
+ */
12
+
13
+ export const ray3 = {};
14
+
15
+ /**
16
+ * Allocates a pooled ray3
17
+ * @returns {Float32Array|ray3}
18
+ */
19
+ ray3.alloc = box3.alloc;
20
+
21
+ /**
22
+ * Unallocates a pooled ray3
23
+ * @param {ray3|Float32Array} a
24
+ */
25
+ ray3.unalloc = box3.unalloc;
26
+
27
+ /**
28
+ * Gets a subarray of a ray3's origin vector
29
+ * @property {box3} a
30
+ * @returns {TypedArray}
31
+ */
32
+ ray3.$origin = box3.$min;
33
+
34
+ /**
35
+ * Gets a subarray of a ray3's direction vector
36
+ * @property {box3} a
37
+ * @returns {TypedArray}
38
+ */
39
+ ray3.$direction = box3.$max;
40
+
41
+ /**
42
+ * Clones a ray3
43
+ *
44
+ * @param {ray3} a
45
+ * @returns {ray3}
46
+ */
47
+ ray3.clone = box3.clone;
48
+
49
+ /**
50
+ * Copies the values from one ray3 into another
51
+ *
52
+ * @param {ray3} out
53
+ * @param {ray3} a
54
+ * @returns {ray3} out
55
+ */
56
+ ray3.copy = box3.copy;
57
+
58
+ /**
59
+ * Copies the origin vector of one ray3 to another
60
+ *
61
+ * @param {ray3} out
62
+ * @param {ray3} a
63
+ * @returns {ray3}
64
+ */
65
+ ray3.copyOrigin = box3.copyMin;
66
+
67
+ /**
68
+ * Copies the direction vector of one ray3 to another
69
+ *
70
+ * @param {ray3} out
71
+ * @param {ray3} a
72
+ * @returns {ray3}
73
+ */
74
+ ray3.copyDirection = box3.copyMax;
75
+
76
+ /**
77
+ * Creates a ray3
78
+ *
79
+ * @returns {ray3}
80
+ */
81
+ ray3.create = box3.create;
82
+
83
+ /**
84
+ * Gets the distance from a ray3 to a point
85
+ *
86
+ * @param {ray3} a - source ray3
87
+ * @param {vec3} p - point to measure distance to
88
+ * @returns {number} - distance
89
+ */
90
+ ray3.distance = function (a, p)
91
+ {
92
+ return Math.sqrt(ray3.squaredDistance(a, p));
93
+ };
94
+
95
+ /**
96
+ * Gets the distance from a ray3"s origin to a plane"s components
97
+ *
98
+ * @author three.js authors (converted)
99
+ * @param {ray3} a - source ray3
100
+ * @param {vec3} n - plane normal
101
+ * @param {number} c - plane constant
102
+ * @returns {null|number} - distance
103
+ */
104
+ ray3.distanceNormalConstant = function (a, n, c)
105
+ {
106
+ let den = n[0] * a[3] + n[1] * a[4] + n[2] * a[5];
107
+ let dist = (a[0] * n[0] + a[1] * n[1] + a[2] * n[2]) + c;
108
+ if (den === 0)
109
+ {
110
+ if (dist === 0) return 0;
111
+ throw new Error("Determinant error");
112
+ //return null;
113
+ }
114
+
115
+ let t = -dist / den;
116
+ return t >= 0 ? t : null;
117
+ };
118
+
119
+ /**
120
+ * Gets the distance from a ray3"s origin to a Float32Array(4) plane
121
+ *
122
+ * @author three.js authors (converted)
123
+ * @param {ray3} a - source ray3
124
+ * @param {pln} p - plane to measure distance to
125
+ * @returns {null|Number} - distance
126
+ */
127
+ ray3.distancePln = function (a, p)
128
+ {
129
+ let den = p[0] * a[3] + p[1] * a[4] + p[2] * a[5];
130
+ let dist = (a[0] * p[0] + a[1] * p[1] + a[2] * p[2]) + p[3];
131
+
132
+ if (den === 0)
133
+ {
134
+ if (dist === 0) return 0;
135
+ throw new Error("Determinant error");
136
+ //return null;
137
+ }
138
+
139
+ let t = -dist / den;
140
+ return t >= 0 ? t : null;
141
+ };
142
+
143
+ /**
144
+ * Checks two ray3"s for equality
145
+ *
146
+ * @param {ray3} a
147
+ * @param {ray3} b
148
+ * @returns {boolean}
149
+ */
150
+ ray3.equals = box3.equals;
151
+
152
+ /**
153
+ * Checks a ray3 against it"s components for equality
154
+ *
155
+ * @param {ray3} a
156
+ * @param {vec3} min
157
+ * @param {vec3} max
158
+ * @returns {boolean}
159
+ */
160
+ ray3.equalsOriginDestination = box3.equalsBounds;
161
+
162
+ /**
163
+ * Checks for box3 exact equality
164
+ *
165
+ * @param {ray3} a
166
+ * @param {ray3} b
167
+ * @returns {boolean}
168
+ */
169
+ ray3.exactEquals = box3.exactEquals;
170
+
171
+ /**
172
+ * Checks for exact equality between a ray3 and ray3 components
173
+ *
174
+ * @param {ray3} a
175
+ * @param {vec3} min
176
+ * @param {vec3} max
177
+ * @returns {boolean}
178
+ */
179
+ ray3.exactEqualsOriginDestination = box3.exactEqualsBounds;
180
+
181
+ /**
182
+ * Sets a ray3 from origin and destination
183
+ *
184
+ * @param {ray3} out
185
+ * @param {vec3} o
186
+ * @param {vec3} d
187
+ * @returns {ray3} out
188
+ */
189
+ ray3.from = box3.from;
190
+
191
+ /**
192
+ * Sets a ray3 from an array at an optional offset
193
+ *
194
+ * @param {ray3} out
195
+ * @param {Array} arr
196
+ * @param {number} [index=0]
197
+ * @returns {ray3}
198
+ */
199
+ ray3.fromArray = box3.fromArray;
200
+
201
+ /**
202
+ * Sets a ray 3 from start and end vectors
203
+ *
204
+ * @param {ray3} out
205
+ * @param {vec3} start
206
+ * @param {vec3} end
207
+ * @returns {ray3}
208
+ */
209
+ ray3.fromStartEnd = function (out, start, end)
210
+ {
211
+ out[0] = start[0];
212
+ out[1] = start[1];
213
+ out[2] = start[2];
214
+ out[3] = end[0] - start[0];
215
+ out[4] = end[1] - start[1];
216
+ out[5] = end[2] - start[2];
217
+ return ray3.normalize(out, out);
218
+ };
219
+
220
+
221
+ let mat3_0;
222
+
223
+ /**
224
+ * Sets a ray3 from a mat4
225
+ * @param {ray3} out
226
+ * @param {mat4} m
227
+ * @return {ray3}
228
+ */
229
+ ray3.fromMat4 = function (out, m)
230
+ {
231
+ if (!mat3_0) mat3_0 = mat3.create();
232
+
233
+ out[0] = 0;
234
+ out[1] = 0;
235
+ out[2] = 0;
236
+ out[3] = 0;
237
+ out[4] = 0;
238
+ out[5] = -1;
239
+
240
+ vec3.transformMat4(ray3.$origin(out), ray3.$origin(out), m);
241
+ mat3.fromMat4(mat3_0, m);
242
+ vec3.transformMat3(ray3.$direction(out), ray3.$direction(out), mat3_0);
243
+ return ray3.normalize(out, out);
244
+ };
245
+
246
+ /**
247
+ * Sets a ray3 from a screen coordinates and an inverse view projection matrix
248
+ *
249
+ * @param {vec3} out - receiving ray3
250
+ * @param {vec2} coords - canvas coordinates (not client)
251
+ * @param {mat4} m - - inverse view projection matrix
252
+ * @param {mat4} viewport - viewport settings (x, y, width, height)
253
+ */
254
+ ray3.fromPerspective = function (out, coords, m, viewport)
255
+ {
256
+ // Convert view port co-ordinates
257
+ let x = (coords[0] - viewport[0]) * 2.0 / viewport[2] - 1.0,
258
+ y = (coords[1] - viewport[1]) * 2.0 / viewport[3] - 1.0;
259
+ // Calculate w
260
+ let oW = (m[3] * x + m[7] * y + m[11] * -1 + m[15]),
261
+ dW = (m[3] * x + m[7] * y + m[11] * 1 + m[15]);
262
+ // Check for perspective divide error
263
+ if (oW === 0.0 || dW === 0.0)
264
+ {
265
+ throw new Error("Perspective Divide Error");
266
+ }
267
+ // Transform origin
268
+ out[0] = (m[0] * x + m[4] * y + m[8] * -1 + m[12]) / oW;
269
+ out[1] = (m[1] * x + m[5] * y + m[9] * -1 + m[13]) / oW;
270
+ out[2] = (m[2] * x + m[6] * y + m[10] * -1 + m[14]) / oW;
271
+ // Transform direction
272
+ out[3] = ((m[0] * x + m[4] * y + m[8] * 1 + m[12]) / dW) - out[0];
273
+ out[4] = ((m[1] * x + m[5] * y + m[9] * 1 + m[13]) / dW) - out[1];
274
+ out[5] = ((m[2] * x + m[6] * y + m[10] * 1 + m[14]) / dW) - out[2];
275
+
276
+ // Normalize direction
277
+ return ray3.normalize(out, out);
278
+ };
279
+
280
+
281
+
282
+ /**
283
+ * Alternative to ray3.fromPerspective
284
+ * @param {ray3} out - receiving ray3
285
+ * @param {vec2} coords - event.ClientX, canvasHeight - event.clientY
286
+ * @param {mat4} invProjView - inverse projection view matrix
287
+ * @param {vec4} viewport - x, y, width, height
288
+ * @returns {ray3}
289
+ */
290
+ ray3.unproject = function (out, coords, invProjView, viewport)
291
+ {
292
+ const
293
+ start = [ coords[0], coords[1], 0 ],
294
+ end = [ coords[0], coords[1], 1 ];
295
+
296
+ vec3.unproject(start, start, invProjView, viewport);
297
+ vec3.unproject(end, end, invProjView, viewport);
298
+
299
+ return ray3.fromStartEnd(out, start, end);
300
+ };
301
+
302
+ /**
303
+ * Sets a vec3 with the position on a ray3 at a given distance from it"s origin
304
+ *
305
+ * @param {vec3} out - receiving vec3
306
+ * @param {ray3} a - source ray3
307
+ * @param {number} t - distance along the ray3
308
+ * @returns {vec3} out - receiving vec3
309
+ */
310
+ ray3.get = function (out, a, t)
311
+ {
312
+ out[0] = a[0] + (a[3] * t);
313
+ out[1] = a[1] + (a[4] * t);
314
+ out[2] = a[2] + (a[5] * t);
315
+ return out;
316
+ };
317
+
318
+ /**
319
+ * Sets a vec3 with the ray3's direction
320
+ *
321
+ * @param {vec3} out - receiving vec3
322
+ * @param {ray3} a - source ray
323
+ * @returns {vec3} [out] - receiving vec3
324
+ */
325
+ ray3.getDirection = box3.getMax;
326
+
327
+ /**
328
+ * Sets a vec3 with the closest point on a ray3 to a given point
329
+ *
330
+ * @author three.js authors (converted)
331
+ * @param {vec3} out - receiving vec3
332
+ * @param {ray3} a - source ray3
333
+ * @param {vec3} p - point to compare
334
+ * @returns {vec3} out - receiving vec3
335
+ */
336
+ ray3.getClosestPointToPoint = function (out, a, p)
337
+ {
338
+ let x = p[0] - a[0],
339
+ y = p[1] - a[1],
340
+ z = p[2] - a[2];
341
+
342
+ let dirDist = x * a[3] + y * a[4] + z * a[5];
343
+
344
+ if (dirDist < 0)
345
+ {
346
+ out[0] = a[0];
347
+ out[1] = a[1];
348
+ out[2] = a[2];
349
+ }
350
+ else
351
+ {
352
+ ray3.get(out, a, dirDist);
353
+ }
354
+
355
+ return out;
356
+ };
357
+
358
+ /**
359
+ * Sets a vec3 with the intersection point of a ray3 and boxes' components
360
+ * - Returns null if there was no intersection, or the receiving vec3 if there was
361
+ *
362
+ * @author three.js authors (converted)
363
+ * @param {vec3} out - receiving vec3
364
+ * @param {ray3} a - source ray3
365
+ * @param {vec3} min - box min bounds
366
+ * @param {vec3} max - box max bounds
367
+ * @returns {(null|vec3)} [out] - null or receiving vec3
368
+ */
369
+ ray3.getIntersectBounds = function (out, a, min, max)
370
+ {
371
+ let tMin, tMax, tyMin, tyMax, tzMin, tzMax;
372
+
373
+ let invDirX = 1 / a[3],
374
+ invDirY = 1 / a[4],
375
+ invDirZ = 1 / a[5];
376
+
377
+ if (invDirX >= 0)
378
+ {
379
+ tMin = (min[0] - a[0]) * invDirX;
380
+ tMax = (max[0] - a[0]) * invDirX;
381
+ }
382
+ else
383
+ {
384
+ tMin = (max[0] - a[0]) * invDirX;
385
+ tMax = (min[0] - a[0]) * invDirX;
386
+ }
387
+
388
+ if (invDirY >= 0)
389
+ {
390
+ tyMin = (min[1] - a[1]) * invDirY;
391
+ tyMax = (max[1] - a[1]) * invDirY;
392
+ }
393
+ else
394
+ {
395
+ tyMin = (max[1] - a[1]) * invDirY;
396
+ tyMax = (min[1] - a[1]) * invDirY;
397
+ }
398
+
399
+ if ((tMin > tyMax) || (tyMin > tMax)) return null;
400
+
401
+ if (tyMin > tMin || tMin !== tMin) tMin = tyMin;
402
+ if (tyMax < tMax || tMax !== tMax) tMax = tyMax;
403
+
404
+ if (invDirZ >= 0)
405
+ {
406
+ tzMin = (min[2] - a[2]) * invDirZ;
407
+ tzMax = (max[2] - a[2]) * invDirZ;
408
+ }
409
+ else
410
+ {
411
+ tzMin = (max[2] - a[2]) * invDirZ;
412
+ tzMax = (min[2] - a[2]) * invDirZ;
413
+ }
414
+
415
+ if ((tMin > tzMax) || (tzMin > tMax)) return null;
416
+
417
+ if (tzMin > tMin || tMin !== tMin) tMin = tzMin;
418
+ if (tzMax < tMax || tMax !== tMax) tMax = tzMax;
419
+ if (tMax < 0) return null;
420
+
421
+ return ray3.get(out, a, tMin >= 0 ? tMin : tMax);
422
+ };
423
+
424
+ /**
425
+ * Sets a vec3 with the intersection point of a ray3 and boxes" components
426
+ * - Returns null if there was no intersection, or the receiving vec3 if there was
427
+ * TODO: Flip internals of getIntersectBounds with this as it will be called more often
428
+ *
429
+ * @param {vec3} out
430
+ * @param {ray3} ray
431
+ * @param {box3|Float32Array} box
432
+ * @returns {null|vec3}
433
+ */
434
+ ray3.getIntersectBox3 = (function ()
435
+ {
436
+ let vec3_0, vec3_1;
437
+
438
+ return function (out, a, b)
439
+ {
440
+ if (!vec3_0)
441
+ {
442
+ vec3_0 = vec3.create();
443
+ vec3_1 = vec3.create();
444
+ }
445
+
446
+ box3.getMin(vec3_0, b);
447
+ box3.getMax(vec3_1, b);
448
+
449
+ return ray3.getIntersectBounds(out, a, vec3_0, vec3_1);
450
+ };
451
+ })();
452
+
453
+ /**
454
+ * Sets a vec3 with the intersection point of a ray3 and a triangle"s components
455
+ * - Returns null if there was no intersection, or the receiving vec3 if there was
456
+ * @TODO: Flip internals with getIntersectVertices as this will be called more often
457
+ *
458
+ * @param {vec3} out - receiving vec3
459
+ * @param {ray3} a - source ray3
460
+ * @param {tri3} f - The tri3 to intersect
461
+ * @param {boolean} bfc - enables/ disables back face culling
462
+ * @returns {(null|vec3)} [out] - null or receiving vec3
463
+ */
464
+ ray3.getIntersectTri3 = (function ()
465
+ {
466
+ let vec3_0, vec3_1, vec3_2;
467
+
468
+ return function (out, a, f, bfc)
469
+ {
470
+ if (!vec3_0)
471
+ {
472
+ vec3_0 = vec3.create();
473
+ vec3_1 = vec3.create();
474
+ vec3_2 = vec3.create();
475
+ }
476
+
477
+ tri3.getV1(vec3_0, f);
478
+ tri3.getV2(vec3_1, f);
479
+ tri3.getV3(vec3_2, f);
480
+
481
+ return ray3.getIntersectVertices(out, a, vec3_0, vec3_1, vec3_2, bfc);
482
+ };
483
+ })();
484
+
485
+
486
+ /**
487
+ * Sets a vec3 with the intersection point of a ray3 and a triangle"s components
488
+ * - Returns null if there was no intersection, or the receiving vec3 if there was
489
+ *
490
+ * @author three.js authors (converted)
491
+ * @param {vec3} out - receiving vec3
492
+ * @param {ray3} a - source ray3
493
+ * @param {vec3} vertA - first triangle vertex position
494
+ * @param {vec3} vertB - second triangle vertex position
495
+ * @param {vec3} vertC - third triangle vertex position
496
+ * @param {boolean} bfc - enables/ disables back face culling
497
+ * @returns {(null|vec3)} [out] - null or receiving vec3
498
+ */
499
+ ray3.getIntersectVertices = (function ()
500
+ {
501
+ let vec3_0, vec3_1, vec3_2, vec3_3, vec3_4, vec3_5;
502
+
503
+ return function (out, a, vertA, vertB, vertC, bfc)
504
+ {
505
+ if (!vec3_0)
506
+ {
507
+ vec3_0 = vec3.create();
508
+ vec3_1 = vec3.create();
509
+ vec3_2 = vec3.create();
510
+ vec3_3 = vec3.create();
511
+ vec3_4 = vec3.create();
512
+ vec3_5 = vec3.create();
513
+ }
514
+
515
+ let o = ray3.getOrigin(vec3_4, a);
516
+ let d = ray3.getDirection(vec3_5, a);
517
+
518
+ let diff = vec3.subtract(vec3_0, o, vertA);
519
+ let e1 = vec3.subtract(vec3_1, vertB, vertA);
520
+ let e2 = vec3.subtract(vec3_2, vertC, vertA);
521
+ let n = vec3.cross(vec3_3, e1, e2);
522
+ let DdN = vec3.dot(d, n);
523
+ let sign;
524
+
525
+ if (DdN > 0)
526
+ {
527
+ if (bfc) return null;
528
+ sign = 1;
529
+ }
530
+ else if (DdN < 0)
531
+ {
532
+ sign = -1;
533
+ DdN = -DdN;
534
+ }
535
+ else return null;
536
+
537
+ vec3.cross(e2, diff, e2);
538
+ let b1 = sign * vec3.dot(d, e2);
539
+ if (b1 < 0) return null;
540
+
541
+ vec3.cross(e1, e1, diff);
542
+ let b2 = sign * vec3.dot(d, e1);
543
+ if (b2 < 0) return null;
544
+ if (b1 + b2 > DdN) return null;
545
+
546
+ let QdN = -sign * vec3.dot(diff, n);
547
+ if (QdN < 0) return null;
548
+
549
+ return ray3.get(out, a, QdN / DdN);
550
+ };
551
+ })();
552
+
553
+ /**
554
+ * Sets a vec3 with the intersection point of a ray3 and a plane"s components
555
+ * - Returns null if there was no intersection, or the receiving vec3 if there was
556
+ *
557
+ * @param {vec3} out - receiving vec3
558
+ * @param {ray3} a - source ray3
559
+ * @param {vec3} n - plane normal
560
+ * @param {number} c - plane constant
561
+ * @returns {(null|vec3)} vecOut - null or receiving vec3
562
+ */
563
+ ray3.getIntersectNormalConstant = function (out, a, n, c)
564
+ {
565
+ let t = ray3.distanceNormalConstant(a, n, c);
566
+ return t !== null ? ray3.get(out, a, t) : null;
567
+ };
568
+
569
+ /**
570
+ * Sets a vec3 with the intersection point of a ray3 and a Float32Array(4) Plane
571
+ * - Returns null if there was no intersection, or the receiving vec3 if there was
572
+ *
573
+ * @param {vec3} out - receiving vec3
574
+ * @param {ray3} a - source ray3
575
+ * @param {(pln|Float32Array)} p - plane to intersect
576
+ * @returns {(null|vec3)} [out] - null or receiving vec3
577
+ */
578
+ ray3.getIntersectPln = function (out, a, p)
579
+ {
580
+ let t = ray3.distancePln(a, p);
581
+ return t !== null ? ray3.get(out, a, t) : null;
582
+ };
583
+
584
+ /**
585
+ * Sets a vec3 with the intersection point of a ray3 and a sphere"s components
586
+ * - Returns null if there was no intersection, or the receiving vec3 if there was
587
+ *
588
+ * @author three.js authors (converted)
589
+ * @param {vec3} out - receiving vec3
590
+ * @param {ray3} a - source ray3
591
+ * @param {vec3} p - sphere position
592
+ * @param {number} r - sphere radius
593
+ * @returns {(null|vec3)} [out] - null or receiving vec3
594
+ */
595
+ ray3.getIntersectPositionRadius = (function ()
596
+ {
597
+ let sph3_0;
598
+
599
+ return function (out, a, p, r)
600
+ {
601
+ if (!sph3_0) sph3_0 = sph3.create();
602
+ sph3.from(sph3_0, p, r);
603
+ return ray3.getIntersectSph3(out, a, sph3_0);
604
+ };
605
+ })();
606
+
607
+ /**
608
+ * Sets a vec3 with the intersection point of a ray3 and a Float32Array(4) sphere
609
+ * - Returns null if there was no intersection, or the receiving vec3 if there was
610
+ *
611
+ * @author three.js authors (converted)
612
+ * @param {vec3} out - receiving vec3
613
+ * @param {ray3} a - source ray3
614
+ * @param {sph3} s - sphere
615
+ * @returns {(null|vec3)} [out] - null or receiving vec3
616
+ */
617
+ ray3.getIntersectSph3 = function (out, a, s)
618
+ {
619
+ let x = s[0] - a[0],
620
+ y = s[1] - a[1],
621
+ z = s[2] - a[2],
622
+ r2 = s[3] * s[3];
623
+
624
+ let tca = x * a[3] + y * a[4] + z * a[5];
625
+ let d2 = (x * x + y * y + z * z) - tca * tca;
626
+
627
+ if (d2 > r2) return null;
628
+
629
+ let thc = Math.sqrt(r2 - d2);
630
+ let t0 = tca - thc;
631
+ let t1 = tca + thc;
632
+
633
+ if (t0 < 0 && t1 < 0) return null;
634
+ if (t0 < 0) return ray3.get(out, a, t1);
635
+ return ray3.get(out, a, t0);
636
+ };
637
+
638
+
639
+ /**
640
+ * Gets the origin component of a ray3
641
+ *
642
+ * @param {vec3} out
643
+ * @param {ray3} a
644
+ * @returns {vec3} out
645
+ */
646
+ ray3.getOrigin = box3.getMin;
647
+
648
+ /**
649
+ * Checks for ray3 intersection with a Float32Array(6) box
650
+ * TODO: Replace internals with intersectsBounds as this will get called more often
651
+ * @param {ray3} a - ray3
652
+ * @param {(box3|Float32Array)} b - box
653
+ * @returns {boolean} - true if intersection occurs
654
+ */
655
+ ray3.intersectsBox3 = (function ()
656
+ {
657
+ let vec3_0;
658
+ return function (a, b)
659
+ {
660
+ if (!vec3_0) vec3_0 = vec3.create();
661
+ return ray3.vec3_0 = ray3.getIntersectBox3(vec3_0, a, b) !== null;
662
+ };
663
+ })();
664
+
665
+ /**
666
+ * Checks for ray3 intersection with bounds
667
+ *
668
+ * @param {ray3} a - ray3
669
+ * @param {vec3} min - box min bounds
670
+ * @param {vec3} max - box max bounds
671
+ * @returns {boolean} - true if intersection occurs
672
+ */
673
+ ray3.intersectsBounds = (function ()
674
+ {
675
+ let vec3_0;
676
+ return function intersectsBounds(a, min, max)
677
+ {
678
+ if (!vec3_0) vec3_0 = vec3.create();
679
+ return ray3.getIntersectBounds(vec3_0, a, min, max) !== null;
680
+ };
681
+ })();
682
+
683
+ /**
684
+ * Checks for ray3 intersection with a plane"s components
685
+ *
686
+ * @param {ray3} a - source ray3
687
+ * @param {vec3} n - plane normal
688
+ * @param {number} c - plane constant
689
+ * @returns {boolean} - true if intersection occurs
690
+ */
691
+ ray3.intersectsNormalConstant = function (a, n, c)
692
+ {
693
+ let dist = (a[0] * n[0] + a[1] * n[1] + a[2] * n[2]) + c;
694
+ return dist === 0 ? true : ((n[0] * a[3] + n[1] * a[4] + n[2] * a[5]) * dist < 0);
695
+ };
696
+
697
+ /**
698
+ * Checks for ray3 intersection with a Float32Array(4) plane
699
+ *
700
+ * @param {ray3} a - source ray3
701
+ * @param {pln} p - plane
702
+ * @returns {boolean} - true if intersection occurs
703
+ */
704
+ ray3.intersectsPln = function (a, p)
705
+ {
706
+ let dist = (a[0] * p[0] + a[1] * p[1] + a[2] * p[2]) + p[3];
707
+ return (dist === 0) ? true : ((p[0] * a[3] + p[1] * a[4] + p[2] * a[5]) * dist < 0);
708
+ };
709
+
710
+ /**
711
+ * Checks for ray3 intersection with a sphere"s components
712
+ *
713
+ * @param {ray3} a - source ray3
714
+ * @param {vec3} p - sphere position
715
+ * @param {number} r - sphere radius
716
+ * @returns {boolean} - true if intersection occurs
717
+ */
718
+ ray3.intersectsPositionRadius = function (a, p, r)
719
+ {
720
+ return ray3.distance(a, p) <= r;
721
+ };
722
+
723
+ /**
724
+ * Checks for ray3 intersection with a Float32Array(4) Sphere
725
+ *
726
+ * @param {ray3} a - source ray3
727
+ * @param {sph3|Float32Array} s - sphere
728
+ * @returns {boolean} - true if intersection occurs
729
+ */
730
+ ray3.intersectsSph3 = function (a, s)
731
+ {
732
+ return ray3.distance(a, s) <= s[3];
733
+ };
734
+
735
+ /**
736
+ * Sets the direction of a ray3 to be looking at a specific point
737
+ *
738
+ * @param {ray3} out - receiving ray3
739
+ * @param {vec3} a - source ray3
740
+ * @param {vec3} p - point to look at
741
+ * @returns {ray3} out - receiving ray3
742
+ */
743
+ ray3.lookAt = function (out, a, p)
744
+ {
745
+ out[0] = a[0];
746
+ out[1] = a[1];
747
+ out[2] = a[2];
748
+ out[3] = p[0] - a[0];
749
+ out[4] = p[1] - a[1];
750
+ out[5] = p[2] - a[2];
751
+ return ray3.normalize(out, out);
752
+ };
753
+
754
+ /**
755
+ * Sets a ray3 from the results of normalizing another
756
+ *
757
+ * @param {ray3} out - receiving ray3
758
+ * @param {ray3} a - source ray3
759
+ * @returns {ray3} out - receiving ray3
760
+ */
761
+ ray3.normalize = function (out, a)
762
+ {
763
+ if (out !== a)
764
+ {
765
+ out[0] = a[0];
766
+ out[1] = a[1];
767
+ out[2] = a[2];
768
+ }
769
+
770
+ let x = a[3],
771
+ y = a[4],
772
+ z = a[5];
773
+
774
+ // Normalize the direction
775
+ let len = x * x + y * y + z * z;
776
+ if (len > 0)
777
+ {
778
+ len = 1 / Math.sqrt(len);
779
+ out[3] = x * len;
780
+ out[4] = y * len;
781
+ out[5] = z * len;
782
+ }
783
+ else
784
+ {
785
+ out[1] = 0;
786
+ out[2] = 0;
787
+ out[3] = 0;
788
+ throw new Error("Normalization error");
789
+ }
790
+
791
+ return out;
792
+ };
793
+
794
+ /**
795
+ * Shifts the origin of a ray3 to be further down it"s direction
796
+ *
797
+ * @param {ray3} out - receiving ray3
798
+ * @param {ray3} a - source ray3
799
+ * @param {number} t - distance along the ray3
800
+ * @returns {ray3} - receiving ray3
801
+ */
802
+ ray3.recast = function (out, a, t)
803
+ {
804
+ out[0] = a[0] + (a[3] * t);
805
+ out[1] = a[1] + (a[4] * t);
806
+ out[2] = a[2] + (a[5] * t);
807
+ out[3] = a[3];
808
+ out[4] = a[4];
809
+ out[5] = a[5];
810
+ return out;
811
+ };
812
+
813
+ /**
814
+ * Sets a ray3 from values
815
+ *
816
+ * @param {ray3} out
817
+ * @param {vec3} startProp
818
+ * @param {vec3} endProp
819
+ * @returns {ray3} out
820
+ */
821
+ ray3.set = box3.set;
822
+
823
+ /**
824
+ * Ray3 generic sorting
825
+ *
826
+ * @param {{}} a
827
+ * @param {number} a.distance
828
+ * @param {{}} b
829
+ * @param {number} b.distance
830
+ * @returns {number}
831
+ */
832
+ ray3.SORT = function (a, b)
833
+ {
834
+ return a.distance - b.distance;
835
+ };
836
+
837
+ /**
838
+ * Gets the squared distance from a ray3 to a point
839
+ *
840
+ * @author three.js authors (converted)
841
+ * @param {ray3} a - source ray3
842
+ * @param {vec3} p - point to measure distance to
843
+ * @returns {number} - squared distance
844
+ */
845
+ ray3.squaredDistance = (function ()
846
+ {
847
+ let vec3_0, vec3_1;
848
+ return function distanceSquared(a, p)
849
+ {
850
+ if (!vec3_0)
851
+ {
852
+ vec3_0 = vec3.create();
853
+ vec3_1 = vec3.create();
854
+ }
855
+
856
+ vec3_0[0] = p[0] - a[0];
857
+ vec3_0[1] = p[1] - a[1];
858
+ vec3_0[2] = p[2] - a[2];
859
+
860
+ let dirDist = vec3_0[0] * a[3] + vec3_0[1] * a[4] + vec3_0[2] * a[5];
861
+ if (dirDist < 0)
862
+ {
863
+ ray3.getOrigin(vec3_1, a);
864
+ return vec3.squaredDistance(vec3_1, p); // could just pass in the ray3
865
+ }
866
+
867
+ ray3.get(vec3_0, a, dirDist);
868
+ return vec3.squaredDistance(vec3_0, p);
869
+ };
870
+ })();
871
+
872
+ /**
873
+ * Sets an array at at optional offset from a ray3
874
+ *
875
+ * @param {ray3} a
876
+ * @param {Array} arr
877
+ * @param {number} [index]
878
+ * @returns {ray3} a
879
+ */
880
+ ray3.toArray = box3.toArray;
881
+
882
+ /**
883
+ * Sets origin and direction vectors from a ray3
884
+ *
885
+ * @param {ray3} a
886
+ * @param {vec3} origin
887
+ * @param {vec3} direction
888
+ * @returns {ray3} a
889
+ */
890
+ ray3.toOriginDirection = function (a, origin, direction)
891
+ {
892
+ origin[0] = a[0];
893
+ origin[1] = a[1];
894
+ origin[2] = a[2];
895
+ direction[0] = a[3];
896
+ direction[1] = a[4];
897
+ direction[2] = a[5];
898
+ return a;
899
+ };
900
+
901
+ /**
902
+ * Transforms a ray3 by a mat4
903
+ *
904
+ * @param {ray3} out - receiving ray3
905
+ * @param {vec3} a - ray3 to transform
906
+ * @param {mat4} m - matrix to transform by
907
+ */
908
+ ray3.transformMat4 = function (out, a, m)
909
+ {
910
+ let oX = a[0],
911
+ oY = a[1],
912
+ oZ = a[2],
913
+ dX = a[3] + a[0],
914
+ dY = a[4] + a[1],
915
+ dZ = a[5] + a[2];
916
+
917
+ // Calculate w
918
+ let oW = (m[3] * oX + m[7] * oY + m[11] * oZ + m[15]) || 1.0,
919
+ dW = (m[3] * dX + m[7] * dY + m[11] * dZ + m[15]) || 1.0;
920
+ // Transform origin
921
+ out[0] = (m[0] * oX + m[4] * oY + m[8] * oZ + m[12]) / oW;
922
+ out[1] = (m[1] * oX + m[5] * oY + m[9] * oZ + m[13]) / oW;
923
+ out[2] = (m[2] * oX + m[6] * oY + m[10] * oZ + m[14]) / oW;
924
+ // Transform direction
925
+ out[3] = (m[0] * dX + m[4] * dY + m[8] * dZ + m[12]) / dW - out[0];
926
+ out[4] = (m[1] * dX + m[5] * dY + m[9] * dZ + m[13]) / dW - out[1];
927
+ out[5] = (m[2] * dX + m[6] * dY + m[10] * dZ + m[14]) / dW - out[2];
928
+ // Normalize direction
929
+ return ray3.normalize(out, out);
930
+ };
931
+
932
+ /**
933
+ * Translates a ray3
934
+ *
935
+ * @param {ray3} out
936
+ * @param {ray3} a
937
+ * @param {vec3} v
938
+ * @returns {ray3} out
939
+ */
940
+ ray3.translate = function (out, a, v)
941
+ {
942
+ out[0] = a[0] + v[0];
943
+ out[1] = a[1] + v[1];
944
+ out[2] = a[2] + v[2];
945
+ out[3] = a[3];
946
+ out[4] = a[4];
947
+ out[5] = a[5];
948
+ return out;
949
+ };
950
+
951
+ let viewPort;
952
+
953
+ /**
954
+ * Gets a ray3 from an element event
955
+ * @param {ray3} ray
956
+ * @param {mat4} viewProjectionInverse
957
+ * @param {event} event
958
+ * @param {vec2} [mouse]
959
+ * @param {vec2} [pixel]
960
+ * @param {vec2} [css]
961
+ * @returns {ray3}
962
+ */
963
+ ray3.fromEvent = function (ray, viewProjectionInverse, event, mouse, pixel, css)
964
+ {
965
+ if (!viewPort) viewPort = pln.create();
966
+
967
+ const
968
+ el = event.target || event.srcElement,
969
+ rect = el.getBoundingClientRect(),
970
+ mX = event.clientX,
971
+ mY = event.clientY,
972
+ cX = mX - rect.left,
973
+ cY = mY - rect.top,
974
+ pX = cX * el.width / el.clientWidth,
975
+ pY = el.height - cY * el.height / el.clientHeight - 1;
976
+
977
+ // Should this be a param?
978
+ viewPort[0] = 0;
979
+ viewPort[1] = 0;
980
+ viewPort[2] = el.width;
981
+ viewPort[3] = el.height;
982
+
983
+ if (mouse)
984
+ {
985
+ mouse[0] = mX;
986
+ mouse[1] = mY;
987
+ }
988
+
989
+ if (pixel)
990
+ {
991
+ pixel[0] = pX;
992
+ pixel[1] = pY;
993
+ }
994
+
995
+ if (css)
996
+ {
997
+ css[0] = cX;
998
+ css[1] = cY;
999
+ }
1000
+
1001
+ return ray3.unproject(ray, [ pX, pY ], viewProjectionInverse, viewPort);
1002
+ };
1003
+
1004
+ export const {
1005
+ alloc,
1006
+ unalloc,
1007
+ $origin,
1008
+ $direction,
1009
+ clone,
1010
+ copy,
1011
+ copyOrigin,
1012
+ copyDirection,
1013
+ create,
1014
+ distance,
1015
+ distanceNormalConstant,
1016
+ distancePln,
1017
+ equals,
1018
+ equalsOriginDestination,
1019
+ exactEquals,
1020
+ exactEqualsOriginDestination,
1021
+ from,
1022
+ fromArray,
1023
+ fromStartEnd,
1024
+ fromMat4,
1025
+ fromPerspective,
1026
+ unproject,
1027
+ get,
1028
+ getDirection,
1029
+ getClosestPointToPoint,
1030
+ getIntersectBounds,
1031
+ getIntersectBox3,
1032
+ getIntersectTri3,
1033
+ getIntersectVertices,
1034
+ getIntersectNormalConstant,
1035
+ getIntersectPln,
1036
+ getIntersectPositionRadius,
1037
+ getIntersectSph3,
1038
+ getOrigin,
1039
+ intersectsBox3,
1040
+ intersectsBounds,
1041
+ intersectsNormalConstant,
1042
+ intersectsPln,
1043
+ intersectsPositionRadius,
1044
+ intersectsSph3,
1045
+ lookAt,
1046
+ normalize,
1047
+ recast,
1048
+ set,
1049
+ SORT,
1050
+ squaredDistance,
1051
+ toArray,
1052
+ toOriginDirection,
1053
+ transformMat4,
1054
+ translate,
1055
+ fromEvent
1056
+ } = ray3;