pimath 0.1.39 → 0.2.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.
Files changed (113) hide show
  1. package/dist/pimath.js +3127 -2865
  2. package/dist/pimath.js.map +1 -1
  3. package/package.json +16 -12
  4. package/src/algebra/equation.ts +558 -0
  5. package/src/algebra/equationSolver.ts +488 -0
  6. package/src/algebra/factor.ts +338 -0
  7. package/src/algebra/index.ts +11 -0
  8. package/src/algebra/linearSystem.ts +439 -0
  9. package/src/algebra/logicalset.ts +255 -0
  10. package/src/algebra/matrix.ts +474 -0
  11. package/src/algebra/monom.ts +977 -0
  12. package/src/algebra/operations.ts +23 -0
  13. package/src/algebra/polyFactor.ts +668 -0
  14. package/src/algebra/polynom.ts +1247 -0
  15. package/src/analyze/index.ts +4 -0
  16. package/src/analyze/solution.ts +178 -0
  17. package/src/analyze/tableOfSigns.ts +30 -0
  18. package/src/coefficients/fraction.ts +718 -0
  19. package/src/coefficients/index.ts +4 -0
  20. package/src/coefficients/root.ts +346 -0
  21. package/src/geometry/TupleN.ts +128 -0
  22. package/src/geometry/circle.ts +456 -0
  23. package/src/geometry/geomMath.ts +71 -0
  24. package/src/geometry/index.ts +11 -0
  25. package/src/geometry/line.ts +653 -0
  26. package/src/geometry/line3.ts +211 -0
  27. package/src/geometry/plane3.ts +179 -0
  28. package/src/geometry/point.ts +104 -0
  29. package/src/geometry/sphere3.ts +214 -0
  30. package/src/geometry/triangle.ts +482 -0
  31. package/src/geometry/vector.ts +225 -0
  32. package/src/helpers.ts +35 -0
  33. package/src/index.ts +61 -0
  34. package/src/numeric.ts +196 -0
  35. package/src/pimath.interface.ts +162 -0
  36. package/src/randomization/algebra/rndEquation.ts +41 -0
  37. package/src/randomization/algebra/rndMonom.ts +39 -0
  38. package/src/randomization/algebra/rndPolynom.ts +100 -0
  39. package/src/randomization/coefficient/rndFraction.ts +38 -0
  40. package/src/randomization/geometry/rndCircle.ts +27 -0
  41. package/src/randomization/geometry/rndLine.ts +35 -0
  42. package/src/randomization/geometry/rndLine3.ts +27 -0
  43. package/src/randomization/geometry/rndVector.ts +63 -0
  44. package/src/randomization/random.ts +89 -0
  45. package/src/randomization/rndHelpers.ts +102 -0
  46. package/src/randomization/rndTypes.ts +67 -0
  47. package/types/algebra/equation.d.ts +18 -17
  48. package/types/algebra/equation.d.ts.map +1 -1
  49. package/types/algebra/equationSolver.d.ts +7 -3
  50. package/types/algebra/equationSolver.d.ts.map +1 -1
  51. package/types/algebra/factor.d.ts +1 -1
  52. package/types/algebra/factor.d.ts.map +1 -1
  53. package/types/algebra/linearSystem.d.ts +23 -6
  54. package/types/algebra/linearSystem.d.ts.map +1 -1
  55. package/types/algebra/logicalset.d.ts +1 -1
  56. package/types/algebra/logicalset.d.ts.map +1 -1
  57. package/types/algebra/monom.d.ts +1 -6
  58. package/types/algebra/monom.d.ts.map +1 -1
  59. package/types/algebra/operations.d.ts.map +1 -1
  60. package/types/algebra/polyFactor.d.ts +9 -4
  61. package/types/algebra/polyFactor.d.ts.map +1 -1
  62. package/types/algebra/polynom.d.ts +10 -7
  63. package/types/algebra/polynom.d.ts.map +1 -1
  64. package/types/analyze/index.d.ts +2 -0
  65. package/types/analyze/index.d.ts.map +1 -0
  66. package/types/analyze/solution.d.ts +27 -0
  67. package/types/analyze/solution.d.ts.map +1 -0
  68. package/types/analyze/tableOfSigns.d.ts +9 -0
  69. package/types/analyze/tableOfSigns.d.ts.map +1 -0
  70. package/types/coefficients/fraction.d.ts +14 -12
  71. package/types/coefficients/fraction.d.ts.map +1 -1
  72. package/types/coefficients/index.d.ts +1 -1
  73. package/types/coefficients/index.d.ts.map +1 -1
  74. package/types/coefficients/root.d.ts +41 -0
  75. package/types/coefficients/root.d.ts.map +1 -0
  76. package/types/geometry/TupleAbstract.d.ts +22 -0
  77. package/types/geometry/TupleAbstract.d.ts.map +1 -0
  78. package/types/geometry/TupleN.d.ts +24 -0
  79. package/types/geometry/TupleN.d.ts.map +1 -0
  80. package/types/geometry/circle.d.ts +26 -17
  81. package/types/geometry/circle.d.ts.map +1 -1
  82. package/types/geometry/geomMath.d.ts +2 -1
  83. package/types/geometry/geomMath.d.ts.map +1 -1
  84. package/types/geometry/index.d.ts.map +1 -1
  85. package/types/geometry/line.d.ts +21 -30
  86. package/types/geometry/line.d.ts.map +1 -1
  87. package/types/geometry/line3.d.ts +19 -19
  88. package/types/geometry/line3.d.ts.map +1 -1
  89. package/types/geometry/matrix.d.ts +11 -11
  90. package/types/geometry/plane3.d.ts +9 -9
  91. package/types/geometry/plane3.d.ts.map +1 -1
  92. package/types/geometry/point.d.ts +12 -7
  93. package/types/geometry/point.d.ts.map +1 -1
  94. package/types/geometry/triangle.d.ts +68 -23
  95. package/types/geometry/triangle.d.ts.map +1 -1
  96. package/types/geometry/vector.d.ts +24 -44
  97. package/types/geometry/vector.d.ts.map +1 -1
  98. package/types/helpers.d.ts +1 -0
  99. package/types/helpers.d.ts.map +1 -1
  100. package/types/index.d.ts +6 -4
  101. package/types/index.d.ts.map +1 -1
  102. package/types/numeric.d.ts +2 -0
  103. package/types/numeric.d.ts.map +1 -1
  104. package/types/pimath.interface.d.ts +38 -44
  105. package/types/pimath.interface.d.ts.map +1 -1
  106. package/types/randomization/algebra/rndPolynom.d.ts.map +1 -1
  107. package/types/randomization/coefficient/rndFraction.d.ts +1 -1
  108. package/types/randomization/coefficient/rndFraction.d.ts.map +1 -1
  109. package/types/randomization/geometry/rndLine.d.ts.map +1 -1
  110. package/types/randomization/random.d.ts +3 -2
  111. package/types/randomization/random.d.ts.map +1 -1
  112. package/types/randomization/rndTypes.d.ts +15 -10
  113. package/types/randomization/rndTypes.d.ts.map +1 -1
