@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/tri3.js ADDED
@@ -0,0 +1,650 @@
1
+ import { vec3 } from "./vec3.js";
2
+ import { mat3 } from "./mat3.js";
3
+ import { pln } from "./pln.js";
4
+ import { lne3 } from "./lne3.js";
5
+ import { pool } from "./pool.js";
6
+
7
+ /**
8
+ * 3d Triangle
9
+ *
10
+ * @typedef {Float32Array} tri3
11
+ */
12
+
13
+ export const tri3 = {};
14
+
15
+ /**
16
+ * Allocates a pooled tri3
17
+ * @returns {Float32Array|tri3}
18
+ */
19
+ tri3.alloc = function()
20
+ {
21
+ return pool.allocF32(9);
22
+ };
23
+
24
+ /**
25
+ * Unallocates a pooled tri3
26
+ * @param {tri3|Float32Array} a
27
+ */
28
+ tri3.unalloc = function(a)
29
+ {
30
+ pool.freeType(a);
31
+ };
32
+
33
+ /**
34
+ * Gets a subarray of a tri3's first vertex
35
+ *
36
+ * @param {tri3} a
37
+ * @returns {vec3}
38
+ */
39
+ tri3.$v1 = lne3.$start;
40
+
41
+ /**
42
+ * Gets a subarray of a tri3's second vertex
43
+ *
44
+ * @param {tri3} a
45
+ * @returns {vec3}
46
+ */
47
+ tri3.$v2 = lne3.$end;
48
+
49
+ /**
50
+ * Gets a subarray of a tri3's third vertex
51
+ *
52
+ * @param {tri3} a
53
+ * @returns {vec3}
54
+ */
55
+ tri3.$v3 = function(a)
56
+ {
57
+ return a.subarray(6, 9);
58
+ };
59
+
60
+ /**
61
+ * Gets the area of a triangle
62
+ *
63
+ * @param {tri3} a
64
+ * @returns {number}
65
+ */
66
+ tri3.area = function(a)
67
+ {
68
+ let ax = a[6] - a[3],
69
+ ay = a[7] - a[4],
70
+ az = a[8] - a[5],
71
+ bx = a[0] - a[3],
72
+ by = a[1] - a[4],
73
+ bz = a[2] - a[5];
74
+ // Cross product
75
+ let x = ax * bz - az * by,
76
+ y = az * bx - ax * bz,
77
+ z = ax * by - ay * bx;
78
+ // Return half length
79
+ return Math.sqrt(x * x + y * y + z * z) * 0.5;
80
+ };
81
+
82
+ /**
83
+ * Creates a tri3
84
+ *
85
+ * @returns {tri3}
86
+ */
87
+ tri3.create = function()
88
+ {
89
+ let out = new Float32Array(9);
90
+ out[0] = 0;
91
+ out[1] = 0;
92
+ out[2] = 0;
93
+ out[3] = 0;
94
+ out[4] = 0;
95
+ out[5] = 0;
96
+ out[6] = 0;
97
+ out[7] = 0;
98
+ out[8] = 0;
99
+ return out;
100
+ };
101
+
102
+ /**
103
+ * Clones a tri3
104
+ *
105
+ * @param {tri3} a
106
+ * @returns {tri3}
107
+ */
108
+ tri3.clone = mat3.clone;
109
+
110
+ /**
111
+ * Checks if a tri3 contains a point
112
+ *
113
+ * @param {tri3} a
114
+ * @param {vec3} point
115
+ * @returns {boolean}
116
+ */
117
+ tri3.contains = (function()
118
+ {
119
+ let vec3_0;
120
+ return function(a, point)
121
+ {
122
+ if (!vec3_0) vec3_0 = vec3.create();
123
+ tri3.getBaryCentricCoordinates(vec3_0, a, point);
124
+ return (vec3_0[0] >= 0) && (vec3_0[1] >= 0) && ((vec3_0[0] + vec3_0[1]) <= 1);
125
+ };
126
+ })();
127
+
128
+ /**
129
+ * Copies a tri3
130
+ *
131
+ * @param {tri3} a
132
+ * @param {tri3} b
133
+ * @returns {tri3} a
134
+ */
135
+ tri3.copy = mat3.copy;
136
+
137
+ /**
138
+ * Sets a tri3 from vertices
139
+ *
140
+ * @param {tri3} out
141
+ * @param {vec3} v1
142
+ * @param {vec3} v2
143
+ * @param {vec3} v3
144
+ * @returns {tri3} out
145
+ */
146
+ tri3.fromVertices = function(out, v1, v2, v3)
147
+ {
148
+ out[0] = v1[0];
149
+ out[1] = v1[1];
150
+ out[2] = v1[2];
151
+ out[3] = v2[0];
152
+ out[4] = v2[1];
153
+ out[5] = v2[2];
154
+ out[6] = v3[0];
155
+ out[7] = v3[1];
156
+ out[8] = v3[2];
157
+ return out;
158
+ };
159
+
160
+ /**
161
+ * Sets a tri3 from an array at an option offset
162
+ *
163
+ * @param {tri3} out
164
+ * @param {Array} arr
165
+ * @param {number} [offset=0]
166
+ * @returns {tri3} out
167
+ */
168
+ tri3.fromArray = mat3.fromArray;
169
+
170
+ /**
171
+ * Gets bary centric coordinates
172
+ *
173
+ * @author three.js (converted)
174
+ * @param {vec3} out
175
+ * @param {tri3} a
176
+ * @param {vec3} point
177
+ * @returns {tri3} out
178
+ */
179
+ tri3.getBaryCentricCoordinates = function(out, a, point)
180
+ {
181
+ let ax = a[6] - a[0],
182
+ ay = a[7] - a[1],
183
+ az = a[8] - a[2],
184
+
185
+ bx = a[3] - a[0],
186
+ by = a[4] - a[1],
187
+ bz = a[5] - a[2],
188
+
189
+ cx = point[0] - a[0],
190
+ cy = point[1] - a[1],
191
+ cz = point[2] - a[2];
192
+
193
+ let dot00 = ax * ax + ay * ay + az * az,
194
+ dot01 = ax * bx + ay * by + az * bz,
195
+ dot02 = ax * cx + ay * cy + az * cz,
196
+ dot11 = bx * bx + by * by + bz * bz,
197
+ dot12 = bx * cx + by * cy + bz * cz;
198
+
199
+ let denom = (dot00 * dot11 - dot01 * dot01);
200
+
201
+ if (denom === 0)
202
+ {
203
+ out[0] = -2;
204
+ out[1] = -1;
205
+ out[2] = -1;
206
+ throw new Error("Denominator error");
207
+ }
208
+ else
209
+ {
210
+ let invDenom = 1 / denom;
211
+ let u = (dot11 * dot02 - dot01 * dot12) * invDenom;
212
+ let v = (dot00 * dot12 - dot01 * dot02) * invDenom;
213
+ out[0] = 1 - u - v;
214
+ out[1] = v;
215
+ out[2] = u;
216
+ }
217
+ return out;
218
+ };
219
+
220
+ /**
221
+ *
222
+ * @author three.js (converted)
223
+ * @param {lne3} out
224
+ * @param {tri3} a
225
+ * @param {vec3} point
226
+ * @returns {*}
227
+ */
228
+ tri3.getClosestEdgeToPoint = (function()
229
+ {
230
+ let v0, v1, edgeList;
231
+
232
+ return function getClosestEdgeToPoint(out, a, point, debug)
233
+ {
234
+ if (!v0)
235
+ {
236
+ v0 = vec3.create();
237
+ v1 = vec3.create();
238
+ edgeList = [ lne3.create(), lne3.create(), lne3.create() ];
239
+ }
240
+
241
+ // Get the closest point on the triangle to the supplied point
242
+ let closestPointOnTriangle = tri3.getClosestPointToPoint(v0, a, point);
243
+
244
+ // Convert the triangle's vertices to edges
245
+ lne3.set(edgeList[0], a[0], a[1], a[2], a[3], a[4], a[5]); // vert a - vert b
246
+ lne3.set(edgeList[1], a[3], a[4], a[5], a[6], a[7], a[8]); // vert b - vert c
247
+ lne3.set(edgeList[2], a[6], a[7], a[8], a[0], a[1], a[2]); // vert c - vert a
248
+
249
+ let minDistance = Infinity,
250
+ edgeIndex;
251
+
252
+ for (let i = 0; i < edgeList.length; i++)
253
+ {
254
+ // Get the closest point on the triangles edge to the closest point on the triangle to the supplied point
255
+ let closestPointOnLine = lne3.getClosestPointToPoint(v1, edgeList[i], closestPointOnTriangle, true);
256
+ let distance = vec3.squaredDistance(closestPointOnLine, closestPointOnTriangle);
257
+ if (distance < minDistance)
258
+ {
259
+ minDistance = distance;
260
+ out[0] = edgeList[i][0];
261
+ out[1] = edgeList[i][1];
262
+ out[2] = edgeList[i][2];
263
+ out[3] = edgeList[i][3];
264
+ out[4] = edgeList[i][4];
265
+ out[5] = edgeList[i][5];
266
+ edgeIndex = i;
267
+ }
268
+ }
269
+
270
+ // Temporary
271
+ if (debug)
272
+ {
273
+ switch(edgeIndex)
274
+ {
275
+ case 0:
276
+ debug.edgeStart = 0;
277
+ debug.edgeEnd = 1;
278
+ break;
279
+
280
+ case 1:
281
+ debug.edgeStart = 1;
282
+ debug.edgeEnd = 2;
283
+ break;
284
+
285
+ default:
286
+ debug.edgeStart = 2;
287
+ debug.edgeEnd = 0;
288
+ break;
289
+ }
290
+ }
291
+
292
+ return out;
293
+ };
294
+ })();
295
+
296
+ /**
297
+ * Gets the closest point on a triangle to another point
298
+ *
299
+ * @author three.js (converted)
300
+ * @param {vec3} out - receiving vec3
301
+ * @param {vec3} a - tri3 to operate on
302
+ * @param {vec3} point - the point
303
+ * @returns {vec3} vecOut - receiving vec3
304
+ */
305
+ tri3.getClosestPointToPoint = (function()
306
+ {
307
+ let plane, edgeList, projectedPoint, closestPoint, vec3_0, vec3_1, vec3_2;
308
+
309
+ return function getClosestPointToPoint(out, a, point)
310
+ {
311
+ if (!plane)
312
+ {
313
+ plane = pln.create();
314
+ edgeList = [ lne3.create(), lne3.create(), lne3.create() ];
315
+ projectedPoint = vec3.create();
316
+ closestPoint = vec3.create();
317
+ vec3_0 = vec3.create();
318
+ vec3_1 = vec3.create();
319
+ vec3_2 = vec3.create();
320
+ }
321
+
322
+ // Replace with subarray tri3.v1 .v2 .v3 ?
323
+ tri3.getV1(vec3_0, a);
324
+ tri3.getV2(vec3_1, a);
325
+ tri3.getV3(vec3_2, a);
326
+
327
+ // project the point onto the plane of the triangle
328
+ pln.fromCoplanarPoints(plane, vec3_0, vec3_1, vec3_2);
329
+ pln.getProjectedPoint(projectedPoint, plane, point);
330
+
331
+ // check if the projection lies within the triangle
332
+ if (tri3.contains(a, projectedPoint) === true)
333
+ {
334
+ out[0] = projectedPoint[0];
335
+ out[1] = projectedPoint[1];
336
+ out[2] = projectedPoint[2];
337
+ }
338
+ // if not, the point falls outside the triangle.
339
+ // the result is the closest point to the triangle's edges or vertices
340
+ else
341
+ {
342
+ lne3.set(edgeList[0], a[0], a[1], a[2], a[3], a[4], a[5]);
343
+ lne3.set(edgeList[1], a[3], a[4], a[5], a[6], a[7], a[8]);
344
+ lne3.set(edgeList[2], a[6], a[7], a[8], a[0], a[1], a[2]);
345
+
346
+ let minDistance = Infinity;
347
+ for (let i = 0; i < edgeList.length; i++)
348
+ {
349
+ lne3.getClosestPointToPoint(closestPoint, edgeList[i], projectedPoint, true);
350
+ let distance = vec3.squaredDistance(projectedPoint, closestPoint);
351
+ if (distance < minDistance)
352
+ {
353
+ minDistance = distance;
354
+ out[0] = closestPoint[0];
355
+ out[1] = closestPoint[1];
356
+ out[2] = closestPoint[2];
357
+ }
358
+ }
359
+ }
360
+ return out;
361
+ };
362
+ })();
363
+
364
+ /**
365
+ * Gets the closest vertex to a given point
366
+ *
367
+ * @param {vec3} out
368
+ * @param {tri3} a
369
+ * @param {vec3} point
370
+ * @returns {vec3} out
371
+ */
372
+ tri3.getClosestVertexToPoint = (function()
373
+ {
374
+ let vec3_0, vec3_1, vec3_2;
375
+
376
+ return function(out, a, point, debug)
377
+ {
378
+ if (!vec3_0)
379
+ {
380
+ vec3_0 = vec3.create();
381
+ vec3_1 = vec3.create();
382
+ vec3_2 = vec3.create();
383
+ }
384
+
385
+ // Get the closest point on the triangle to the supplied point
386
+ tri3.getClosestPointToPoint(out, a, point);
387
+
388
+ let minDistance = Infinity,
389
+ distance,
390
+ x, y, z,
391
+ vertices = [
392
+ tri3.getV1(vec3_0, a),
393
+ tri3.getV2(vec3_1, a),
394
+ tri3.getV3(vec3_2, a)
395
+ ];
396
+
397
+ let foundIndex;
398
+ // Find the closest triangle vertex
399
+ for (let i = 0; i < vertices.length; i++)
400
+ {
401
+ distance = vec3.squaredDistance(vertices[i], out);
402
+ if (distance < minDistance)
403
+ {
404
+ minDistance = distance;
405
+ x = vertices[i][0];
406
+ y = vertices[i][1];
407
+ z = vertices[i][2];
408
+ foundIndex = i;
409
+ }
410
+ }
411
+
412
+ if (debug) debug.closest = foundIndex;
413
+
414
+ out[0] = x;
415
+ out[1] = y;
416
+ out[2] = z;
417
+ return out;
418
+ };
419
+ })();
420
+
421
+ /**
422
+ * Sets a vec3 as the midpoint of a triangle
423
+ *
424
+ * @param {vec3} out - receiving vec3
425
+ * @param {tri3} a - tri3 to get the midpoint of -
426
+ * @returns {vec3} out - receiving vec3
427
+ */
428
+ tri3.getMidpoint = function(out, a)
429
+ {
430
+ let s = 1 / 3;
431
+ out[0] = (a[0] + a[3] + a[6]) * s;
432
+ out[1] = (a[1] + a[4] + a[7]) * s;
433
+ out[2] = (a[2] + a[5] + a[8]) * s;
434
+ return out;
435
+ };
436
+
437
+ let tri3_0 = null;
438
+
439
+ /**
440
+ * Gets normal vertices
441
+ *
442
+ * @param {vec3} out
443
+ * @param {vec3} v1
444
+ * @param {vec3} v2
445
+ * @param {vec3} v3
446
+ * @return {vec3} out
447
+ */
448
+ tri3.getNormalFromVertices = function(out, v1, v2, v3)
449
+ {
450
+ if (!tri3_0) tri3_0 = tri3.create();
451
+ tri3.fromVertices(tri3_0, v1, v2, v3);
452
+ return tri3.getNormal(out, tri3_0);
453
+ };
454
+
455
+ /**
456
+ * Gets a triangle's normal
457
+ *
458
+ * @param {vec3} out
459
+ * @param {tri3} a
460
+ * @returns {vec3} out
461
+ */
462
+ tri3.getNormal = function(out, a)
463
+ {
464
+ let ax = a[6] - a[3],
465
+ ay = a[7] - a[4],
466
+ az = a[8] - a[5],
467
+ bx = a[0] - a[3],
468
+ by = a[1] - a[4],
469
+ bz = a[2] - a[5];
470
+
471
+ // Get cross product
472
+ let x = ay * bz - az * by,
473
+ y = az * bx - ax * bz,
474
+ z = ax * by - ay * bx;
475
+
476
+ // Normalize
477
+ let len = x * x + y * y + z * z;
478
+ if (len > 0)
479
+ {
480
+ len = 1 / Math.sqrt(len);
481
+ out[0] = x * len;
482
+ out[1] = y * len;
483
+ out[2] = z * len;
484
+ }
485
+ else
486
+ {
487
+ out[0] = 0;
488
+ out[1] = 0;
489
+ out[2] = 0;
490
+ throw new Error("Normalization error");
491
+ }
492
+ return out;
493
+ };
494
+
495
+ /**
496
+ * Sets a vec3 with the tri3's first vert
497
+ *
498
+ * @param {vec3} out - receiving vec3
499
+ * @param {tri3} a - source tri3
500
+ * @returns {vec3} [out] - receiving vec3
501
+ */
502
+ tri3.getV1 = lne3.getStart;
503
+
504
+ /**
505
+ * Sets a vec3 with the tri3's second vert
506
+ *
507
+ * @param {vec3} out - receiving vec3
508
+ * @param {tri3} a - source tri3
509
+ * @returns {vec3} [out] - receiving vec3
510
+ */
511
+ tri3.getV2 = lne3.getEnd;
512
+
513
+ /**
514
+ * Sets a vec3 with the tri3's third vert
515
+ *
516
+ * @param {vec3} out - receiving vec3
517
+ * @param {tri3} v - source tri3
518
+ * @returns {vec3} [out] - receiving vec3
519
+ */
520
+ tri3.getV3 = function(out, v)
521
+ {
522
+ out[0] = v[6];
523
+ out[1] = v[7];
524
+ out[2] = v[8];
525
+ return out;
526
+ };
527
+
528
+ /**
529
+ * Sets the first position of a triangle
530
+ * @param {tri3} out
531
+ * @param {vec3} v
532
+ * @returns {tri3} out
533
+ */
534
+ tri3.setV1 = lne3.setStart;
535
+
536
+ /**
537
+ * Sets the second position of a triangle
538
+ * @param {tri3} out
539
+ * @param {vec3} v
540
+ * @returns {tri3} out
541
+ */
542
+ tri3.setV2 = lne3.setEnd;
543
+
544
+ /**
545
+ * Sets the second position of a triangle
546
+ * @param {tri3} out
547
+ * @param {vec3} v
548
+ * @returns {tri3} out
549
+ */
550
+ tri3.setV3 = function(out, v)
551
+ {
552
+ out[6] = v[0];
553
+ out[7] = v[1];
554
+ out[8] = v[2];
555
+ return out;
556
+ };
557
+
558
+ /**
559
+ * Sets an array at an optional offset
560
+ *
561
+ * @param {mat3} a
562
+ * @param {Array} arr
563
+ * @param {number} [index=0]
564
+ * @returns {mat3} a
565
+ */
566
+ tri3.toArray = mat3.toArray;
567
+
568
+ /**
569
+ * Extracts the vertices of a tri3
570
+ *
571
+ * @param {tri3} a
572
+ * @param {vec3} v1
573
+ * @param {vec3} v2
574
+ * @param {vec3} v3
575
+ */
576
+ tri3.toVertices = function(a, v1, v2, v3)
577
+ {
578
+ v1[0] = a[0];
579
+ v1[1] = a[1];
580
+ v1[2] = a[2];
581
+ v2[0] = a[3];
582
+ v2[1] = a[4];
583
+ v2[2] = a[5];
584
+ v3[0] = a[6];
585
+ v3[1] = a[7];
586
+ v3[2] = a[8];
587
+ return a;
588
+ };
589
+
590
+ let vec3_0, vec3_1, vec3_2;
591
+
592
+ /**
593
+ * Transforms a tri3 by a mat4
594
+ * TODO: Optimize
595
+ * @param {tri3} out
596
+ * @param {tri3} a
597
+ * @param {mat4} m
598
+ * @return {tri3}
599
+ */
600
+ tri3.transformMat4 = function(out, a, m)
601
+ {
602
+ if (!vec3_0)
603
+ {
604
+ vec3_0 = vec3.create();
605
+ vec3_1 = vec3.create();
606
+ vec3_2 = vec3.create();
607
+ }
608
+
609
+ tri3.getV1(vec3_0, a);
610
+ tri3.getV2(vec3_1, a);
611
+ tri3.getV3(vec3_2, a);
612
+
613
+ vec3.transformMat4(vec3_0, vec3_0, m);
614
+ vec3.transformMat4(vec3_1, vec3_1, m);
615
+ vec3.transformMat4(vec3_2, vec3_2, m);
616
+
617
+ return tri3.fromVertices(out, vec3_0, vec3_1, vec3_2);
618
+ };
619
+
620
+ export const {
621
+ alloc,
622
+ unalloc,
623
+ $v1,
624
+ $v2,
625
+ $v3,
626
+ area,
627
+ create,
628
+ clone,
629
+ contains,
630
+ copy,
631
+ fromVertices,
632
+ fromArray,
633
+ getBaryCentricCoordinates,
634
+ getClosestEdgeToPoint,
635
+ getClosestPointToPoint,
636
+ getClosestVertexToPoint,
637
+ getMidpoint,
638
+ getNormalFromVertices,
639
+ getNormal,
640
+ getV1,
641
+ getV2,
642
+ getV3,
643
+ setV1,
644
+ setV2,
645
+ setV3,
646
+ toArray,
647
+ toVertices,
648
+ transformMat4
649
+ } = tri3;
650
+
package/src/utils.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Convert a nullable, scalar, or array-like value into an array.
3
+ *
4
+ * Kept local so geometry helpers do not depend on the old ccpwgl `utils`
5
+ * webpack alias.
6
+ *
7
+ * @param {any} value Value to normalize.
8
+ * @returns {Array} Normalized array.
9
+ */
10
+ export function toArray(value)
11
+ {
12
+ if (value === undefined || value === null) return [];
13
+ return Array.isArray(value) ? value : [ value ];
14
+ }
15
+