pimath 0.0.132 → 0.0.133

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 (33) hide show
  1. package/dist/main.d.ts +39 -1
  2. package/package.json +2 -3
  3. package/dist/pimath.d.ts +0 -39
  4. package/lib/main.ts +0 -1
  5. package/lib/maths/algebra/equation.ts +0 -891
  6. package/lib/maths/algebra/linearSystem.ts +0 -369
  7. package/lib/maths/algebra/logicalset.ts +0 -183
  8. package/lib/maths/algebra/monom.ts +0 -1027
  9. package/lib/maths/algebra/polynom.ts +0 -1537
  10. package/lib/maths/algebra/rational.ts +0 -244
  11. package/lib/maths/algebra/study/rationalStudy.ts +0 -287
  12. package/lib/maths/algebra/study.ts +0 -506
  13. package/lib/maths/coefficients/fraction.ts +0 -593
  14. package/lib/maths/coefficients/nthRoot.ts +0 -148
  15. package/lib/maths/geometry/circle.ts +0 -379
  16. package/lib/maths/geometry/line.ts +0 -604
  17. package/lib/maths/geometry/point.ts +0 -215
  18. package/lib/maths/geometry/triangle.ts +0 -368
  19. package/lib/maths/geometry/vector.ts +0 -243
  20. package/lib/maths/numeric.ts +0 -162
  21. package/lib/maths/numexp.ts +0 -198
  22. package/lib/maths/randomization/random.ts +0 -80
  23. package/lib/maths/randomization/randomCore.ts +0 -19
  24. package/lib/maths/randomization/rndFraction.ts +0 -47
  25. package/lib/maths/randomization/rndGeometryCircle.ts +0 -50
  26. package/lib/maths/randomization/rndGeometryLine.ts +0 -53
  27. package/lib/maths/randomization/rndGeometryPoint.ts +0 -69
  28. package/lib/maths/randomization/rndHelpers.ts +0 -107
  29. package/lib/maths/randomization/rndMonom.ts +0 -57
  30. package/lib/maths/randomization/rndPolynom.ts +0 -90
  31. package/lib/maths/randomization/rndTypes.ts +0 -43
  32. package/lib/maths/shutingyard.ts +0 -496
  33. package/lib/pimath.ts +0 -40
