pimath 0.1.39 → 0.1.40
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/dist/pimath.js +188 -159
- package/dist/pimath.js.map +1 -1
- package/package.json +4 -2
- package/src/algebra/equation.ts +556 -0
- package/src/algebra/equationSolver.ts +539 -0
- package/src/algebra/factor.ts +339 -0
- package/src/algebra/index.ts +11 -0
- package/src/algebra/linearSystem.ts +388 -0
- package/src/algebra/logicalset.ts +256 -0
- package/src/algebra/matrix.ts +474 -0
- package/src/algebra/monom.ts +1015 -0
- package/src/algebra/operations.ts +24 -0
- package/src/algebra/polyFactor.ts +668 -0
- package/src/algebra/polynom.ts +1394 -0
- package/src/analyze/solution.ts +115 -0
- package/src/analyze/tableOfSigns.ts +30 -0
- package/src/coefficients/fraction.ts +678 -0
- package/src/coefficients/index.ts +4 -0
- package/src/coefficients/nthRoot.ts +149 -0
- package/src/coefficients/root.ts +299 -0
- package/src/geometry/circle.ts +386 -0
- package/src/geometry/geomMath.ts +70 -0
- package/src/geometry/index.ts +10 -0
- package/src/geometry/line.ts +677 -0
- package/src/geometry/line3.ts +206 -0
- package/src/geometry/plane3.ts +170 -0
- package/src/geometry/point.ts +66 -0
- package/src/geometry/sphere3.ts +214 -0
- package/src/geometry/triangle.ts +354 -0
- package/src/geometry/vector.ts +341 -0
- package/src/helpers.ts +35 -0
- package/src/index.ts +60 -0
- package/src/numeric.ts +199 -0
- package/src/pimath.interface.ts +160 -0
- package/src/randomization/algebra/rndEquation.ts +41 -0
- package/src/randomization/algebra/rndMonom.ts +39 -0
- package/src/randomization/algebra/rndPolynom.ts +86 -0
- package/src/randomization/coefficient/rndFraction.ts +38 -0
- package/src/randomization/geometry/rndCircle.ts +27 -0
- package/src/randomization/geometry/rndLine.ts +37 -0
- package/src/randomization/geometry/rndLine3.ts +27 -0
- package/src/randomization/geometry/rndVector.ts +63 -0
- package/src/randomization/random.ts +91 -0
- package/src/randomization/rndHelpers.ts +102 -0
- package/src/randomization/rndTypes.ts +63 -0
- package/types/algebra/equationSolver.d.ts +3 -0
- package/types/algebra/equationSolver.d.ts.map +1 -1
- package/types/algebra/polyFactor.d.ts +5 -0
- package/types/algebra/polyFactor.d.ts.map +1 -1
- package/types/analyze/solution.d.ts +21 -0
- package/types/analyze/solution.d.ts.map +1 -0
- package/types/analyze/tableOfSigns.d.ts +9 -0
- package/types/analyze/tableOfSigns.d.ts.map +1 -0
- package/types/coefficients/root.d.ts +38 -0
- package/types/coefficients/root.d.ts.map +1 -0
- package/types/geometry/point.d.ts +1 -1
- package/types/geometry/point.d.ts.map +1 -1
- package/types/helpers.d.ts +1 -0
- package/types/helpers.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/numeric.d.ts +2 -0
- package/types/numeric.d.ts.map +1 -1
- package/types/pimath.interface.d.ts +26 -26
- package/types/pimath.interface.d.ts.map +1 -1
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { Line } from "./line"
|
|
2
|
+
import { Vector } from "./vector"
|
|
3
|
+
import { Numeric } from "../numeric"
|
|
4
|
+
import { Fraction } from "../coefficients"
|
|
5
|
+
import { Equation } from "../algebra"
|
|
6
|
+
import { Polynom } from "../algebra"
|
|
7
|
+
import { Monom } from "../algebra"
|
|
8
|
+
import {type IPiMathObject, LinePropriety} from "../pimath.interface"
|
|
9
|
+
import { Point } from "./point"
|
|
10
|
+
|
|
11
|
+
export class Circle
|
|
12
|
+
implements
|
|
13
|
+
IPiMathObject<Circle> {
|
|
14
|
+
#center: Point | undefined = undefined
|
|
15
|
+
#squareRadius: Fraction | undefined = undefined
|
|
16
|
+
#cartesian: Equation | undefined = undefined
|
|
17
|
+
|
|
18
|
+
constructor()
|
|
19
|
+
constructor(equation: string | Equation)
|
|
20
|
+
constructor(circle: Circle)
|
|
21
|
+
constructor(center: Point, radius: Fraction | number, square?: boolean)
|
|
22
|
+
constructor(center: Point, pointThrough: Point)
|
|
23
|
+
constructor(A: Point, B: Point, C: Point)
|
|
24
|
+
constructor(...values: unknown[]) {
|
|
25
|
+
if (values.length > 0) {
|
|
26
|
+
this.parse(...values)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get center(): Point {
|
|
31
|
+
return this.#center ?? new Point()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get squareRadius(): Fraction {
|
|
35
|
+
return this.#squareRadius ?? new Fraction(0)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get cartesian(): Equation {
|
|
39
|
+
if (this.#cartesian === undefined) { throw new Error('Cartesian equation not defined') }
|
|
40
|
+
|
|
41
|
+
return this.#cartesian
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get radius(): { tex: string, display: string, value: number } {
|
|
45
|
+
if (this.#squareRadius === undefined) { return { tex: '', display: '', value: 0 } }
|
|
46
|
+
if (this.#squareRadius.isSquare()) {
|
|
47
|
+
return {
|
|
48
|
+
tex: this.#squareRadius.clone().sqrt().tex,
|
|
49
|
+
display: this.#squareRadius.clone().sqrt().display,
|
|
50
|
+
value: this.#squareRadius.clone().sqrt().value
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
return {
|
|
54
|
+
tex: `\\sqrt{${this.#squareRadius.tex}}`,
|
|
55
|
+
display: `sqrt(${this.#squareRadius.display})`,
|
|
56
|
+
value: this.#squareRadius.clone().sqrt().value
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get tex(): string {
|
|
62
|
+
|
|
63
|
+
let cx, cy
|
|
64
|
+
if (this.center.x.isZero()) {
|
|
65
|
+
cx = 'x^2'
|
|
66
|
+
} else {
|
|
67
|
+
cx = `\\left(x${this.center.x.isNegative() ? '+' : '-'}${this.center.x.clone().abs().tex}\\right)^2`
|
|
68
|
+
}
|
|
69
|
+
if (this.center.y.isZero()) {
|
|
70
|
+
cy = 'y^2'
|
|
71
|
+
} else {
|
|
72
|
+
cy = `\\left(y${this.center.y.isNegative() ? '+' : '-'}${this.center.y.clone().abs().tex}\\right)^2`
|
|
73
|
+
}
|
|
74
|
+
return `${cx}+${cy}=${this.squareRadius.tex}`
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
get developed(): string {
|
|
78
|
+
return this.cartesian.tex
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get display(): string {
|
|
82
|
+
let cx, cy
|
|
83
|
+
if (this.center.x.isZero()) {
|
|
84
|
+
cx = 'x^2'
|
|
85
|
+
} else {
|
|
86
|
+
cx = `(x${this.center.x.isNegative() ? '+' : '-'}${this.center.x.clone().abs().tex})^2`
|
|
87
|
+
}
|
|
88
|
+
if (this.center.y.isZero()) {
|
|
89
|
+
cy = 'y^2'
|
|
90
|
+
} else {
|
|
91
|
+
cy = `(y${this.center.y.isNegative() ? '+' : '-'}${this.center.y.clone().abs().tex})^2`
|
|
92
|
+
}
|
|
93
|
+
return `${cx}+${cy}=${this.squareRadius.display}`
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Get the relative position between circle and line. It corresponds to the number of intersection.
|
|
98
|
+
* @param {Line} L
|
|
99
|
+
* @returns {number}
|
|
100
|
+
*/
|
|
101
|
+
relativePosition = (L: Line): number => {
|
|
102
|
+
if (this.#center === undefined || this.#squareRadius === undefined) { throw new Error('Circle not defined') }
|
|
103
|
+
|
|
104
|
+
const distance = L.distanceTo(this.#center), radius = Math.sqrt(this.#squareRadius.value)
|
|
105
|
+
|
|
106
|
+
if (distance.value - radius > 0.0000000001) {
|
|
107
|
+
return 0 // external
|
|
108
|
+
} else if (Math.abs(distance.value - radius) < 0.0000000001) {
|
|
109
|
+
return 1 // tangent
|
|
110
|
+
} else {
|
|
111
|
+
return 2 // secant
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
lineIntersection = (L: Line): Point[] => {
|
|
116
|
+
const intersectionPoints: Point[] = []
|
|
117
|
+
// let solX: Fraction
|
|
118
|
+
|
|
119
|
+
if (this.#cartesian === undefined) { return [] }
|
|
120
|
+
const equX = this.#cartesian.clone(), lineX = L.getEquation().clone().isolate('x'),
|
|
121
|
+
lineY = L.getEquation().clone().isolate('y')
|
|
122
|
+
|
|
123
|
+
if (lineX instanceof Equation && lineY instanceof Equation) {
|
|
124
|
+
equX.replaceBy('y', lineY.right).simplify()
|
|
125
|
+
equX.solve()
|
|
126
|
+
|
|
127
|
+
// TODO: rework the solutions of an equation.
|
|
128
|
+
// for (const x of equX.solutions) {
|
|
129
|
+
// if (x.exact === false && isNaN(x.value)) {
|
|
130
|
+
// continue
|
|
131
|
+
// }
|
|
132
|
+
|
|
133
|
+
// solX = new Fraction(x.exact === false ? x.value : x.exact)
|
|
134
|
+
// intersectionPoints.push(new Point(solX.clone(), lineY.right.evaluate(solX)))
|
|
135
|
+
// }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return intersectionPoints
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
tangents = (P: Point | Fraction): Line[] => {
|
|
142
|
+
if (P instanceof Fraction) {
|
|
143
|
+
return this.#tangentsWithSlope(P)
|
|
144
|
+
} else if (this.isPointOnCircle(P)) {
|
|
145
|
+
return this.#tangentsThroughOnePointOnTheCircle(P)
|
|
146
|
+
} else if (this.#center !== undefined && this.#center.distanceTo(P).value > this.radius.value) {
|
|
147
|
+
//TODO: Must check it's outside the circle
|
|
148
|
+
return this.#tangentsThroughOnePointOutsideTheCircle(P)
|
|
149
|
+
} else {
|
|
150
|
+
console.log('No tangents as the point is inside !')
|
|
151
|
+
}
|
|
152
|
+
return []
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
isPointOnCircle = (P: Point): boolean => {
|
|
156
|
+
return this.#cartesian?.test({ x: P.x, y: P.y }) ?? false
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
getPointsOnCircle = (numberIsInteger?: boolean): Point[] => {
|
|
160
|
+
if (numberIsInteger === undefined) {
|
|
161
|
+
numberIsInteger = false
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// It means searching for pythagorician triples that make a perfect square.
|
|
165
|
+
// (x-4)^2 + (y+3)^2 = 15
|
|
166
|
+
|
|
167
|
+
const triplets = Numeric.pythagoreanTripletsWithTarget(this.squareRadius.value, true)
|
|
168
|
+
|
|
169
|
+
const points: Point[] = []
|
|
170
|
+
|
|
171
|
+
triplets.forEach(triplet => {
|
|
172
|
+
// Allow positive / negative values
|
|
173
|
+
// x-a = t => x = a + t
|
|
174
|
+
// x-a = -t => x = a - t
|
|
175
|
+
|
|
176
|
+
for (const k of [[1, 1], [-1, 1], [-1, -1], [1, -1]]) {
|
|
177
|
+
points.push(new Point(
|
|
178
|
+
this.center.x.clone().add(k[0] * triplet[0]),
|
|
179
|
+
this.center.y.clone().add(k[1] * triplet[1])
|
|
180
|
+
)
|
|
181
|
+
)
|
|
182
|
+
// Check if the point is not already in points.
|
|
183
|
+
// TODO: isInListOfPoints not implemented
|
|
184
|
+
// if (!pt.isInListOfPoints(points)) {
|
|
185
|
+
// points.push(pt)
|
|
186
|
+
// }
|
|
187
|
+
}
|
|
188
|
+
})
|
|
189
|
+
return points
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
clone(): Circle {
|
|
193
|
+
return new Circle(
|
|
194
|
+
this.center.clone(),
|
|
195
|
+
this.squareRadius.clone(),
|
|
196
|
+
true
|
|
197
|
+
)
|
|
198
|
+
// this.#center = this.center.clone()
|
|
199
|
+
// this.#squareRadius = this.squareRadius.clone()
|
|
200
|
+
// this._calculateCartesian()
|
|
201
|
+
// return this
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
setRadius(radius: Fraction | number, square?: boolean): this {
|
|
205
|
+
if (square) {
|
|
206
|
+
this.#squareRadius = new Fraction(radius)
|
|
207
|
+
} else {
|
|
208
|
+
this.#squareRadius = new Fraction(radius).pow(2)
|
|
209
|
+
}
|
|
210
|
+
this.#calculateCartesian()
|
|
211
|
+
return this
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
#tangentsThroughOnePointOnTheCircle = (P: Point): Line[] => {
|
|
215
|
+
const CT = new Vector(this.center, P)
|
|
216
|
+
return [new Line(P, CT, LinePropriety.Perpendicular)]
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
#tangentsThroughOnePointOutsideTheCircle = (P: Point): Line[] => {
|
|
220
|
+
// y = mx + h
|
|
221
|
+
// px, py => h = -m px + py => mx - y -m.px + py = 0 =>
|
|
222
|
+
// Centre: cx, cy, radius: r
|
|
223
|
+
// (m.cx - cy -m.px + py)^2 = r^2 * (m^2 + 1)
|
|
224
|
+
// (m(cx-py) - (cy - py))^2 = r^2 * (m^2 + 1)
|
|
225
|
+
|
|
226
|
+
const cx_px = this.center.x.clone().subtract(P.x), cy_py = this.center.y.clone().subtract(P.y),
|
|
227
|
+
polyLeft = new Polynom('x'), polyRight = new Polynom('x^2+1')
|
|
228
|
+
|
|
229
|
+
polyLeft.multiply(cx_px).subtract(cy_py).pow(2)
|
|
230
|
+
polyRight.multiply(this.squareRadius)
|
|
231
|
+
|
|
232
|
+
const equ = new Equation(polyLeft, polyRight)
|
|
233
|
+
const solutions = equ.solve()
|
|
234
|
+
|
|
235
|
+
return solutions.map(sol => {
|
|
236
|
+
// h = -m px + py
|
|
237
|
+
let h: Fraction
|
|
238
|
+
const equ = new Equation('y', 'x')
|
|
239
|
+
|
|
240
|
+
if (sol.exact instanceof Fraction) {
|
|
241
|
+
h = P.x.clone().opposite().multiply(sol.exact).add(P.y)
|
|
242
|
+
equ.right.multiply(sol.exact).add(h)
|
|
243
|
+
} else {
|
|
244
|
+
h = P.x.clone().opposite().multiply(sol.value).add(P.y)
|
|
245
|
+
equ.right.multiply(sol.value).add(h)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return new Line(equ)
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
#tangentsWithSlope = (slope: Fraction): Line[] => {
|
|
254
|
+
// d(C;t)=r => ac1+bc2 + x = +- sqrt(a^2 + b^2)*r
|
|
255
|
+
// x = -ac1-bc2 +- sqrt(a^2 + b^2)*r
|
|
256
|
+
// y = a/bx + h => ax-by + H = 0
|
|
257
|
+
|
|
258
|
+
const a = slope.numerator, b = -slope.denominator, c1 = this.center.x.clone(), c2 = this.center.y.clone()
|
|
259
|
+
|
|
260
|
+
const sq = this.squareRadius.clone().multiply(slope.numerator ** 2 + slope.denominator ** 2),
|
|
261
|
+
x1 = c1.clone().multiply(a).opposite().subtract(c2.clone().multiply(b)).add(sq.clone().sqrt()),
|
|
262
|
+
x2 = c1.clone().multiply(a).opposite().subtract(c2.clone().multiply(b)).subtract(sq.clone().sqrt())
|
|
263
|
+
|
|
264
|
+
return [new Line(a, b, x1), new Line(a, b, x2)]
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
#reset(): this {
|
|
268
|
+
this.#center = undefined
|
|
269
|
+
this.#squareRadius = undefined
|
|
270
|
+
this.#cartesian = undefined
|
|
271
|
+
|
|
272
|
+
return this
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
parse(...values: unknown[]): this {
|
|
276
|
+
// Data can be given in these formats:
|
|
277
|
+
// one value, a string -> make it an Equation
|
|
278
|
+
// one value, an Equation
|
|
279
|
+
// one value, a circle -> clone it
|
|
280
|
+
// two values: two points (center and pointThrough)
|
|
281
|
+
// two values: point and Fraction (center and radius)
|
|
282
|
+
// three values: Vector2D, Fraction, Boolean (center, square radius, true)
|
|
283
|
+
|
|
284
|
+
this.#reset()
|
|
285
|
+
|
|
286
|
+
if (typeof values[0] === 'string') {
|
|
287
|
+
this.#parseEquation(new Equation(values[0]))
|
|
288
|
+
} else if (values[0] instanceof Equation) {
|
|
289
|
+
this.#parseEquation(values[0])
|
|
290
|
+
} else if (values[0] instanceof Circle) {
|
|
291
|
+
this.#parseCopyCircle(values[0])
|
|
292
|
+
} else if (values[0] instanceof Point && values.length > 1) {
|
|
293
|
+
if (values[1] instanceof Point) {
|
|
294
|
+
if (values[2] instanceof Point) {
|
|
295
|
+
// TODO: Add the method to parse through three points
|
|
296
|
+
// this._parseThroughtThreePoints(values[0], values[1], values[2])
|
|
297
|
+
} else {
|
|
298
|
+
this.#parseCenterAndPointThrough(values[0], values[1])
|
|
299
|
+
}
|
|
300
|
+
} else if (values[1] instanceof Fraction || typeof values[1] === 'number') {
|
|
301
|
+
this.#parseCenterAndRadius(values[0], values[1], (typeof values[2] === "boolean") ? values[2] : false)
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Calculate once the different values.
|
|
306
|
+
this.#calculateCartesian()
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
return this
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
#calculateCartesian() {
|
|
313
|
+
this.#cartesian = (
|
|
314
|
+
new Equation(
|
|
315
|
+
new Polynom(`(x-(${this.center.x.display}))^2+(y-(${this.center.y.display}))^2`),
|
|
316
|
+
new Polynom(this.squareRadius.display))
|
|
317
|
+
).moveLeft()
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
#parseCopyCircle(circle: Circle): this {
|
|
321
|
+
this.#center = circle.center.clone()
|
|
322
|
+
this.#squareRadius = circle.squareRadius.clone()
|
|
323
|
+
this.#calculateCartesian()
|
|
324
|
+
return this
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
#parseCenterAndRadius(center: Point, radius: Fraction | number, square?: boolean): this {
|
|
328
|
+
this.#center = center.clone()
|
|
329
|
+
if (square) {
|
|
330
|
+
this.#squareRadius = (new Fraction(radius))
|
|
331
|
+
} else {
|
|
332
|
+
this.#squareRadius = new Fraction(radius).pow(2)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return this
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
#parseCenterAndPointThrough(center: Point, pointThrough: Point): this {
|
|
339
|
+
this.#center = center.clone()
|
|
340
|
+
this.#squareRadius = new Vector(this.#center, pointThrough).normSquare
|
|
341
|
+
return this
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
#parseEquation(equ: Equation): this {
|
|
345
|
+
|
|
346
|
+
// Move everything to the left.
|
|
347
|
+
equ.moveLeft()
|
|
348
|
+
|
|
349
|
+
if (equ.degree('x').value === 2 && equ.degree('y').value === 2) {
|
|
350
|
+
// Both must be of degree 2.
|
|
351
|
+
const x2 = equ.left.monomByDegree(2, 'x'), y2 = equ.left.monomByDegree(2, 'y')
|
|
352
|
+
let x1: Monom, y1: Monom, c: Monom
|
|
353
|
+
|
|
354
|
+
// Both square monoms must have the same coefficient.
|
|
355
|
+
if (x2.coefficient.isEqual(y2.coefficient)) {
|
|
356
|
+
equ.divide(x2.coefficient)
|
|
357
|
+
|
|
358
|
+
x1 = equ.left.monomByDegree(1, 'x')
|
|
359
|
+
y1 = equ.left.monomByDegree(1, 'y')
|
|
360
|
+
|
|
361
|
+
c = equ.left.monomByDegree(0)
|
|
362
|
+
|
|
363
|
+
this.#center = new Point(x1.coefficient.clone().divide(2).opposite(), y1.coefficient.clone().divide(2).opposite())
|
|
364
|
+
|
|
365
|
+
this.#squareRadius = c.coefficient.clone().opposite()
|
|
366
|
+
.add(this.#center.x.clone().pow(2))
|
|
367
|
+
.add(this.#center.y.clone().pow(2))
|
|
368
|
+
|
|
369
|
+
} else {
|
|
370
|
+
// The circle is not a valid circle
|
|
371
|
+
this.#center = undefined
|
|
372
|
+
this.#squareRadius = undefined
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return this
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// private _parseThroughtThreePoints(A: Point, B: Point, C: Point): this {
|
|
379
|
+
// const T = new Triangle(A, B, C), mAB = T.remarquables.mediators.AB.clone(),
|
|
380
|
+
// mAC = T.remarquables.mediators.AC.clone()
|
|
381
|
+
// this.parse(mAB.intersection(mAC).point, A)
|
|
382
|
+
|
|
383
|
+
// return this
|
|
384
|
+
// }
|
|
385
|
+
|
|
386
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Fraction } from "../coefficients"
|
|
2
|
+
import type { Vector } from "./vector"
|
|
3
|
+
|
|
4
|
+
type V = Vector
|
|
5
|
+
export function areVectorsEquals(v1: V, v2: V): boolean {
|
|
6
|
+
return v1.dimension === v2.dimension &&
|
|
7
|
+
v1.array.every(
|
|
8
|
+
(value, index) => {
|
|
9
|
+
return v2.array[index].isEqual(value)
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function areVectorsColinears(v1: V, v2: V): boolean {
|
|
14
|
+
if (v1.dimension !== v2.dimension) { return false }
|
|
15
|
+
|
|
16
|
+
// Constant of proportionality
|
|
17
|
+
const k = v2.array[0].value / v1.array[0].value
|
|
18
|
+
return v1.array.every(
|
|
19
|
+
(value, index) => {
|
|
20
|
+
return v2.array[index].value === value.value * k
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
export function dotProduct(v1: V, v2: V): Fraction {
|
|
26
|
+
if (v1.dimension !== v2.dimension) { return new Fraction().invalid() }
|
|
27
|
+
|
|
28
|
+
// Calculate the dot product
|
|
29
|
+
// Why does the reduce not add the last element?
|
|
30
|
+
|
|
31
|
+
return v1.array.reduce(
|
|
32
|
+
(acc, value, index) => {
|
|
33
|
+
return acc.add(value.clone().multiply(v2.array[index]))
|
|
34
|
+
}, new Fraction(0))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function determinantFromVectors(...values: V[]): Fraction {
|
|
38
|
+
// TODO: Make it work for vectors of dimension n
|
|
39
|
+
// Check if the vectors are in the same dimension
|
|
40
|
+
if (values.some((value) => value.dimension !== values[0].dimension)) {
|
|
41
|
+
throw new Error('All vectors must have the same dimension')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Check if the vectors are in dimension 2 or 3 and that the number of values is correct
|
|
45
|
+
if (values[0].dimension !== values.length ) {
|
|
46
|
+
throw new Error(`The determinant of dimension ${values[0].dimension} must have the same number of vectors (${values.length} given)`)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Calculate the determinant 2x2
|
|
50
|
+
if (values[0].dimension === 2) {
|
|
51
|
+
return values[0].array[0].clone().multiply(values[1].array[1])
|
|
52
|
+
.subtract(values[0].array[1].clone().multiply(values[1].array[0]))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Calculate the determinant 3x3
|
|
56
|
+
return values[0].array[0].clone()
|
|
57
|
+
.multiply(
|
|
58
|
+
values[1].array[1].clone().multiply(values[2].array[2])
|
|
59
|
+
.subtract(values[1].array[2].clone().multiply(values[2].array[1]))
|
|
60
|
+
)
|
|
61
|
+
.subtract(values[0].array[1].clone()
|
|
62
|
+
.multiply(
|
|
63
|
+
values[1].array[0].clone().multiply(values[2].array[2])
|
|
64
|
+
.subtract(values[1].array[2].clone().multiply(values[2].array[0]))
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
.add(values[0].array[2].clone()
|
|
68
|
+
.multiply(values[1].array[0].clone().multiply(values[2].array[1])
|
|
69
|
+
.subtract(values[1].array[1].clone().multiply(values[2].array[0]))))
|
|
70
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Import / export every files from the geometry folder
|
|
2
|
+
export * from './geomMath'
|
|
3
|
+
export * from './circle'
|
|
4
|
+
export * from './line'
|
|
5
|
+
export * from './line3'
|
|
6
|
+
export * from './plane3'
|
|
7
|
+
export * from './point'
|
|
8
|
+
export * from './triangle'
|
|
9
|
+
export * from './vector'
|
|
10
|
+
export * from './sphere3'
|