pimath 0.0.33 → 0.0.34
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/pi.js +6530 -1
- package/dist/pi.js.map +1 -1
- package/dist/pi.min.js +2 -0
- package/dist/pi.min.js.map +1 -0
- package/docs/assets/search.js +1 -1
- package/docs/classes/algebra.Equation.html +9 -9
- package/docs/classes/algebra.LinearSystem.html +1 -1
- package/docs/classes/algebra.Logicalset.html +2 -2
- package/docs/classes/algebra.Monom.html +37 -37
- package/docs/classes/algebra.Polynom.html +10 -10
- package/docs/classes/algebra.PolynomExpFactor.html +1 -1
- package/docs/classes/algebra.PolynomExpProduct.html +1 -1
- package/docs/classes/algebra.Rational.html +2 -2
- package/docs/classes/coefficients.Fraction.html +4 -4
- package/docs/classes/coefficients.Nthroot.html +1 -1
- package/docs/classes/geometry.Circle.html +2 -2
- package/docs/classes/geometry.Line.html +2 -2
- package/docs/classes/geometry.Point.html +1 -1
- package/docs/classes/geometry.Triangle.html +5 -5
- package/docs/classes/geometry.Vector.html +1 -1
- package/docs/classes/numeric.Numeric.html +5 -5
- package/docs/classes/shutingyard.Shutingyard.html +4 -4
- package/docs/enums/geometry.LinePropriety.html +1 -0
- package/docs/enums/shutingyard.ShutingyardMode.html +1 -1
- package/docs/enums/shutingyard.ShutingyardType.html +1 -1
- package/docs/interfaces/geometry.remarquableLines.html +1 -1
- package/docs/modules/algebra.html +1 -1
- package/docs/modules/coefficients.html +1 -1
- package/docs/modules/geometry.html +1 -1
- package/docs/modules/random.Random.html +1 -1
- package/docs/modules/random.html +1 -1
- package/docs/modules/shutingyard.html +1 -1
- package/esm/main.js +2 -0
- package/esm/main.js.map +1 -1
- package/esm/maths/algebra/equation.d.ts +62 -17
- package/esm/maths/algebra/equation.js +597 -502
- package/esm/maths/algebra/equation.js.map +1 -1
- package/esm/maths/algebra/linearSystem.js +154 -101
- package/esm/maths/algebra/linearSystem.js.map +1 -1
- package/esm/maths/algebra/logicalset.d.ts +11 -0
- package/esm/maths/algebra/logicalset.js +18 -6
- package/esm/maths/algebra/logicalset.js.map +1 -1
- package/esm/maths/algebra/monom.d.ts +144 -0
- package/esm/maths/algebra/monom.js +624 -396
- package/esm/maths/algebra/monom.js.map +1 -1
- package/esm/maths/algebra/polynom.d.ts +49 -0
- package/esm/maths/algebra/polynom.js +995 -712
- package/esm/maths/algebra/polynom.js.map +1 -1
- package/esm/maths/algebra/rational.d.ts +12 -0
- package/esm/maths/algebra/rational.js +97 -82
- package/esm/maths/algebra/rational.js.map +1 -1
- package/esm/maths/coefficients/fraction.d.ts +18 -0
- package/esm/maths/coefficients/fraction.js +390 -332
- package/esm/maths/coefficients/fraction.js.map +1 -1
- package/esm/maths/coefficients/nthroot.d.ts +3 -0
- package/esm/maths/coefficients/nthroot.js +48 -33
- package/esm/maths/coefficients/nthroot.js.map +1 -1
- package/esm/maths/expressions/numexp.js +11 -3
- package/esm/maths/expressions/numexp.js.map +1 -1
- package/esm/maths/expressions/polynomexp.bkp.js +93 -93
- package/esm/maths/expressions/polynomexp.bkp.js.map +1 -1
- package/esm/maths/expressions/polynomexp.js +22 -9
- package/esm/maths/expressions/polynomexp.js.map +1 -1
- package/esm/maths/geometry/circle.d.ts +18 -6
- package/esm/maths/geometry/circle.js +139 -42
- package/esm/maths/geometry/circle.js.map +1 -1
- package/esm/maths/geometry/line.d.ts +9 -2
- package/esm/maths/geometry/line.js +245 -188
- package/esm/maths/geometry/line.js.map +1 -1
- package/esm/maths/geometry/point.d.ts +12 -0
- package/esm/maths/geometry/point.js +121 -73
- package/esm/maths/geometry/point.js.map +1 -1
- package/esm/maths/geometry/triangle.d.ts +22 -0
- package/esm/maths/geometry/triangle.js +197 -158
- package/esm/maths/geometry/triangle.js.map +1 -1
- package/esm/maths/geometry/vector.d.ts +4 -0
- package/esm/maths/geometry/vector.js +139 -115
- package/esm/maths/geometry/vector.js.map +1 -1
- package/esm/maths/numeric.d.ts +17 -0
- package/esm/maths/numeric.js +40 -0
- package/esm/maths/numeric.js.map +1 -1
- package/esm/maths/random/randomCore.js +15 -15
- package/esm/maths/random/randomCore.js.map +1 -1
- package/esm/maths/random/rndFraction.d.ts +3 -0
- package/esm/maths/random/rndFraction.js +19 -16
- package/esm/maths/random/rndFraction.js.map +1 -1
- package/esm/maths/random/rndHelpers.d.ts +17 -0
- package/esm/maths/random/rndHelpers.js +20 -0
- package/esm/maths/random/rndHelpers.js.map +1 -1
- package/esm/maths/random/rndMonom.d.ts +3 -0
- package/esm/maths/random/rndMonom.js +33 -26
- package/esm/maths/random/rndMonom.js.map +1 -1
- package/esm/maths/random/rndPolynom.d.ts +3 -0
- package/esm/maths/random/rndPolynom.js +49 -37
- package/esm/maths/random/rndPolynom.js.map +1 -1
- package/esm/maths/shutingyard.d.ts +21 -0
- package/esm/maths/shutingyard.js +86 -9
- package/esm/maths/shutingyard.js.map +1 -1
- package/package.json +2 -2
- package/public/index.html +47 -0
- package/src/maths/algebra/equation.ts +142 -128
- package/src/maths/geometry/circle.ts +168 -75
- package/src/maths/geometry/line.ts +1 -1
- package/src/maths/geometry/point.ts +25 -2
- package/src/maths/numeric.ts +15 -0
- package/tests/geometry/circle.test.ts +33 -0
- package/tsconfig.json +2 -2
- package/webpack-production-min.config.js +26 -0
- package/webpack-production.config.js +1 -1
- package/dev/pi.js +0 -5392
- package/dev/pi.js.map +0 -1
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import {Point} from "./point";
|
|
2
2
|
import {Fraction} from "../coefficients";
|
|
3
3
|
import {Equation, Monom, Polynom} from "../algebra";
|
|
4
|
-
import {Line} from "./line";
|
|
4
|
+
import {Line, LinePropriety} from "./line";
|
|
5
5
|
import {Vector} from "./vector";
|
|
6
6
|
import {Triangle} from "./triangle";
|
|
7
|
+
import {Numeric} from "../numeric";
|
|
7
8
|
|
|
8
9
|
export class Circle {
|
|
9
|
-
private _center: Point;
|
|
10
|
-
private _squareRadius: Fraction;
|
|
11
|
-
private _cartesian: Equation;
|
|
12
|
-
private _exists: boolean;
|
|
13
|
-
|
|
14
10
|
constructor(...values: unknown[]) {
|
|
15
11
|
this._exists = false
|
|
16
12
|
|
|
@@ -19,30 +15,42 @@ export class Circle {
|
|
|
19
15
|
}
|
|
20
16
|
}
|
|
21
17
|
|
|
18
|
+
private _center: Point;
|
|
22
19
|
|
|
23
20
|
get center(): Point {
|
|
24
21
|
return this._center;
|
|
25
22
|
}
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
get exists(): boolean {
|
|
29
|
-
return this._exists;
|
|
30
|
-
}
|
|
24
|
+
private _squareRadius: Fraction;
|
|
31
25
|
|
|
32
26
|
get squareRadius(): Fraction {
|
|
33
27
|
return this._squareRadius
|
|
34
28
|
}
|
|
35
29
|
|
|
36
|
-
|
|
30
|
+
private _cartesian: Equation;
|
|
31
|
+
|
|
32
|
+
get cartesian(): Equation {
|
|
33
|
+
return this._cartesian
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private _exists: boolean;
|
|
37
|
+
|
|
38
|
+
get exists(): boolean {
|
|
39
|
+
return this._exists;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get radius(): { tex: string, display: string, value: number } {
|
|
37
43
|
if (this._squareRadius.isSquare()) {
|
|
38
44
|
return {
|
|
39
45
|
tex: this._squareRadius.clone().sqrt().tex,
|
|
40
46
|
display: this._squareRadius.clone().sqrt().display,
|
|
47
|
+
value: this._squareRadius.clone().sqrt().value
|
|
41
48
|
}
|
|
42
49
|
} else {
|
|
43
50
|
return {
|
|
44
51
|
tex: `\\sqrt{${this._squareRadius.tex}}`,
|
|
45
|
-
display: `sqrt(${this._squareRadius.display})
|
|
52
|
+
display: `sqrt(${this._squareRadius.display})`,
|
|
53
|
+
value: this._squareRadius.clone().sqrt().value
|
|
46
54
|
}
|
|
47
55
|
}
|
|
48
56
|
return this._squareRadius
|
|
@@ -72,14 +80,100 @@ export class Circle {
|
|
|
72
80
|
return this._cartesian.tex
|
|
73
81
|
}
|
|
74
82
|
|
|
75
|
-
|
|
76
83
|
// TODO: reformat code for better display.
|
|
77
84
|
get display(): string {
|
|
78
85
|
return this._cartesian.display
|
|
79
86
|
}
|
|
80
87
|
|
|
81
|
-
|
|
82
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Get the relative position between circle and line. It corresponds to the number of intersection.
|
|
90
|
+
* @param {Line} L
|
|
91
|
+
* @returns {number}
|
|
92
|
+
*/
|
|
93
|
+
relativePosition = (L: Line): number => {
|
|
94
|
+
let distance = L.distanceTo(this.center), radius = Math.sqrt(this._squareRadius.value)
|
|
95
|
+
|
|
96
|
+
if (distance.value - radius > 0.0000000001) {
|
|
97
|
+
return 0 // external
|
|
98
|
+
} else if (Math.abs(distance.value - radius) < 0.0000000001) {
|
|
99
|
+
return 1 // tangent
|
|
100
|
+
} else {
|
|
101
|
+
return 2 // external
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
lineIntersection = (L: Line): Point[] => {
|
|
106
|
+
let intersectionPoints: Point[] = [], solX: Fraction
|
|
107
|
+
|
|
108
|
+
if (this._cartesian === null) {
|
|
109
|
+
return []
|
|
110
|
+
}
|
|
111
|
+
const equX = this._cartesian.clone(), lineX = L.equation.clone().isolate('x'),
|
|
112
|
+
lineY = L.equation.clone().isolate('y')
|
|
113
|
+
|
|
114
|
+
if (lineX instanceof Equation && lineY instanceof Equation) {
|
|
115
|
+
equX.replaceBy('y', lineY.right).simplify()
|
|
116
|
+
equX.solve()
|
|
117
|
+
|
|
118
|
+
for (let x of equX.solutions) {
|
|
119
|
+
if (x.exact === false && isNaN(x.value)) {
|
|
120
|
+
continue
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
solX = new Fraction(x.exact === false ? x.value : x.exact)
|
|
124
|
+
intersectionPoints.push(new Point(solX.clone(), lineY.right.evaluate(solX)))
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return intersectionPoints
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
tangents = (P: Point | Fraction): Line[] => {
|
|
132
|
+
if (P instanceof Fraction) {
|
|
133
|
+
return this._tangentsWithSlope(P)
|
|
134
|
+
} else if (this.isPointOnCircle(P)) {
|
|
135
|
+
return this._tangentsThroughOnePointOnTheCircle(P)
|
|
136
|
+
} else if (this.center.distanceTo(P).value > this.radius.value) {
|
|
137
|
+
//TODO: Must check it's outside the circle
|
|
138
|
+
return this._tangentsThroughOnePointOutsideTheCircle(P)
|
|
139
|
+
} else {
|
|
140
|
+
console.log('No tangents as the point is inside !')
|
|
141
|
+
}
|
|
142
|
+
return []
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
isPointOnCircle = (P: Point): Boolean => {
|
|
146
|
+
return this._cartesian.test({x: P.x, y: P.y})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
getPointsOnCircle = (numberIsInteger?: boolean): Point[] => {
|
|
150
|
+
if (numberIsInteger === undefined) {
|
|
151
|
+
numberIsInteger = false
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// It means searching for pythagorician triples that make a perfect square.
|
|
155
|
+
// (x-4)^2 + (y+3)^2 = 15
|
|
156
|
+
|
|
157
|
+
let triplets = Numeric.pythagoricianTripletsWithTarget(this._squareRadius.value, true)
|
|
158
|
+
|
|
159
|
+
let points: Point[] = [], pt
|
|
160
|
+
triplets.forEach(triplet => {
|
|
161
|
+
// Allow positive / negative values
|
|
162
|
+
// x-a = t => x = a + t
|
|
163
|
+
// x-a = -t => x = a - t
|
|
164
|
+
|
|
165
|
+
for (let k of [[1, 1], [-1, 1], [-1, -1], [1, -1]]) {
|
|
166
|
+
pt = new Point(
|
|
167
|
+
this.center.x.clone().add(k[0] * triplet[0]),
|
|
168
|
+
this.center.y.clone().add(k[1] * triplet[1])
|
|
169
|
+
)
|
|
170
|
+
// Check if the point is not already in points.
|
|
171
|
+
if (!pt.isInListOfPoints(points)) {
|
|
172
|
+
points.push(pt)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
})
|
|
176
|
+
return points
|
|
83
177
|
}
|
|
84
178
|
|
|
85
179
|
clone(): Circle {
|
|
@@ -89,6 +183,59 @@ export class Circle {
|
|
|
89
183
|
return this
|
|
90
184
|
}
|
|
91
185
|
|
|
186
|
+
private _tangentsThroughOnePointOnTheCircle = (P: Point): Line[] => {
|
|
187
|
+
let CT = new Vector(this._center, P)
|
|
188
|
+
return [new Line(P, CT, LinePropriety.Perpendicular)]
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private _tangentsThroughOnePointOutsideTheCircle = (P: Point): Line[] => {
|
|
192
|
+
// y = mx + h
|
|
193
|
+
// px, py => h = -m px + py => mx - y -m.px + py = 0 =>
|
|
194
|
+
// Centre: cx, cy, radius: r
|
|
195
|
+
// (m.cx - cy -m.px + py)^2 = r^2 * (m^2 + 1)
|
|
196
|
+
// (m(cx-py) - (cy - py))^2 = r^2 * (m^2 + 1)
|
|
197
|
+
|
|
198
|
+
let cx_px = this.center.x.clone().subtract(P.x), cy_py = this.center.y.clone().subtract(P.y),
|
|
199
|
+
polyLeft = new Polynom('x'), polyRight = new Polynom('x^2+1')
|
|
200
|
+
|
|
201
|
+
polyLeft.multiply(cx_px).subtract(cy_py).pow(2)
|
|
202
|
+
polyRight.multiply(this.squareRadius)
|
|
203
|
+
|
|
204
|
+
let equ = new Equation(polyLeft, polyRight)
|
|
205
|
+
equ.moveLeft().simplify().solve()
|
|
206
|
+
|
|
207
|
+
return equ.solutions.map(sol => {
|
|
208
|
+
// h = -m px + py
|
|
209
|
+
let h, equ = new Equation('y', 'x')
|
|
210
|
+
|
|
211
|
+
if (sol.exact instanceof Fraction) {
|
|
212
|
+
h = P.x.clone().opposed().multiply(sol.exact).add(P.y)
|
|
213
|
+
equ.right.multiply(sol.exact).add(h)
|
|
214
|
+
} else {
|
|
215
|
+
h = P.x.clone().opposed().multiply(sol.value).add(P.y)
|
|
216
|
+
equ.right.multiply(sol.value).add(h)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return new Line(equ)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private _tangentsWithSlope = (slope: Fraction): Line[] => {
|
|
225
|
+
// d(C;t)=r => ac1+bc2 + x = +- sqrt(a^2 + b^2)*r
|
|
226
|
+
// x = -ac1-bc2 +- sqrt(a^2 + b^2)*r
|
|
227
|
+
// y = a/bx + h => ax-by + H = 0
|
|
228
|
+
|
|
229
|
+
const a = slope.numerator, b = -slope.denominator, c1 = this._center.x.clone(), c2 = this._center.y.clone(),
|
|
230
|
+
r = this._squareRadius
|
|
231
|
+
|
|
232
|
+
let sq = this._squareRadius.clone().multiply(slope.numerator ** 2 + slope.denominator ** 2),
|
|
233
|
+
x1 = c1.clone().multiply(a).opposed().subtract(c2.clone().multiply(b)).add(sq.clone().sqrt()),
|
|
234
|
+
x2 = c1.clone().multiply(a).opposed().subtract(c2.clone().multiply(b)).subtract(sq.clone().sqrt())
|
|
235
|
+
|
|
236
|
+
return [new Line(a, b, x1), new Line(a, b, x2)]
|
|
237
|
+
}
|
|
238
|
+
|
|
92
239
|
private _reset(): Circle {
|
|
93
240
|
this._center = null
|
|
94
241
|
this._squareRadius = null
|
|
@@ -128,7 +275,7 @@ export class Circle {
|
|
|
128
275
|
}
|
|
129
276
|
|
|
130
277
|
// Calculate once the different values.
|
|
131
|
-
if(this._exists) {
|
|
278
|
+
if (this._exists) {
|
|
132
279
|
this._calculateCartesian()
|
|
133
280
|
|
|
134
281
|
// If the square radius is zero or positive, the circle exists.
|
|
@@ -141,10 +288,7 @@ export class Circle {
|
|
|
141
288
|
}
|
|
142
289
|
|
|
143
290
|
private _calculateCartesian() {
|
|
144
|
-
this._cartesian = (new Equation(
|
|
145
|
-
new Polynom(`(x-(${this._center.x.display}))^2+(y-(${this._center.y.display}))^2`),
|
|
146
|
-
new Polynom(`${this._squareRadius.display}`)
|
|
147
|
-
)).moveLeft()
|
|
291
|
+
this._cartesian = (new Equation(new Polynom(`(x-(${this._center.x.display}))^2+(y-(${this._center.y.display}))^2`), new Polynom(`${this._squareRadius.display}`))).moveLeft()
|
|
148
292
|
}
|
|
149
293
|
|
|
150
294
|
private _parseCopyCircle(circle: Circle): Circle {
|
|
@@ -183,9 +327,7 @@ export class Circle {
|
|
|
183
327
|
|
|
184
328
|
if (equ.degree('x').value === 2 && equ.degree('y').value === 2) {
|
|
185
329
|
// Both must be of degree 2.
|
|
186
|
-
let x2 = equ.left.monomByDegree(2, 'x'),
|
|
187
|
-
y2 = equ.left.monomByDegree(2, 'y'),
|
|
188
|
-
x1: Monom, y1: Monom, c: Monom
|
|
330
|
+
let x2 = equ.left.monomByDegree(2, 'x'), y2 = equ.left.monomByDegree(2, 'y'), x1: Monom, y1: Monom, c: Monom
|
|
189
331
|
|
|
190
332
|
// Both square monoms must have the same coefficient.
|
|
191
333
|
if (x2.coefficient.isEqual(y2.coefficient)) {
|
|
@@ -196,10 +338,7 @@ export class Circle {
|
|
|
196
338
|
|
|
197
339
|
c = equ.left.monomByDegree(0)
|
|
198
340
|
|
|
199
|
-
this._center = new Point(
|
|
200
|
-
x1.coefficient.clone().divide(2).opposed(),
|
|
201
|
-
y1.coefficient.clone().divide(2).opposed()
|
|
202
|
-
)
|
|
341
|
+
this._center = new Point(x1.coefficient.clone().divide(2).opposed(), y1.coefficient.clone().divide(2).opposed())
|
|
203
342
|
|
|
204
343
|
this._squareRadius = c.coefficient.clone().opposed()
|
|
205
344
|
.add(this._center.x.clone().pow(2))
|
|
@@ -207,7 +346,7 @@ export class Circle {
|
|
|
207
346
|
|
|
208
347
|
this._calculateCartesian()
|
|
209
348
|
this._exists = true
|
|
210
|
-
}else{
|
|
349
|
+
} else {
|
|
211
350
|
// The circle is not a valid circle
|
|
212
351
|
this._center = null
|
|
213
352
|
this._squareRadius = null
|
|
@@ -218,57 +357,11 @@ export class Circle {
|
|
|
218
357
|
}
|
|
219
358
|
|
|
220
359
|
private _parseThroughtThreePoints(A: Point, B: Point, C: Point): Circle {
|
|
221
|
-
let T = new Triangle(A, B, C),
|
|
222
|
-
mAB = T.remarquables.mediators.AB.clone(),
|
|
360
|
+
let T = new Triangle(A, B, C), mAB = T.remarquables.mediators.AB.clone(),
|
|
223
361
|
mAC = T.remarquables.mediators.AC.clone()
|
|
224
362
|
this.parse(mAB.intersection(mAC).point, A)
|
|
225
363
|
|
|
226
364
|
return this
|
|
227
365
|
}
|
|
228
366
|
|
|
229
|
-
/**
|
|
230
|
-
* Get the relative position between circle and line. It corresponds to the number of intersection.
|
|
231
|
-
* @param {Line} L
|
|
232
|
-
* @returns {number}
|
|
233
|
-
*/
|
|
234
|
-
relativePosition = (L: Line): number => {
|
|
235
|
-
let distance = L.distanceTo(this.center),
|
|
236
|
-
radius = Math.sqrt(this._squareRadius.value)
|
|
237
|
-
|
|
238
|
-
if (distance.value - radius > 0.0000000001) {
|
|
239
|
-
return 0 // external
|
|
240
|
-
} else if (Math.abs(distance.value - radius) < 0.0000000001) {
|
|
241
|
-
return 1 // tangent
|
|
242
|
-
} else {
|
|
243
|
-
return 2 // external
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
lineIntersection = (L: Line): Point[] => {
|
|
248
|
-
let intersectionPoints: Point[] = [], solX: Fraction
|
|
249
|
-
|
|
250
|
-
if(this._cartesian===null){return []}
|
|
251
|
-
const equX = this._cartesian.clone(),
|
|
252
|
-
lineX = L.equation.clone().isolate('x'),
|
|
253
|
-
lineY = L.equation.clone().isolate('y')
|
|
254
|
-
|
|
255
|
-
if (lineX instanceof Equation && lineY instanceof Equation) {
|
|
256
|
-
equX.replaceBy('y', lineY.right).simplify()
|
|
257
|
-
equX.solve()
|
|
258
|
-
|
|
259
|
-
for(let x of equX.solutions){
|
|
260
|
-
if(x.exact===false && isNaN(x.value)){continue}
|
|
261
|
-
|
|
262
|
-
solX = new Fraction(x.exact===false?x.value:x.exact)
|
|
263
|
-
intersectionPoints.push(
|
|
264
|
-
new Point(
|
|
265
|
-
solX.clone(),
|
|
266
|
-
lineY.right.evaluate(solX)
|
|
267
|
-
)
|
|
268
|
-
)
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return intersectionPoints
|
|
273
|
-
}
|
|
274
367
|
}
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* @module Vector
|
|
4
4
|
*/
|
|
5
5
|
import {Fraction} from "../coefficients"
|
|
6
|
+
import {Line} from "./line";
|
|
7
|
+
import {Vector} from "./vector";
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Helper class - a way to identify an object {x: number, y: number}
|
|
@@ -68,8 +70,6 @@ export class Point {
|
|
|
68
70
|
// ------------------------------------------
|
|
69
71
|
// Creation / parsing functions
|
|
70
72
|
// ------------------------------------------
|
|
71
|
-
|
|
72
|
-
|
|
73
73
|
parse = (...values: unknown[]): Point => {
|
|
74
74
|
// Initialize the value.
|
|
75
75
|
this.zero();
|
|
@@ -171,4 +171,27 @@ export class Point {
|
|
|
171
171
|
}
|
|
172
172
|
};
|
|
173
173
|
|
|
174
|
+
distanceTo = (item:Point|Line): { value: number, fraction: Fraction, tex: string } => {
|
|
175
|
+
let value = 0, fraction = new Fraction(), tex = ''
|
|
176
|
+
|
|
177
|
+
if(item instanceof Line){
|
|
178
|
+
return item.distanceTo(this)
|
|
179
|
+
}else if(item instanceof Point){
|
|
180
|
+
let V = new Vector(this, item)
|
|
181
|
+
|
|
182
|
+
value = V.norm
|
|
183
|
+
fraction = V.normSquare.sqrt()
|
|
184
|
+
tex = V.normSquare.isSquare()?fraction.tex:`\\sqrt{\\dfrac{ ${V.normSquare.numerator} }{ ${V.normSquare.denominator} }}`
|
|
185
|
+
}
|
|
186
|
+
return { value, fraction, tex }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
get key(): string {
|
|
190
|
+
return `${this.x.display};${this.y.display}`
|
|
191
|
+
}
|
|
192
|
+
isInListOfPoints = (list: Point[]): boolean => {
|
|
193
|
+
const keyList = list.map(x=>x.key)
|
|
194
|
+
|
|
195
|
+
return keyList.includes(this.key)
|
|
196
|
+
}
|
|
174
197
|
}
|
package/src/maths/numeric.ts
CHANGED
|
@@ -89,4 +89,19 @@ export class Numeric{
|
|
|
89
89
|
return Math.abs(a * b / Numeric.gcd(a, b));
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
|
+
|
|
93
|
+
static pythagoricianTripletsWithTarget(target: number, targetIsSquare?:boolean): number[][] {
|
|
94
|
+
// méthode inverse, à partir du triplet.
|
|
95
|
+
const triplets = [],
|
|
96
|
+
targetValue = targetIsSquare===true?+target:target**2
|
|
97
|
+
for(let u = 0; u <= target; u++){
|
|
98
|
+
for(let v = 0; v <=target; v++){
|
|
99
|
+
if(u**2+v**2===targetValue){
|
|
100
|
+
triplets.push([u, v, target])
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return triplets
|
|
106
|
+
}
|
|
92
107
|
}
|
|
@@ -25,4 +25,37 @@ describe('Circle', function () {
|
|
|
25
25
|
expect(IPS[1].x.value).to.be.equal(6)
|
|
26
26
|
expect(IPS[1].y.value).to.be.equal(10)
|
|
27
27
|
});
|
|
28
|
+
|
|
29
|
+
it('should calculate tangents', function(){
|
|
30
|
+
|
|
31
|
+
// Through one point on the circle
|
|
32
|
+
const C = new Circle(
|
|
33
|
+
new Point(-2, 3),
|
|
34
|
+
25,
|
|
35
|
+
true
|
|
36
|
+
), P = new Point(-5, 7);
|
|
37
|
+
|
|
38
|
+
expect(C.tangents(P).map(x=>x.tex.canonical)).to.have.all.members(['3x-4y+43=0'])
|
|
39
|
+
|
|
40
|
+
// With a slope
|
|
41
|
+
const D = new Circle('x^2+y^2+10x=2y-6'),
|
|
42
|
+
slope = new Fraction(-2, 1)
|
|
43
|
+
|
|
44
|
+
expect(D.tangents(slope).map(x=>x.tex.canonical)).to.have.all.members(['2x+y-1=0', '2x+y+19=0'])
|
|
45
|
+
|
|
46
|
+
const E = new Circle('(x-2)^2+(y-1)^2=5'),
|
|
47
|
+
P2 = new Point(6, -2)
|
|
48
|
+
|
|
49
|
+
expect(E.tangents(P2).map(x=>x.tex.canonical)).to.have.all.members(['2x+y-10=0','2x+11y+10=0'])
|
|
50
|
+
|
|
51
|
+
let P3 = new Point(2, 2)
|
|
52
|
+
expect(E.tangents(P3)).to.be.empty
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('should get a list of point on the circle', function () {
|
|
56
|
+
const C = new Circle('(x-3)^2+(y+4)^2=16'),
|
|
57
|
+
pts = C.getPointsOnCircle()
|
|
58
|
+
|
|
59
|
+
expect(pts.map(x=>x.x.display + ',' + x.y.display)).to.have.all.members([ '3,0', '3,-8', '7,-4', '-1,-4' ])
|
|
60
|
+
});
|
|
28
61
|
});
|
package/tsconfig.json
CHANGED
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
"outDir": "./esm/",
|
|
18
18
|
"noImplicitAny": true,
|
|
19
19
|
"module": "commonjs",
|
|
20
|
-
"target": "
|
|
20
|
+
"target": "es2021",
|
|
21
21
|
"allowJs": true,
|
|
22
22
|
"sourceMap": true,
|
|
23
23
|
"moduleResolution": "node",
|
|
24
24
|
"declaration": true,
|
|
25
|
-
"removeComments":
|
|
25
|
+
"removeComments": false
|
|
26
26
|
},
|
|
27
27
|
"include": [
|
|
28
28
|
"./src/**/*"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
mode: 'production',
|
|
5
|
+
entry: './src/main.ts',
|
|
6
|
+
devtool: 'source-map',
|
|
7
|
+
module: {
|
|
8
|
+
rules: [
|
|
9
|
+
{
|
|
10
|
+
test: /\.tsx?$/,
|
|
11
|
+
use: 'ts-loader',
|
|
12
|
+
exclude: /node_module/,
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
resolve: {
|
|
17
|
+
extensions: ['.tsx','.ts', '.js'],
|
|
18
|
+
},
|
|
19
|
+
output: {
|
|
20
|
+
filename: 'pi.min.js',
|
|
21
|
+
path: path.resolve(__dirname, 'dist'),
|
|
22
|
+
},
|
|
23
|
+
optimization: {
|
|
24
|
+
minimize: true
|
|
25
|
+
}
|
|
26
|
+
};
|