@@ -1,604 +0,0 @@
1
- /**
2
- * This class works for 2d line in a plane.
3
- */
4
-
5
- import {Vector} from "./vector";
6
- import {Point} from "./point";
7
- import {Numeric} from "../numeric.ts";
8
- import {Fraction} from "../coefficients/fraction";
9
- import {Equation} from "../algebra/equation";
10
- import {Polynom} from "../algebra/polynom";
11
- import {Random} from "../randomization/random";
12
- import {Monom} from "../algebra/monom";
13
-
14
- export enum LinePropriety {
15
- None,
16
- Parallel = 'parallel',
17
- Perpendicular = 'perpendicular',
18
- Tangent = 'tangent'
19
- }
20
-
21
- export class Line {
22
- // A line is defined as the canonical form
23
- static PERPENDICULAR = LinePropriety.Perpendicular
24
- static PARALLEL = LinePropriety.Parallel
25
- private _referencePropriety: LinePropriety
26
- private _referenceLine: Line
27
- private _reduceBeforeDisplay: boolean
28
- // ax + by + c = 0
29
- private _a: Fraction;
30
- private _b: Fraction;
31
- private _c: Fraction;
32
- private _OA: Point;
33
- private _d: Vector;
34
- private _n: Vector;
35
- private _exists: boolean
36
-
37
- /**
38
- * Value can be a mix of:
39
- *
40
- * @param values
41
- */
42
- constructor(...values: unknown[]) {
43
-
44
- this._exists = false;
45
- this._reduceBeforeDisplay = true
46
-
47
- if (values.length > 0) {
48
- this.parse(...values);
49
- }
50
-
51
- return this;
52
- }
53
-
54
- get a(): Fraction {
55
- return this._a;
56
- }
57
-
58
- // ------------------------------------------
59
- // Getter and setter
60
-
61
- set a(value: Fraction) {
62
- this._a = value;
63
- }
64
-
65
- get b(): Fraction {
66
- return this._b;
67
- }
68
-
69
- set b(value: Fraction) {
70
- this._b = value;
71
- }
72
-
73
- get c(): Fraction {
74
- return this._c;
75
- }
76
-
77
- set c(value: Fraction) {
78
- this._c = value;
79
- }
80
-
81
- get OA(): Point {
82
- return this._OA;
83
- }
84
-
85
- set OA(value: Point) {
86
- this._OA = value;
87
- }
88
-
89
- get d(): Vector {
90
- return this._d;
91
- }
92
-
93
- set d(value: Vector) {
94
- this._d = value;
95
- }
96
-
97
- get n(): Vector {
98
- return this._n;
99
- }
100
-
101
- get exists(): boolean {
102
- return this._exists;
103
- }
104
-
105
- // ------------------------------------------
106
- get equation(): Equation {
107
- let equ = new Equation(new Polynom().parse('xy', this._a, this._b, this._c), new Polynom('0'))
108
- if (this._reduceBeforeDisplay) {
109
- return equ.simplify();
110
- } else {
111
- return equ
112
- }
113
- }
114
-
115
- get system(): { x: Equation, y: Equation } {
116
- let e1 = new Equation(
117
- new Polynom('x'),
118
- new Polynom(this._OA.x)
119
- .add(new Monom('k').multiplyByNumber(this._d.x))
120
- ),
121
- e2 = new Equation(
122
- new Polynom('y'),
123
- new Polynom(this._OA.y)
124
- .add(new Monom('k').multiplyByNumber(this._d.y))
125
- )
126
-
127
- return {x: e1, y: e2}
128
- }
129
-
130
- get tex(): { canonical: string, mxh: string, parametric: string, equation: string, system: string } {
131
- // canonical => ax + by + c = 0
132
- // mxh => y = -a/b x - c/b
133
- // parametric => (xy) = OA + k*d
134
- // equation => ax + by = -c
135
-
136
- let canonical = this.equation.clone().reorder(true);
137
- // Make sur the first item is positive.
138
- if (this._a.isNegative()) {
139
- canonical.multiply(-1);
140
- }
141
-
142
- let d = this._d.clone()
143
- if (this._reduceBeforeDisplay) {
144
- d.simplifyDirection()
145
- }
146
-
147
- return {
148
- canonical: canonical.tex,
149
- equation: canonical.clone().reorder().tex,
150
- mxh: this.slope.isInfinity() ? 'x=' + this.OA.x.tex : 'y=' + new Polynom().parse('x', this.slope, this.height).tex,
151
- parametric: `${Point.pmatrix('x', 'y')} = ${Point.pmatrix(this._OA.x, this._OA.y)} + k\\cdot ${Point.pmatrix(d.x, d.y)}`,
152
- system: `\\left\\{\\begin{aligned}
153
- x &= ${(new Polynom(this._OA.x)
154
- .add(new Monom(this._d.x).multiply(new Monom('k'))))
155
- .reorder('k', true)
156
- .tex}\\\\\
157
- y &= ${(new Polynom(this._OA.y)
158
- .add(new Monom(this._d.y).multiply(new Monom('k'))))
159
- .reorder('k', true)
160
- .tex}
161
- \\end{aligned}\\right.`
162
- }
163
- }
164
-
165
- get reduceBeforeDisplay(): boolean {
166
- return this._reduceBeforeDisplay;
167
- }
168
-
169
- set reduceBeforeDisplay(value: boolean) {
170
- this._reduceBeforeDisplay = value;
171
- }
172
-
173
- get display(): { canonical: string, mxh: string, parametric: string } {
174
- // canonical => ax + by + c = 0
175
- // mxh => y = -a/b x - c/b
176
- // parametric => (xy) = OA + k*d // not relevant in display mode.
177
-
178
- let canonical = this.equation;
179
- // Make sur the first item is positive.
180
- if (this._a.isNegative()) {
181
- canonical.multiply(-1);
182
- }
183
-
184
- return {
185
- canonical: canonical.display,
186
- mxh: this.slope.isInfinity() ? 'x=' + this.OA.x.display : 'y=' + new Polynom().parse('x', this.slope, this.height).display,
187
- parametric: ""
188
- }
189
- }
190
-
191
- get normal(): Vector {
192
- return new Vector(this._a, this._b);
193
- }
194
-
195
- get director(): Vector {
196
- return this._d.clone()
197
- }
198
-
199
- get slope(): Fraction {
200
- return this._a.clone().opposed().divide(this._b);
201
- }
202
-
203
- get height(): Fraction {
204
- return this._c.clone().opposed().divide(this._b);
205
- }
206
-
207
- randomPoint = (k?: number): Point => {
208
- // Return a random point on the line.
209
- return this._d
210
- .clone()
211
- .multiplyByScalar(Random.numberSym((k === undefined || k <= 1) ? 3 : k, false))
212
- .add(this._OA.asVector)
213
- .asPoint
214
- }
215
- randomNearPoint = (k?: number): Point => {
216
- let pt = this.randomPoint(k)
217
-
218
- let maxIterationTest = 10
219
- while (this.isOnLine(pt) && maxIterationTest > 0) {
220
- pt.x.add(Random.numberSym(1, false))
221
- pt.y.add(Random.numberSym(1, false))
222
- maxIterationTest--
223
-
224
- }
225
- return pt
226
- }
227
-
228
- // ------------------------------------------
229
- // Creation / parsing functions
230
-
231
- // ------------------------------------------
232
- /**
233
- * Parse data to a line
234
- * @param {any} values
235
- * @returns {Line}
236
- */
237
- parse = (...values: unknown[]): Line => {
238
- this._exists = false;
239
-
240
- // Nothing is given...
241
- if (values.length === 0) {
242
- return this
243
- }
244
-
245
- // One value only: already a line (clone it), an Equation, a string (as Equation)
246
- if (values.length === 1) {
247
- if (values[0] instanceof Line) {
248
- // Already a Line
249
- return values[0].clone()
250
- } else if (values[0] instanceof Equation) {
251
- // It's an Equation
252
- return this.parseEquation(values[0])
253
- } else if (typeof values[0] === "string") {
254
- // It's a string - create an Equation from it.
255
- try {
256
- let E = new Equation(values[0])
257
- return this.parse(E)
258
- } catch (e) {
259
- return this
260
- }
261
- }
262
- }
263
-
264
- if (values.length === 2) {
265
- if (values[0] instanceof Point && values[1] instanceof Vector) {
266
- return this.parseByPointAndVector(values[0], values[1]);
267
- } else if (values[0] instanceof Point && values[1] instanceof Point) {
268
- return this.parseByPointAndVector(values[0], new Vector(values[0], values[1]));
269
- } else if (values[0] instanceof Vector && values[1] instanceof Point) {
270
- return this.parseByPointAndNormal(values[1], values[0])
271
- }
272
- }
273
-
274
- if (values.length === 3) {
275
- if (
276
- (values[0] instanceof Fraction || typeof values[0] === 'number')
277
- &&
278
- (values[1] instanceof Fraction || typeof values[1] === 'number')
279
- &&
280
- (values[2] instanceof Fraction || typeof values[2] === 'number')
281
- ) {
282
- return this.parseByCoefficient(values[0], values[1], values[2]);
283
- } else if (
284
- values[0] instanceof Point && values[1] instanceof Vector
285
- ) {
286
- if (values[2] === LinePropriety.Perpendicular) {
287
- return this.parseByPointAndNormal(values[0], values[1])
288
- } else if (values[2] === LinePropriety.Parallel) {
289
- return this.parseByPointAndVector(values[0], values[1])
290
- }
291
- } else if (values[0] instanceof Point && values[1] instanceof Line) {
292
- if (values[2] === LinePropriety.Parallel || values[2] === null) {
293
- return this.parseByPointAndLine(values[0], values[1], LinePropriety.Parallel)
294
- } else {
295
- return this.parseByPointAndLine(values[0], values[1], LinePropriety.Perpendicular)
296
- }
297
- }
298
- }
299
-
300
- // TODO: Add the ability to create line from a normal vector
301
- console.log('Someting wrong happend while creating the line')
302
- return this;
303
- }
304
-
305
- parseEquation = (equ: Equation): Line => {
306
- // Reorder the eequation
307
- equ.reorder(true)
308
-
309
- // It must contain either x, y or both.
310
- let letters = new Set(equ.letters());
311
-
312
- // No 'x', no 'y' in the equations
313
- if (!(letters.has('x') || letters.has('y'))) {
314
- return this
315
- }
316
-
317
- // Another letter in the equation ?
318
- for (let elem of ['x', 'y']) {
319
- if (letters.has(elem)) {
320
- letters.delete(elem)
321
- }
322
- }
323
-
324
- if (letters.size > 0) {
325
- return this
326
- }
327
-
328
- // Everything should be ok now...
329
- return this.parseByCoefficient(equ.left.monomByLetter('x').coefficient, equ.left.monomByLetter('y').coefficient, equ.left.monomByDegree(0).coefficient)
330
- }
331
- parseByCoefficient = (a: Fraction | number, b: Fraction | number, c: Fraction | number): Line => {
332
- this._a = new Fraction(a);
333
- this._b = new Fraction(b);
334
- this._c = new Fraction(c);
335
-
336
- this._d = new Vector(this._b.clone(), this._a.clone().opposed());
337
- this._OA = new Point(new Fraction().zero(), this._c.clone());
338
- this._n = this._d.clone().normal();
339
-
340
- this._exists = true;
341
- return this;
342
- }
343
-
344
- parseByPointAndVector = (P: Point, d: Vector): Line => {
345
- // OX = OP + k*d
346
- // x = px + kdx * dy
347
- // y = py + kdy * dx
348
- // ------------------
349
- // dy * x = px * dy + kdxdy
350
- // dx * y = py * dx + kdxdy
351
- // ------------------
352
- // dy * x - dx * y = px * dy - py * dx
353
- // dy * x - dx * y - (px * dy - py * dx) = 0
354
- this.parseByCoefficient(
355
- d.y,
356
- d.x.clone().opposed(),
357
- P.x.clone().multiply(d.y).subtract(P.y.clone().multiply(d.x)).opposed()
358
- )
359
-
360
- // Choose the current values as point and direction vector instead of the automatic version.
361
- this._OA = P.clone();
362
- this._d = d.clone();
363
- this._n = this._d.clone().normal();
364
-
365
- this._exists = true;
366
- return this;
367
- }
368
-
369
- parseByPointAndNormal = (P: Point, n: Vector): Line => {
370
- return this.parseByCoefficient(
371
- n.x,
372
- n.y,
373
- P.x.clone().multiply(n.x)
374
- .add(P.y.clone().multiply(n.y)).opposed()
375
- )
376
- }
377
-
378
- parseByPointAndLine = (P: Point, L: Line, orientation?: LinePropriety): Line => {
379
-
380
- if (orientation === undefined) {
381
- orientation = LinePropriety.Parallel
382
- }
383
-
384
- if (orientation === LinePropriety.Parallel) {
385
- return this.parseByPointAndNormal(P, L.normal)
386
- } else if (orientation === LinePropriety.Perpendicular) {
387
- return this.parseByPointAndNormal(P, L.director)
388
- }
389
-
390
- this._exists = false
391
- return this
392
- }
393
-
394
- clone = (): Line => {
395
- this._a = this._a.clone();
396
- this._b = this._b.clone();
397
- this._c = this._c.clone();
398
-
399
- this._d = this._d.clone();
400
- this._OA = this._OA.clone();
401
- this._n = this._n.clone();
402
-
403
- this._exists = this.exists
404
- return this;
405
- }
406
- // ------------------------------------------
407
- // Mathematical operations
408
- // ------------------------------------------
409
- isOnLine = (pt: Point): Boolean => {
410
- return this._a.clone()
411
- .multiply(pt.x)
412
- .add(
413
- this._b.clone()
414
- .multiply(pt.y)
415
- )
416
- .add(this._c)
417
- .isZero()
418
- }
419
-
420
- isParallelTo = (line: Line): Boolean => {
421
- // Do they have the isSame direction ?
422
- return this.slope.isEqual(line.slope) && this.height.isNotEqual(line.height);
423
- }
424
- isSameAs = (line: Line): Boolean => {
425
- return this.slope.isEqual(line.slope) && this.height.isEqual(line.height);
426
- }
427
- isPerpendicularTo = (line: Line): Boolean => {
428
- return this.d.isNormalTo(line.d)
429
- }
430
- isVertical = (): Boolean => {
431
- return this.slope.isInfinity()
432
- }
433
- simplify = (): Line => {
434
- let lcm = Numeric.lcm(this._a.denominator, this._b.denominator, this._c.denominator),
435
- gcd = Numeric.gcd(this._a.numerator, this._b.numerator, this._c.numerator);
436
-
437
- this.parseByCoefficient(
438
- this._a.clone().multiply(lcm).divide(gcd),
439
- this._b.clone().multiply(lcm).divide(gcd),
440
- this._c.clone().multiply(lcm).divide(gcd),
441
- )
442
-
443
- return this
444
- }
445
-
446
- simplifyDirection = (): Line => {
447
- this._d.simplifyDirection()
448
- return this;
449
- }
450
- intersection = (line: Line): { point: Point, hasIntersection: boolean, isParallel: boolean, isSame: boolean } => {
451
- let Pt = new Point(), isParallel = false, isSame = false, hasIntersection = true;
452
-
453
- // this => ax+by+c = 0
454
- // line => dx+ey+f = 0
455
- //
456
- // aex + bey + ce = 0
457
- // dbx + bey + bf = 0
458
- // (ae-db)x + ce-bf = 0
459
- //
460
- // adx + bdy + cd = 0
461
- // adx + aey + af = 0
462
- // (bd-ae)y + (cd-af)
463
- //
464
- // x = (bf-ce)/(ae-db)
465
- // y = (af-cd)/(bd-ae)
466
-
467
-
468
- // Theres is no 'y'
469
- if (this._b.isZero() || line.b.isZero()) {
470
- // TODO : handle no y in the line canonical form
471
- }
472
-
473
- if (this.isParallelTo(line)) {
474
- Pt.x = null;
475
- Pt.y = null;
476
- isParallel = true;
477
- } else if (this.isSameAs(line)) {
478
- Pt.x = null;
479
- Pt.y = null;
480
- isSame = true;
481
- } else {
482
- Pt.x = this._b.clone().multiply(line.c).subtract(this._c.clone().multiply(line.b))
483
- .divide(this._a.clone().multiply(line.b).subtract(this._b.clone().multiply(line.a)));
484
- Pt.y = this._a.clone().multiply(line.c).subtract(this._c.clone().multiply(line.a))
485
- .divide(this._b.clone().multiply(line.a).subtract(this._a.clone().multiply(line.b)));
486
- }
487
-
488
- return {
489
- point: Pt,
490
- hasIntersection: !(isParallel || isSame),
491
- isParallel,
492
- isSame
493
- };
494
- }
495
-
496
- distanceTo(pt: Point): { value: number, fraction: Fraction, tex: string } {
497
- let numerator = pt.x.clone().multiply(this._a)
498
- .add(pt.y.clone().multiply(this._b))
499
- .add(this._c).abs(),
500
- d2 = this.normal.normSquare;
501
-
502
- // The denominator is null - shouldn't be possible
503
- if (d2.isZero()) {
504
- return {
505
- value: NaN,
506
- tex: 'Not a line',
507
- fraction: new Fraction().infinite()
508
- }
509
- }
510
- // The denominator is a perfect square - simplify the tex result
511
- let value = numerator.value / Math.sqrt(d2.value),
512
- F = numerator.clone().divide(d2.clone().sqrt());
513
-
514
- // The denominator is a perfect square.
515
- if (d2.isSquare()) {
516
- return {
517
- value,
518
- tex: F.tex,
519
- fraction: F
520
- }
521
- }
522
- // Complete answer...
523
- return {
524
- value,
525
- tex: `\\frac{${numerator.tex}}{\\sqrt{${d2.tex}}}`,
526
- fraction: F
527
- };
528
- }
529
-
530
- hitSegment(A: Point, B: Point): boolean {
531
- let iPt = this.intersection(
532
- new Line(A, B)
533
- )
534
-
535
- // There is an intersection point
536
- if (iPt.hasIntersection) {
537
- return iPt.point.x.value >= Math.min(A.x.value, B.x.value)
538
- && iPt.point.x.value <= Math.max(A.x.value, B.x.value)
539
- && iPt.point.y.value >= Math.min(A.y.value, B.y.value)
540
- && iPt.point.y.value <= Math.max(A.y.value, B.y.value)
541
- }
542
- return false;
543
- }
544
-
545
- getValueAtX = (value: Fraction | number): Fraction => {
546
- const equ = this.equation.clone().isolate('y'),
547
- F = new Fraction(value)
548
-
549
- if (equ instanceof Equation) {
550
- return equ.right.evaluate({x: F})
551
- }
552
- return
553
- }
554
- getValueAtY = (value: Fraction | number): Fraction => {
555
- const equ = this.equation.clone().isolate('x'),
556
- F = new Fraction(value)
557
-
558
- if (equ instanceof Equation) {
559
- return equ.right.evaluate({y: F})
560
- }
561
- return
562
- }
563
-
564
- // ------------------------------------------
565
- // Special functions
566
- // ------------------------------------------
567
- canonicalAsFloatCoefficient(decimals: number): string {
568
- if (decimals === undefined) {
569
- decimals = 2;
570
- }
571
-
572
- let ca = this._a.value,
573
- cb = this._b.value,
574
- cc = this._c.value,
575
- canonical = '';
576
-
577
- if (!this._a.isZero()) {
578
- if (this._a.isOne()) {
579
- canonical = 'x'
580
- } else if (this._a.clone().opposed().isOne()) {
581
- canonical = '-x'
582
- } else {
583
- canonical = this._a.value.toFixed(decimals) + 'x'
584
- }
585
- }
586
-
587
- if (!this._b.isZero()) {
588
- if (this._b.isPositive()) {
589
- canonical += '+'
590
- }
591
- canonical += this._b.value.toFixed(decimals) + 'y'
592
- }
593
-
594
- if (!this._c.isZero()) {
595
- if (this._c.isPositive()) {
596
- canonical += '+'
597
- }
598
- canonical += this._c.value.toFixed(decimals)
599
- }
600
-
601
-
602
- return canonical + '=0';
603
- }
604
- }