@eturnity/eturnity_maths 1.0.2

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/index.js ADDED
@@ -0,0 +1,10 @@
1
+
2
+ export * from './coords';
3
+ export * from './geo';
4
+ export * from './geometry';
5
+ export * from './matrix';
6
+ export * from './vector';
7
+ export * from './intersectionPolygon';
8
+ export * from './objects';
9
+ export * from './splitMergePolygons';
10
+
@@ -0,0 +1,623 @@
1
+
2
+ import {
3
+ getPointInsideOutline,
4
+ isInsidePolygon
5
+ } from './geometry'
6
+ import {getIntersections,
7
+ getNodeList,
8
+ getEdgeList,
9
+ getOutlineList
10
+ } from './splitMergePolygons'
11
+
12
+ // Determines whether a given polygon is self-intersecting
13
+ //is counterClockwise
14
+ export function isCounterClockwise(A, B, C) {
15
+ return (C.y - A.y) * (B.x - A.x) > (B.y - A.y) * (C.x - A.x)
16
+ }
17
+
18
+ // Determines whether line segment AB intersects line segment CD
19
+ export function doLineSegmentsIntersect(A, B, C, D) {
20
+ return (
21
+ isCounterClockwise(A, C, D) != isCounterClockwise(B, C, D) &&
22
+ isCounterClockwise(A, B, C) != isCounterClockwise(A, B, D)
23
+ )
24
+ }
25
+ export function isSelfIntersecting(outline) {
26
+ let isSelfIntersecting = false
27
+ const length = outline.length
28
+ if (length < 4) return false
29
+ //let AB and CD be two edges we are testing for intersection
30
+ for (let k = 0; k < length; k++) {
31
+ let A = outline[k]
32
+ let B = outline[(k + 1) % length]
33
+ let offset = k == 0 ? 0 : 1
34
+ for (let j = k + 2; j < length - 1 + offset; j++) {
35
+ let C = outline[j]
36
+ let D = outline[(j + 1) % length]
37
+ if (doLineSegmentsIntersect(A, B, C, D)) {
38
+ isSelfIntersecting = true
39
+ break
40
+ }
41
+ }
42
+ if (isSelfIntersecting) {
43
+ break
44
+ }
45
+ }
46
+ return isSelfIntersecting
47
+ }
48
+
49
+
50
+ export function logicOperationOnPolygons(outline1,outline2,mode='intersect')
51
+ {
52
+ const fig1 = outline1.map((p) => {
53
+ return { x: p.x, y: p.y, z: p.z }
54
+ })
55
+ fig1.push(fig1[0])
56
+ const fig2 = outline2.map((p) => {
57
+ return { x: p.x, y: p.y, z: p.z }
58
+ })
59
+ //nodeList:
60
+ let dirtyNodeList = []
61
+ fig1.forEach((p) => {dirtyNodeList.push(p)})
62
+ fig2.forEach((p) => {dirtyNodeList.push(p)})
63
+ //edgeList (just in term of indexes)
64
+ const edges=fig2.map((p,index)=>{
65
+ return {outline:[p,fig2[(index+1)%fig2.length]]}
66
+ })
67
+ let intersections = getIntersections({outline:fig1}, edges)
68
+ //2. gather all nodes+intersection in a list[[x,y],[x,y]]
69
+ const nodeList = getNodeList(intersections, edges, {outline:fig1})
70
+ //3. generate all edges not cut, those cut and those from construction polyline
71
+
72
+
73
+ const edgeList = getEdgeList(
74
+ nodeList,
75
+ intersections,
76
+ edges,
77
+ {outline:fig1},
78
+ 1
79
+ )
80
+ //4. run planar-face-discovery to get all cycles and rebuild our polygons
81
+ const outlineList = getOutlineList(nodeList, edgeList)
82
+
83
+ return filterPolygons(outlineList, fig1, fig2, mode)
84
+ }
85
+
86
+ function filterPolygons(polygons, fig1, fig2, mode) {
87
+ var filtered = []
88
+ var c1, c2
89
+ var point
90
+ var bigPolygons = removeSmallPolygons(polygons, 0.0001)
91
+ for (var i = 0; i < bigPolygons.length; i++) {
92
+ point = getPointInsideOutline(bigPolygons[i],bigPolygons.filter((p,index)=>index!=i))
93
+ c1 = isInsidePolygon(point, fig1)
94
+ c2 = isInsidePolygon(point, fig2)
95
+ if (
96
+ (mode === 'intersect' && c1 && c2) || //intersection
97
+ (mode === 'cut1' && c1 && !c2) || //fig1 - fig2
98
+ (mode === 'cut2' && !c1 && c2) || //fig2 - fig2
99
+ (mode === 'sum' && (c1 || c2))
100
+ ) {
101
+ //fig1 + fig2
102
+ //remove undefined point:
103
+ bigPolygons[i]=bigPolygons[i].filter(p=>!!p)
104
+ filtered.push(bigPolygons[i])
105
+ }
106
+ }
107
+ return filtered
108
+ }
109
+
110
+
111
+ export function intersectOutlines(outline1, outline2) {
112
+ const fig1 = outline1.map((p) => {
113
+ return { x: p.x, y: p.y, z: p.z }
114
+ })
115
+ const fig2 = outline2.map((p) => {
116
+ return { x: p.x, y: p.y, z: p.z }
117
+ })
118
+
119
+ return logicOperationOnPolygons(fig1,fig2,'intersect')
120
+
121
+ }
122
+
123
+ function alignPolygon(polygon, points) {
124
+ for (let i = 0; i < polygon.length; i++) {
125
+ for (let j = 0; j < points.length; j++) {
126
+ if (distance(polygon[i], points[j]) < 0.0001) polygon[i] = points[j]
127
+ }
128
+ }
129
+ return polygon
130
+ }
131
+
132
+ function distance(p1, p2) {
133
+ var dx = Math.abs(p1.x - p2.x)
134
+ var dy = Math.abs(p1.y - p2.y)
135
+ return Math.sqrt(dx * dx + dy * dy)
136
+ }
137
+
138
+ //check polygons for correctness
139
+ function checkPolygons(fig1, fig2) {
140
+ var figs = [fig1, fig2]
141
+ for (var i = 0; i < figs.length; i++) {
142
+ if (figs[i].length < 3) {
143
+ console.error('Polygon ' + (i + 1) + ' is invalid!')
144
+ return false
145
+ }
146
+ }
147
+ return true
148
+ }
149
+
150
+ //create array of edges of all polygons
151
+ function edgify(fig1, fig2) {
152
+ //create primary array from all edges
153
+ var primEdges = getEdges(fig1).concat(getEdges(fig2))
154
+ var secEdges = []
155
+ //check every edge
156
+ for (var i = 0; i < primEdges.length; i++) {
157
+ var points = []
158
+ //for intersection with every edge except itself
159
+ for (var j = 0; j < primEdges.length; j++) {
160
+ if (i != j) {
161
+ var interPoints = findEdgeIntersection(primEdges[i], primEdges[j])
162
+ addNewPoints(interPoints, points)
163
+ }
164
+ }
165
+ //add start and end points to intersection points
166
+ let startPoint = primEdges[i][0]
167
+ startPoint.t = 0
168
+ let endPoint = primEdges[i][1]
169
+ endPoint.t = 1
170
+ addNewPoints([startPoint, endPoint], points)
171
+ //sort all points by position on edge
172
+ points = sortPoints(points)
173
+ //break edge to parts
174
+ for (var k = 0; k < points.length - 1; k++) {
175
+ var edge = [
176
+ { x: points[k].x, y: points[k].y },
177
+ { x: points[k + 1].x, y: points[k + 1].y }
178
+ ]
179
+ // check for existanse in sec.array
180
+ if (!edgeExists(edge, secEdges)) {
181
+ //push if not exists
182
+ secEdges.push(edge)
183
+ }
184
+ }
185
+ }
186
+ return secEdges
187
+ }
188
+
189
+ function addNewPoints(newPoints, points) {
190
+ if (newPoints.length > 0) {
191
+ //check for uniqueness
192
+ for (var k = 0; k < newPoints.length; k++) {
193
+ if (!pointExists(newPoints[k], points)) {
194
+ points.push(newPoints[k])
195
+ }
196
+ }
197
+ }
198
+ }
199
+
200
+ function sortPoints(points) {
201
+ var p = points
202
+ p.sort((a, b) => {
203
+ if (a.t > b.t) return 1
204
+ if (a.t < b.t) return -1
205
+ })
206
+ return p
207
+ }
208
+
209
+ function getEdges(fig) {
210
+ var edges = []
211
+ var len = fig.length
212
+ for (var i = 0; i < len; i++) {
213
+ edges.push([
214
+ { x: fig[i % len].x, y: fig[i % len].y },
215
+ { x: fig[(i + 1) % len].x, y: fig[(i + 1) % len].y }
216
+ ])
217
+ }
218
+ return edges
219
+ }
220
+
221
+ function findEdgeIntersection(edge1, edge2) {
222
+ var x1 = edge1[0].x
223
+ var x2 = edge1[1].x
224
+ var x3 = edge2[0].x
225
+ var x4 = edge2[1].x
226
+ var y1 = edge1[0].y
227
+ var y2 = edge1[1].y
228
+ var y3 = edge2[0].y
229
+ var y4 = edge2[1].y
230
+ var nom1 = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)
231
+ var nom2 = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)
232
+ var denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
233
+ var t1 = nom1 / denom
234
+ var t2 = nom2 / denom
235
+ var interPoints = []
236
+ //1. lines are parallel or edges don't intersect
237
+ if ((denom === 0 && nom1 !== 0) || t1 <= 0 || t1 >= 1 || t2 < 0 || t2 > 1) {
238
+ return interPoints
239
+ }
240
+ //2. lines are collinear
241
+ else if (nom1 === 0 && denom === 0) {
242
+ //check if endpoints of edge2 lies on edge1
243
+ for (var i = 0; i < 2; i++) {
244
+ var classify = classifyPoint(edge2[i], edge1)
245
+ //find position of this endpoints relatively to edge1
246
+ if (classify.loc == 'ORIGIN' || classify.loc == 'DESTINATION') {
247
+ interPoints.push({ x: edge2[i].x, y: edge2[i].y, t: classify.t })
248
+ } else if (classify.loc == 'BETWEEN') {
249
+ x = +(x1 + classify.t * (x2 - x1)).toFixed(9)
250
+ y = +(y1 + classify.t * (y2 - y1)).toFixed(9)
251
+ interPoints.push({ x: x, y: y, t: classify.t })
252
+ }
253
+ }
254
+ return interPoints
255
+ }
256
+ //3. edges intersect
257
+ else {
258
+ for (var i = 0; i < 2; i++) {
259
+ var classify = classifyPoint(edge2[i], edge1)
260
+ if (classify.loc == 'ORIGIN' || classify.loc == 'DESTINATION') {
261
+ interPoints.push({ x: edge2[i].x, y: edge2[i].y, t: classify.t })
262
+ }
263
+ }
264
+ if (interPoints.length > 0) {
265
+ return interPoints
266
+ }
267
+ var x = +(x1 + t1 * (x2 - x1)).toFixed(9)
268
+ var y = +(y1 + t1 * (y2 - y1)).toFixed(9)
269
+ interPoints.push({ x: x, y: y, t: t1 })
270
+ return interPoints
271
+ }
272
+ }
273
+
274
+ function classifyPoint(p, edge) {
275
+ var ax = edge[1].x - edge[0].x
276
+ var ay = edge[1].y - edge[0].y
277
+ var bx = p.x - edge[0].x
278
+ var by = p.y - edge[0].y
279
+ var sa = ax * by - bx * ay
280
+ if (p.x === edge[0].x && p.y === edge[0].y) {
281
+ return { loc: 'ORIGIN', t: 0 }
282
+ }
283
+ if (p.x === edge[1].x && p.y === edge[1].y) {
284
+ return { loc: 'DESTINATION', t: 1 }
285
+ }
286
+ var theta =
287
+ (polarAngle([edge[1], edge[0]]) -
288
+ polarAngle([
289
+ { x: edge[1].x, y: edge[1].y },
290
+ { x: p.x, y: p.y }
291
+ ])) %
292
+ 360
293
+ if (theta < 0) {
294
+ theta = theta + 360
295
+ }
296
+ if (sa < -0.0000001) {
297
+ return { loc: 'LEFT', theta: theta }
298
+ }
299
+ if (sa > 0.0000001) {
300
+ return { loc: 'RIGHT', theta: theta }
301
+ }
302
+ if (ax * bx < 0 || ay * by < 0) {
303
+ return { loc: 'BEHIND', theta: theta }
304
+ }
305
+ if (Math.sqrt(ax * ax + ay * ay) < Math.sqrt(bx * bx + by * by)) {
306
+ return { loc: 'BEYOND', theta: theta }
307
+ }
308
+ var t
309
+ if (ax !== 0) {
310
+ t = bx / ax
311
+ } else {
312
+ t = by / ay
313
+ }
314
+ return { loc: 'BETWEEN', t: t }
315
+ }
316
+
317
+ function polarAngle(edge) {
318
+ var dx = edge[1].x - edge[0].x
319
+ var dy = edge[1].y - edge[0].y
320
+ if (dx === 0 && dy === 0) {
321
+ //console.error("Edge has zero length.");
322
+ return false
323
+ }
324
+ if (dx === 0) {
325
+ return dy > 0 ? 90 : 270
326
+ }
327
+ if (dy === 0) {
328
+ return dx > 0 ? 0 : 180
329
+ }
330
+ var theta = (Math.atan(dy / dx) * 360) / (2 * Math.PI)
331
+ if (dx > 0) {
332
+ return dy >= 0 ? theta : theta + 360
333
+ } else {
334
+ return theta + 180
335
+ }
336
+ }
337
+
338
+ function pointExists(p, points) {
339
+ if (points.length === 0) {
340
+ return false
341
+ }
342
+ for (var i = 0; i < points.length; i++) {
343
+ if (p.x === points[i].x && p.y === points[i].y) {
344
+ return true
345
+ }
346
+ }
347
+ return false
348
+ }
349
+
350
+ function edgeExists(e, edges) {
351
+ if (edges.length === 0) {
352
+ return false
353
+ }
354
+ for (var i = 0; i < edges.length; i++) {
355
+ if (equalEdges(e, edges[i])) return true
356
+ }
357
+ return false
358
+ }
359
+
360
+ function equalEdges(edge1, edge2) {
361
+ if (
362
+ (edge1[0].x === edge2[0].x &&
363
+ edge1[0].y === edge2[0].y &&
364
+ edge1[1].x === edge2[1].x &&
365
+ edge1[1].y === edge2[1].y) ||
366
+ (edge1[0].x === edge2[1].x &&
367
+ edge1[0].y === edge2[1].y &&
368
+ edge1[1].x === edge2[0].x &&
369
+ edge1[1].y === edge2[0].y)
370
+ ) {
371
+ return true
372
+ } else {
373
+ return false
374
+ }
375
+ }
376
+
377
+ function polygonate(edges) {
378
+ var polygons = []
379
+ var polygon = []
380
+ var len = edges.length
381
+ var midpoints = getMidpoints(edges)
382
+ //start from every edge and create non-selfintersecting polygons
383
+ for (var i = 0; i < len - 2; i++) {
384
+ var org = { x: edges[i][0].x, y: edges[i][0].y }
385
+ var dest = { x: edges[i][1].x, y: edges[i][1].y }
386
+ var currentEdge = i
387
+ var point
388
+ var p
389
+ var direction
390
+ var stop
391
+ //while we havn't come to the starting edge again
392
+ for (direction = 0; direction < 2; direction++) {
393
+ polygon = []
394
+ stop = false
395
+ while (polygon.length === 0 || !stop) {
396
+ //add point to polygon
397
+ polygon.push({ x: org.x, y: org.y })
398
+ point = undefined
399
+ //look for edge connected with end of current edge
400
+ for (var j = 0; j < len; j++) {
401
+ p = undefined
402
+ //except itself
403
+ if (!equalEdges(edges[j], edges[currentEdge])) {
404
+ //if some edge is connected to current edge in one endpoint
405
+ if (edges[j][0].x === dest.x && edges[j][0].y === dest.y) {
406
+ p = edges[j][1]
407
+ }
408
+ if (edges[j][1].x === dest.x && edges[j][1].y === dest.y) {
409
+ p = edges[j][0]
410
+ }
411
+ //compare it with last found connected edge for minimum angle between itself and current edge
412
+ if (p) {
413
+ var classify = classifyPoint(p, [org, dest])
414
+ //if this edge has smaller theta then last found edge update data of next edge of polygon
415
+ if (
416
+ !point ||
417
+ (classify.theta < point.theta && direction === 0) ||
418
+ (classify.theta > point.theta && direction === 1)
419
+ ) {
420
+ point = { x: p.x, y: p.y, theta: classify.theta, edge: j }
421
+ }
422
+ }
423
+ }
424
+ }
425
+ //change current edge to next edge
426
+ org.x = dest.x
427
+ org.y = dest.y
428
+ dest.x = point.x
429
+ dest.y = point.y
430
+ currentEdge = point.edge
431
+ //if we reach start edge
432
+ if (equalEdges([org, dest], edges[i])) {
433
+ stop = true
434
+ //check polygon for correctness
435
+ /*for (var k = 0; k < allPoints.length; k++) {
436
+ //if some point is inside polygon it is incorrect
437
+ if ((!pointExists(allPoints[k], polygon)) && (findPointInsidePolygon(allPoints[k], polygon))) {
438
+ polygon = false;
439
+ }
440
+ }*/
441
+ for (let k = 0; k < midpoints.length; k++) {
442
+ //if some midpoint is inside polygon (edge inside polygon) it is incorrect
443
+ if (findPointInsidePolygon(midpoints[k], polygon)) {
444
+ polygon = false
445
+ }
446
+ }
447
+ }
448
+ }
449
+ //add created polygon if it is correct and was not found before
450
+ if (polygon && !polygonExists(polygon, polygons)) {
451
+ polygons.push(polygon)
452
+ }
453
+ }
454
+ }
455
+ return polygons
456
+ }
457
+
458
+ function polygonExists(polygon, polygons) {
459
+ //if array is empty element doesn't exist in it
460
+ if (polygons.length === 0) return false
461
+ //check every polygon in array
462
+ for (var i = 0; i < polygons.length; i++) {
463
+ //if lengths are not same go to next element
464
+ if (polygon.length !== polygons[i].length) continue
465
+ //if length are same need to check
466
+ else {
467
+ //if all the points are same
468
+ for (var j = 0; j < polygon.length; j++) {
469
+ //if point is not found break forloop and go to next element
470
+ if (!pointExists(polygon[j], polygons[i])) break
471
+ //if point found
472
+ else {
473
+ //and it is last point in polygon we found polygon in array!
474
+ if (j === polygon.length - 1) return true
475
+ }
476
+ }
477
+ }
478
+ }
479
+ return false
480
+ }
481
+
482
+ function filterPolygonsOld(polygons, fig1, fig2, mode) {
483
+ var filtered = []
484
+ var c1, c2
485
+ var point
486
+ var bigPolygons = removeSmallPolygons(polygons, 0.0001)
487
+ for (var i = 0; i < bigPolygons.length; i++) {
488
+ point = getPointInsidePolygon(bigPolygons[i])
489
+ c1 = findPointInsidePolygon(point, fig1)
490
+ c2 = findPointInsidePolygon(point, fig2)
491
+ if (
492
+ (mode === 'intersect' && c1 && c2) || //intersection
493
+ (mode === 'cut1' && c1 && !c2) || //fig1 - fig2
494
+ (mode === 'cut2' && !c1 && c2) || //fig2 - fig2
495
+ (mode === 'sum' && (c1 || c2))
496
+ ) {
497
+ //fig1 + fig2
498
+ filtered.push(bigPolygons[i])
499
+ }
500
+ }
501
+ return filtered
502
+ }
503
+
504
+ function removeSmallPolygons(polygons, minSize) {
505
+ var big = []
506
+ for (var i = 0; i < polygons.length; i++) {
507
+ if (polygonArea(polygons[i]) >= minSize) {
508
+ big.push(polygons[i])
509
+ }
510
+ }
511
+ return big
512
+ }
513
+
514
+ function polygonArea(p) {
515
+ var len = p.length
516
+ var s = 0
517
+ for (var i = 0; i < len; i++) {
518
+ s += Math.abs(
519
+ p[i % len].x * p[(i + 1) % len].y - p[i % len].y * p[(i + 1) % len].x
520
+ )
521
+ }
522
+ return s / 2
523
+ }
524
+
525
+ function getPointInsidePolygon(polygon) {
526
+ var point
527
+ var size = getSize(polygon)
528
+ var edges = getEdges(polygon)
529
+ var y = size.y.min + (size.y.max - size.y.min) / Math.PI
530
+ var dy = (size.y.max - size.y.min) / 13
531
+ var line = []
532
+ var points
533
+ var interPoints = []
534
+ var pointsOK = false
535
+ while (!pointsOK) {
536
+ line = [
537
+ { x: size.x.min - 1, y: y },
538
+ { x: size.x.max + 1, y: y }
539
+ ]
540
+ //find intersections with all polygon edges
541
+ for (var i = 0; i < edges.length; i++) {
542
+ points = findEdgeIntersection(line, edges[i])
543
+ //if edge doesn't lie inside line
544
+ if (points && points.length === 1) {
545
+ interPoints.push(points[0])
546
+ }
547
+ }
548
+ interPoints = sortPoints(interPoints)
549
+ //find two correct interpoints
550
+ for (var i = 0; i < interPoints.length - 1; i++) {
551
+ if (interPoints[i].t !== interPoints[i + 1].t) {
552
+ //enable exit from loop and calculate point coordinates
553
+ pointsOK = true
554
+ point = { x: (interPoints[i].x + interPoints[i + 1].x) / 2, y: y }
555
+ }
556
+ }
557
+ //all points are incorrect, need to change line parameters
558
+ y = y + dy
559
+ if ((y > size.y.max || y < size.y.min) && pointsOK === false) {
560
+ pointsOK = true
561
+ point = undefined
562
+ }
563
+ }
564
+ return point
565
+ }
566
+
567
+ function getSize(polygon) {
568
+ var size = {
569
+ x: {
570
+ min: polygon[0].x,
571
+ max: polygon[0].x
572
+ },
573
+ y: {
574
+ min: polygon[0].y,
575
+ max: polygon[0].y
576
+ }
577
+ }
578
+ for (var i = 1; i < polygon.length; i++) {
579
+ if (polygon[i].x < size.x.min) size.x.min = polygon[i].x
580
+ if (polygon[i].x > size.x.max) size.x.max = polygon[i].x
581
+ if (polygon[i].y < size.y.min) size.y.min = polygon[i].y
582
+ if (polygon[i].y > size.y.max) size.y.max = polygon[i].y
583
+ }
584
+ return size
585
+ }
586
+
587
+ function findPointInsidePolygon(point, polygon) {
588
+ var cross = 0
589
+ var edges = getEdges(polygon)
590
+ var classify
591
+ var org, dest
592
+ for (var i = 0; i < edges.length; i++) {
593
+ ;[org, dest] = edges[i]
594
+ classify = classifyPoint(point, [org, dest])
595
+ if (
596
+ (classify.loc === 'RIGHT' && org.y < point.y && dest.y >= point.y) ||
597
+ (classify.loc === 'LEFT' && org.y >= point.y && dest.y < point.y)
598
+ ) {
599
+ cross++
600
+ }
601
+ if (classify.loc === 'BETWEEN') return false
602
+ }
603
+ if (cross % 2) {
604
+ return true
605
+ } else {
606
+ return false
607
+ }
608
+ }
609
+
610
+ function getMidpoints(edges) {
611
+ var midpoints = []
612
+ var x, y
613
+ for (var i = 0; i < edges.length; i++) {
614
+ x = (edges[i][0].x + edges[i][1].x) / 2
615
+ y = (edges[i][0].y + edges[i][1].y) / 2
616
+ let classify = classifyPoint({ x: x, y: y }, edges[i])
617
+ if (classify.loc != 'BETWEEN') {
618
+ //console.error('Midpoint calculation error in intersect algo',edges)
619
+ }
620
+ midpoints.push({ x: x, y: y })
621
+ }
622
+ return midpoints
623
+ }
package/src/matrix.js ADDED
@@ -0,0 +1,53 @@
1
+ export function inverse2x2Matrix([a, b, c, d]) {
2
+ //inverse matrix |a,c|
3
+ // |b,d|
4
+ const det = a * b - c * b
5
+ if (det == 0) {
6
+ return null
7
+ }
8
+ return [d / det, -b / det, -c / det, a / det]
9
+ }
10
+
11
+ export function inverse3x3matrix(m) {
12
+ let [[a, b, c], [d, e, f], [g, h, i]] = m
13
+ let x = e * i - h * f
14
+ let y = f * g - d * i
15
+ let z = d * h - g * e
16
+ let det = a * x + b * y + c * z
17
+ return det != 0
18
+ ? [
19
+ [x, c * h - b * i, b * f - c * e],
20
+ [y, a * i - c * g, d * c - a * f],
21
+ [z, g * b - a * h, a * e - d * b]
22
+ ].map((r) => r.map((v) => (v /= det)))
23
+ : null
24
+ }
25
+ export function multiplyMatrices(a, b) {
26
+ if (!Array.isArray(a) || !Array.isArray(b) || !a.length || !b.length) {
27
+ throw new Error('arguments should be in 2-dimensional array format')
28
+ }
29
+ let x = a.length
30
+ let z = a[0].length
31
+ let y = b[0].length
32
+ if (b.length !== z) {
33
+ throw new Error(
34
+ 'number of columns in the first matrix should be the same as the number of rows in the second'
35
+ )
36
+ }
37
+ let productRow = Array.apply(null, new Array(y)).map(
38
+ Number.prototype.valueOf,
39
+ 0
40
+ )
41
+ let product = new Array(x)
42
+ for (let p = 0; p < x; p++) {
43
+ product[p] = productRow.slice()
44
+ }
45
+ for (let i = 0; i < x; i++) {
46
+ for (let j = 0; j < y; j++) {
47
+ for (let k = 0; k < z; k++) {
48
+ product[i][j] += a[i][k] * b[k][j]
49
+ }
50
+ }
51
+ }
52
+ return product
53
+ }