@@ -0,0 +1,456 @@
1
+ import {Line} from "./line"
2
+ import {Vector} from "./vector"
3
+ import {Numeric} from "../numeric"
4
+ import {Fraction, Root} from "../coefficients"
5
+ import {Equation, Monom, Polynom} from "../algebra"
6
+ import {type IPiMathObject} from "../pimath.interface"
7
+ import {Point} from "./point"
8
+ import {Triangle} from "./triangle"
9
+ import {Solution} from "../analyze"
10
+
11
+ enum CIRCLE_DISPLAY {
12
+ CANONICAL,
13
+ CENTER_RADIUS,
14
+ }
15
+
16
+ export class Circle
17
+ implements IPiMathObject<Circle> {
18
+
19
+ #center: Point | null = null
20
+ #equation: Equation | null = null
21
+ #output_style: CIRCLE_DISPLAY = CIRCLE_DISPLAY.CENTER_RADIUS
22
+ #squareRadius: Fraction | null = null
23
+
24
+ constructor()
25
+ constructor(equation: string | Equation)
26
+ constructor(circle: Circle)
27
+ constructor(center: Point, radius: Fraction | number, square?: boolean)
28
+ constructor(center: Point, pointThrough: Point)
29
+ constructor(A: Point, B: Point, C: Point)
30
+ constructor(...values: unknown[]) {
31
+ if (values.length > 0) {
32
+ this.parse(...values)
33
+ }
34
+ }
35
+
36
+ parse(...values: unknown[]): this {
37
+ // Data can be given in these formats:
38
+ // one value, a string -> make it an Equation
39
+ // one value, an Equation
40
+ // one value, a circle -> clone it
41
+ // two values: two points (center and pointThrough)
42
+ // two values: point and Fraction (center and radius)
43
+ // three values: Vector2D, Fraction, Boolean (center, square radius, true)
44
+
45
+ if (typeof values[0] === 'string') {
46
+ return this.fromString(values[0])
47
+ }
48
+
49
+ if (values[0] instanceof Equation) {
50
+ return this.fromEquation(values[0])
51
+ }
52
+
53
+ if (values[0] instanceof Circle) {
54
+ return this.copy(values[0])
55
+ }
56
+
57
+ if (values.length === 2 &&
58
+ values[0] instanceof Point && values[1] instanceof Point
59
+ ) {
60
+ // Circle center through one point
61
+ return this.fromCenterPoint(values[0], values[1])
62
+ }
63
+
64
+ if (values.length >= 2 && values[0]
65
+ instanceof Point &&
66
+ (values[1] instanceof Fraction || typeof values[1] === 'number')
67
+ ) {
68
+ // Circle center through one point
69
+ return this.fromCenterRadius(
70
+ values[0], values[1],
71
+ (typeof values[2] === "boolean") ? values[2] : false
72
+ )
73
+ }
74
+
75
+ return this
76
+ }
77
+
78
+ clone(): Circle {
79
+ return new Circle().fromCenterRadius(
80
+ this.center.clone(),
81
+ this.squareRadius.clone(),
82
+ true
83
+ )
84
+ }
85
+
86
+ copy(circle: Circle): this {
87
+ this.#center = circle.center.clone()
88
+ this.#squareRadius = circle.squareRadius.clone()
89
+
90
+ this.#calculateCartesian()
91
+
92
+ return this
93
+ }
94
+
95
+ get tex(): string {
96
+ if (this.#output_style === CIRCLE_DISPLAY.CANONICAL) {
97
+ return this.equation.moveLeft().reduce().tex
98
+ }
99
+
100
+ let cx, cy
101
+ if (this.center.x.isZero()) {
102
+ cx = 'x^2'
103
+ } else {
104
+ cx = `\\left(x${this.center.x.isNegative() ? '+' : '-'}${this.center.x.clone().abs().tex}\\right)^2`
105
+ }
106
+ if (this.center.y.isZero()) {
107
+ cy = 'y^2'
108
+ } else {
109
+ cy = `\\left(y${this.center.y.isNegative() ? '+' : '-'}${this.center.y.clone().abs().tex}\\right)^2`
110
+ }
111
+ return `${cx}+${cy}=${this.squareRadius.tex}`
112
+ }
113
+
114
+ get display(): string {
115
+ if (this.#output_style === CIRCLE_DISPLAY.CANONICAL) {
116
+ return this.equation.moveLeft().reduce().display
117
+ }
118
+
119
+ let cx, cy
120
+ if (this.center.x.isZero()) {
121
+ cx = 'x^2'
122
+ } else {
123
+ cx = `(x${this.center.x.isNegative() ? '+' : '-'}${this.center.x.clone().abs().tex})^2`
124
+ }
125
+ if (this.center.y.isZero()) {
126
+ cy = 'y^2'
127
+ } else {
128
+ cy = `(y${this.center.y.isNegative() ? '+' : '-'}${this.center.y.clone().abs().tex})^2`
129
+ }
130
+ return `${cx}+${cy}=${this.squareRadius.display}`
131
+ }
132
+
133
+ get asCanonical(): this {
134
+ this.#output_style = CIRCLE_DISPLAY.CANONICAL
135
+ return this
136
+ }
137
+
138
+ get asCenterRadius(): this {
139
+ this.#output_style = CIRCLE_DISPLAY.CENTER_RADIUS
140
+ return this
141
+ }
142
+
143
+ get center(): Point {
144
+ return this.#center ?? new Point()
145
+ }
146
+
147
+ get equation(): Equation {
148
+ return this.#equation?.clone() ?? new Equation('0=0')
149
+ }
150
+
151
+ fromCenterPoint(center: Point, pointThrough: Point): this {
152
+ this.#center = center.clone()
153
+ this.#squareRadius = new Vector(this.#center, pointThrough).normSquare
154
+
155
+ this.#calculateCartesian()
156
+
157
+ return this
158
+ }
159
+
160
+ fromCenterRadius(center: Point, radius: Fraction | number, square?: boolean): this {
161
+ this.#center = center.clone()
162
+ if (square) {
163
+ this.#squareRadius = (new Fraction(radius))
164
+ } else {
165
+ this.#squareRadius = new Fraction(radius).pow(2)
166
+ }
167
+
168
+ this.#calculateCartesian()
169
+
170
+ return this
171
+ }
172
+
173
+ fromEquation(equ: Equation): this {
174
+ // Move everything to the left.
175
+ equ.moveLeft()
176
+
177
+ if (equ.degree('x').value === 2 && equ.degree('y').value === 2) {
178
+ // Both must be of degree 2.
179
+ const x2 = equ.left.monomByDegree(2, 'x'), y2 = equ.left.monomByDegree(2, 'y')
180
+ let x1: Monom, y1: Monom, c: Monom
181
+
182
+ // Both square monoms must have the same coefficient.
183
+ if (x2.coefficient.isEqual(y2.coefficient)) {
184
+ equ.divide(x2.coefficient)
185
+
186
+ x1 = equ.left.monomByDegree(1, 'x')
187
+ y1 = equ.left.monomByDegree(1, 'y')
188
+
189
+ c = equ.left.monomByDegree(0)
190
+
191
+ this.#center = new Point(x1.coefficient.clone().divide(2).opposite(), y1.coefficient.clone().divide(2).opposite())
192
+
193
+ this.#squareRadius = c.coefficient.clone().opposite()
194
+ .add(this.#center.x.clone().pow(2))
195
+ .add(this.#center.y.clone().pow(2))
196
+
197
+ this.#calculateCartesian()
198
+
199
+ return this
200
+ } else {
201
+ // The circle is not a valid circle
202
+ this.#reset()
203
+ }
204
+ }
205
+
206
+ return this
207
+ }
208
+
209
+ fromPoints(A: Point, B: Point, C: Point): this {
210
+ const T = new Triangle(A, B, C)
211
+
212
+ if (!T.isValid || !T.remarquables) {
213
+ this.#reset()
214
+ return this
215
+ }
216
+
217
+ const mAB = T.getMediators().c.clone()
218
+ const mAC = T.getMediators().b.clone()
219
+
220
+ return this.fromCenterPoint(
221
+ mAB.intersection(mAC).point,
222
+ A
223
+ )
224
+ }
225
+
226
+ fromString(str: string): this {
227
+ return this.fromEquation(new Equation(str))
228
+ }
229
+
230
+ getPointsOnCircle(): Point[] {
231
+ // It means searching for pythagorician triples that make a perfect square.
232
+ // (x-4)^2 + (y+3)^2 = 15
233
+ const triplets = Numeric.pythagoreanTripletsWithTarget(this.squareRadius.value, true)
234
+
235
+ const points: Point[] = []
236
+
237
+ triplets.forEach(triplet => {
238
+ // Allow positive / negative values
239
+ // x-a = t => x = a + t
240
+ // x-a = -t => x = a - t
241
+ for (const k of [[1, 1], [-1, 1], [-1, -1], [1, -1]]) {
242
+ // check if the point is not already here.
243
+ const x = this.center.x.clone().add(k[0] * triplet[0])
244
+ const y = this.center.y.clone().add(k[1] * triplet[1])
245
+
246
+ if (points.every(pt => !pt.isEqualXY(x, y))) {
247
+ points.push(new Point(x, y))
248
+ }
249
+
250
+ }
251
+ })
252
+ return points
253
+ }
254
+
255
+ isPointOnCircle = (P: Point): boolean => {
256
+ return this.#equation?.test({x: P.x, y: P.y}) ?? false
257
+ }
258
+
259
+ public isSame(circ: Circle): boolean {
260
+ return circ.center.isEqual(this.center)
261
+ && circ.radius.isEqual(this.radius)
262
+ }
263
+
264
+ /**
265
+ * Find the intersection points between the circle and a line. It can be 0, 1 or 2 points.
266
+ * The points are sorted depending on the direction vector of the line.
267
+ * @param L
268
+ */
269
+ lineIntersection(L: Line): Point[] {
270
+ if (this.#equation === null) return []
271
+
272
+ const center = this.center
273
+ const d = L.d
274
+ const OP = L.OA
275
+
276
+ // A = dx^2+dy^2
277
+ const A = d.normSquare
278
+
279
+ // B = 2 ( dx (x0-cx) + dy(y0-cy) )
280
+ const B = OP.x.clone().subtract(center.x).multiply(d.x)
281
+ .add(OP.y.clone().subtract(center.y).multiply(d.y))
282
+ .multiply(2)
283
+
284
+ // C = (x0-cx)^2 + (y0-cy)^2 - r^2
285
+ const C = OP.x.clone().subtract(center.x).pow(2)
286
+ .add(OP.y.clone().subtract(center.y).pow(2))
287
+ .subtract(this.squareRadius)
288
+
289
+ const sol = Solution.fromQuadratic(A, B, C)
290
+
291
+ if (sol.length === 0) return []
292
+
293
+ // One intersection point
294
+ if (sol.length === 1) { // means exact answer
295
+ const OX = OP.add(d.clone().multiplyByScalar(sol[0].fraction))
296
+ return [
297
+ new Point(OX.x, OX.y)
298
+ ]
299
+ }
300
+
301
+ // Two intersection points
302
+ const OX1 = sol[0].exact
303
+ ? OP.clone().add(d.clone().multiplyByScalar(sol[0].fraction))
304
+ : OP.clone().add(d.clone().multiplyByScalar(sol[0].value))
305
+
306
+ const OX2 = sol[1].exact
307
+ ? OP.clone().add(d.clone().multiplyByScalar(sol[1].fraction))
308
+ : OP.clone().add(d.clone().multiplyByScalar(sol[1].value))
309
+
310
+ // sort the points depending on the direction vector.
311
+ return [
312
+ new Point(OX1.x, OX1.y),
313
+ new Point(OX2.x, OX2.y),
314
+ ].sort((a, b) => {
315
+ // <0 => a before
316
+ if (d.x.isZero()) {
317
+ return d.y.isPositive()
318
+ ? a.y.value - b.y.value
319
+ : b.y.value - a.y.value
320
+ }
321
+
322
+ return d.x.isPositive()
323
+ ? a.x.value - b.x.value
324
+ : b.x.value - a.x.value
325
+ })
326
+ }
327
+
328
+ get radius(): Root {
329
+ return new Root().from(2, this.#squareRadius ?? 0)
330
+ }
331
+
332
+ /**
333
+ * Get the relative position between circle and line. It corresponds to the number of intersection.
334
+ * @param {Line} L
335
+ * @returns {number}
336
+ */
337
+ public relativePosition(L: Line): number {
338
+ if (this.#center === null || this.#squareRadius === null) {
339
+ return -1
340
+ }
341
+
342
+ const distance = L.distanceTo(this.#center).pow(2).value
343
+ const radius = this.#squareRadius.value
344
+
345
+ if (distance - radius > 0.0000000001) {
346
+ return 0 // external
347
+ }
348
+
349
+ if (Math.abs(distance - radius) < 0.0000000001) {
350
+ return 1 // tangent
351
+ }
352
+
353
+ return 2 // secant
354
+ }
355
+
356
+ setRadius(radius: Fraction | number, square?: boolean): this {
357
+ if (square) {
358
+ this.#squareRadius = new Fraction(radius)
359
+ } else {
360
+ this.#squareRadius = new Fraction(radius).pow(2)
361
+ }
362
+
363
+ this.#calculateCartesian()
364
+ return this
365
+ }
366
+
367
+ get squareRadius(): Fraction {
368
+ return this.#squareRadius?.clone() ?? new Fraction(-1)
369
+ }
370
+
371
+ tangents = (P: Point | Fraction): Line[] => {
372
+ if (P instanceof Fraction) {
373
+ return this.#tangentsWithSlope(P)
374
+ }
375
+
376
+ if (this.isPointOnCircle(P)) {
377
+ return this.#tangentsThroughOnePointOnTheCircle(P)
378
+ }
379
+
380
+ if (this.#center !== null && this.#center.distanceTo(P).value > this.radius.value) {
381
+ return this.#tangentsThroughOnePointOutsideTheCircle(P)
382
+ }
383
+
384
+ return []
385
+ }
386
+
387
+ #calculateCartesian(): void {
388
+ this.#equation = (
389
+ new Equation(
390
+ new Polynom(`(x-(${this.center.x.display}))^2+(y-(${this.center.y.display}))^2`),
391
+ new Polynom(this.squareRadius.display))
392
+ ).moveLeft()
393
+ }
394
+
395
+ #reset() {
396
+ this.#center = null
397
+ this.#squareRadius = null
398
+ this.#equation = null
399
+ }
400
+
401
+ #tangentsThroughOnePointOnTheCircle = (P: Point): Line[] => {
402
+ const CT = new Vector(this.center, P)
403
+ return [new Line().fromPointAndNormal(P, CT)]
404
+ }
405
+
406
+ #tangentsThroughOnePointOutsideTheCircle = (P: Point): Line[] => {
407
+ // y = mx + h
408
+ // px, py => h = -m px + py => mx - y -m.px + py = 0 =>
409
+ // Centre: cx, cy, radius: r
410
+ // (m.cx - cy -m.px + py)^2 = r^2 * (m^2 + 1)
411
+ // (m(cx-py) - (cy - py))^2 = r^2 * (m^2 + 1)
412
+
413
+ const cx_px = this.center.x.clone().subtract(P.x)
414
+ const cy_py = this.center.y.clone().subtract(P.y)
415
+ const polyLeft = new Polynom('x')
416
+ const polyRight = new Polynom('x^2+1')
417
+
418
+ polyLeft.multiply(cx_px).subtract(cy_py).pow(2)
419
+ polyRight.multiply(this.squareRadius)
420
+
421
+ const equ = new Equation(polyLeft, polyRight)
422
+
423
+ const solutions = equ.solve()
424
+
425
+ return solutions.map(sol => {
426
+ // h = -m px + py
427
+ let h: Fraction
428
+ const equ = new Equation('y', 'x')
429
+
430
+ if (sol.exact) {
431
+ h = P.x.clone().opposite().multiply(sol.fraction).add(P.y)
432
+ equ.right.multiply(sol.fraction).add(h)
433
+ } else {
434
+ h = P.x.clone().opposite().multiply(sol.value).add(P.y)
435
+ equ.right.multiply(sol.value).add(h)
436
+ }
437
+
438
+ return new Line(equ)
439
+ })
440
+
441
+ }
442
+
443
+ #tangentsWithSlope = (slope: Fraction): Line[] => {
444
+ // d(C;t)=r => ac1+bc2 + x = +- sqrt(a^2 + b^2)*r
445
+ // x = -ac1-bc2 +- sqrt(a^2 + b^2)*r
446
+ // y = a/bx + h => ax-by + H = 0
447
+
448
+ const a = slope.numerator, b = -slope.denominator, c1 = this.center.x.clone(), c2 = this.center.y.clone()
449
+
450
+ const sq = this.squareRadius.clone().multiply(slope.numerator ** 2 + slope.denominator ** 2),
451
+ x1 = c1.clone().multiply(a).opposite().subtract(c2.clone().multiply(b)).add(sq.clone().sqrt()),
452
+ x2 = c1.clone().multiply(a).opposite().subtract(c2.clone().multiply(b)).subtract(sq.clone().sqrt())
453
+
454
+ return [new Line(a, b, x1), new Line(a, b, x2)]
455
+ }
456
+ }
@@ -0,0 +1,71 @@
1
+ import {Fraction} from "../coefficients"
2
+ import type {Vector} from "./vector"
3
+ import type {Point} from "./point"
4
+
5
+ type V = Vector | Point
6
+ export function areVectorsEquals(v1: V, v2: V): boolean {
7
+ return v1.dimension === v2.dimension &&
8
+ v1.array.every(
9
+ (value, index) => {
10
+ return v2.array[index].isEqual(value)
11
+ })
12
+ }
13
+
14
+ export function areVectorsColinears(v1: V, v2: V): boolean {
15
+ if (v1.dimension !== v2.dimension) { return false }
16
+
17
+ // Constant of proportionality
18
+ const k = v2.array[0].value / v1.array[0].value
19
+ return v1.array.every(
20
+ (value, index) => {
21
+ return v2.array[index].value === value.value * k
22
+ })
23
+ }
24
+
25
+
26
+ export function dotProduct(v1: V, v2: V): Fraction {
27
+ if (v1.dimension !== v2.dimension) { return new Fraction().invalid() }
28
+
29
+ // Calculate the dot product
30
+ // Why does the reduce not add the last element?
31
+
32
+ return v1.array.reduce(
33
+ (acc, value, index) => {
34
+ return acc.add(value.clone().multiply(v2.array[index]))
35
+ }, new Fraction(0))
36
+ }
37
+
38
+ export function determinantFromVectors(...values: V[]): Fraction {
39
+ // TODO: Make it work for vectors of dimension n
40
+ // Check if the vectors are in the same dimension
41
+ if (values.some((value) => value.dimension !== values[0].dimension)) {
42
+ throw new Error('All vectors must have the same dimension')
43
+ }
44
+
45
+ // Check if the vectors are in dimension 2 or 3 and that the number of values is correct
46
+ if (values[0].dimension !== values.length ) {
47
+ throw new Error(`The determinant of dimension ${values[0].dimension} must have the same number of vectors (${values.length} given)`)
48
+ }
49
+
50
+ // Calculate the determinant 2x2
51
+ if (values[0].dimension === 2) {
52
+ return values[0].array[0].clone().multiply(values[1].array[1])
53
+ .subtract(values[0].array[1].clone().multiply(values[1].array[0]))
54
+ }
55
+
56
+ // Calculate the determinant 3x3
57
+ return values[0].array[0].clone()
58
+ .multiply(
59
+ values[1].array[1].clone().multiply(values[2].array[2])
60
+ .subtract(values[1].array[2].clone().multiply(values[2].array[1]))
61
+ )
62
+ .subtract(values[0].array[1].clone()
63
+ .multiply(
64
+ values[1].array[0].clone().multiply(values[2].array[2])
65
+ .subtract(values[1].array[2].clone().multiply(values[2].array[0]))
66
+ )
67
+ )
68
+ .add(values[0].array[2].clone()
69
+ .multiply(values[1].array[0].clone().multiply(values[2].array[1])
70
+ .subtract(values[1].array[1].clone().multiply(values[2].array[0]))))
71
+ }
@@ -0,0 +1,11 @@
1
+ // Import / export every files from the geometry folder
2
+
3
+ export * from './geomMath'
4
+ export * from './circle'
5
+ export * from './line'
6
+ export * from './line3'
7
+ export * from './plane3'
8
+ export * from './point'
9
+ export * from './triangle'
10
+ export * from './vector'
11
+ export * from './sphere3'