pimath 0.1.40 → 0.2.1

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 (99) hide show
  1. package/dist/pimath.js +3106 -2873
  2. package/dist/pimath.js.map +1 -1
  3. package/package.json +13 -11
  4. package/src/algebra/equation.ts +113 -111
  5. package/src/algebra/equationSolver.ts +69 -120
  6. package/src/algebra/factor.ts +6 -7
  7. package/src/algebra/linearSystem.ts +97 -46
  8. package/src/algebra/logicalset.ts +51 -52
  9. package/src/algebra/monom.ts +23 -61
  10. package/src/algebra/operations.ts +0 -1
  11. package/src/algebra/polyFactor.ts +5 -5
  12. package/src/algebra/polynom.ts +69 -216
  13. package/src/analyze/index.ts +4 -0
  14. package/src/analyze/solution.ts +92 -29
  15. package/src/analyze/tableOfSigns.ts +1 -1
  16. package/src/coefficients/fraction.ts +189 -149
  17. package/src/coefficients/index.ts +1 -1
  18. package/src/coefficients/root.ts +66 -19
  19. package/src/geometry/TupleN.ts +128 -0
  20. package/src/geometry/circle.ts +308 -238
  21. package/src/geometry/geomMath.ts +4 -3
  22. package/src/geometry/index.ts +1 -0
  23. package/src/geometry/line.ts +221 -245
  24. package/src/geometry/line3.ts +78 -73
  25. package/src/geometry/plane3.ts +64 -55
  26. package/src/geometry/point.ts +57 -19
  27. package/src/geometry/triangle.ts +376 -248
  28. package/src/geometry/vector.ts +113 -229
  29. package/src/index.ts +13 -12
  30. package/src/numeric.ts +6 -9
  31. package/src/pimath.interface.ts +30 -28
  32. package/src/randomization/algebra/rndPolynom.ts +29 -15
  33. package/src/randomization/coefficient/rndFraction.ts +3 -3
  34. package/src/randomization/geometry/rndLine.ts +8 -10
  35. package/src/randomization/random.ts +11 -13
  36. package/src/randomization/rndTypes.ts +16 -12
  37. package/types/algebra/equation.d.ts +18 -17
  38. package/types/algebra/equation.d.ts.map +1 -1
  39. package/types/algebra/equationSolver.d.ts +5 -4
  40. package/types/algebra/equationSolver.d.ts.map +1 -1
  41. package/types/algebra/factor.d.ts +1 -1
  42. package/types/algebra/factor.d.ts.map +1 -1
  43. package/types/algebra/linearSystem.d.ts +23 -6
  44. package/types/algebra/linearSystem.d.ts.map +1 -1
  45. package/types/algebra/logicalset.d.ts +1 -1
  46. package/types/algebra/logicalset.d.ts.map +1 -1
  47. package/types/algebra/monom.d.ts +1 -6
  48. package/types/algebra/monom.d.ts.map +1 -1
  49. package/types/algebra/operations.d.ts.map +1 -1
  50. package/types/algebra/polyFactor.d.ts +4 -4
  51. package/types/algebra/polyFactor.d.ts.map +1 -1
  52. package/types/algebra/polynom.d.ts +10 -7
  53. package/types/algebra/polynom.d.ts.map +1 -1
  54. package/types/analyze/index.d.ts +2 -0
  55. package/types/analyze/index.d.ts.map +1 -0
  56. package/types/analyze/solution.d.ts +14 -8
  57. package/types/analyze/solution.d.ts.map +1 -1
  58. package/types/coefficients/fraction.d.ts +14 -12
  59. package/types/coefficients/fraction.d.ts.map +1 -1
  60. package/types/coefficients/index.d.ts +1 -1
  61. package/types/coefficients/index.d.ts.map +1 -1
  62. package/types/coefficients/root.d.ts +3 -0
  63. package/types/coefficients/root.d.ts.map +1 -1
  64. package/types/geometry/TupleAbstract.d.ts +22 -0
  65. package/types/geometry/TupleAbstract.d.ts.map +1 -0
  66. package/types/geometry/TupleN.d.ts +24 -0
  67. package/types/geometry/TupleN.d.ts.map +1 -0
  68. package/types/geometry/circle.d.ts +26 -17
  69. package/types/geometry/circle.d.ts.map +1 -1
  70. package/types/geometry/geomMath.d.ts +2 -1
  71. package/types/geometry/geomMath.d.ts.map +1 -1
  72. package/types/geometry/index.d.ts.map +1 -1
  73. package/types/geometry/line.d.ts +21 -30
  74. package/types/geometry/line.d.ts.map +1 -1
  75. package/types/geometry/line3.d.ts +19 -19
  76. package/types/geometry/line3.d.ts.map +1 -1
  77. package/types/geometry/matrix.d.ts +11 -11
  78. package/types/geometry/plane3.d.ts +10 -10
  79. package/types/geometry/plane3.d.ts.map +1 -1
  80. package/types/geometry/point.d.ts +11 -6
  81. package/types/geometry/point.d.ts.map +1 -1
  82. package/types/geometry/triangle.d.ts +68 -23
  83. package/types/geometry/triangle.d.ts.map +1 -1
  84. package/types/geometry/vector.d.ts +24 -44
  85. package/types/geometry/vector.d.ts.map +1 -1
  86. package/types/index.d.ts +5 -4
  87. package/types/index.d.ts.map +1 -1
  88. package/types/numeric.d.ts.map +1 -1
  89. package/types/pimath.interface.d.ts +18 -24
  90. package/types/pimath.interface.d.ts.map +1 -1
  91. package/types/randomization/algebra/rndPolynom.d.ts.map +1 -1
  92. package/types/randomization/coefficient/rndFraction.d.ts +1 -1
  93. package/types/randomization/coefficient/rndFraction.d.ts.map +1 -1
  94. package/types/randomization/geometry/rndLine.d.ts.map +1 -1
  95. package/types/randomization/random.d.ts +3 -2
  96. package/types/randomization/random.d.ts.map +1 -1
  97. package/types/randomization/rndTypes.d.ts +15 -10
  98. package/types/randomization/rndTypes.d.ts.map +1 -1
  99. package/src/coefficients/nthRoot.ts +0 -149
@@ -1,19 +1,25 @@
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"
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
+ }
10
15
 
11
16
  export class Circle
12
- implements
13
- IPiMathObject<Circle> {
14
- #center: Point | undefined = undefined
15
- #squareRadius: Fraction | undefined = undefined
16
- #cartesian: Equation | undefined = undefined
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
17
23
 
18
24
  constructor()
19
25
  constructor(equation: string | Equation)
@@ -27,38 +33,69 @@ export class Circle
27
33
  }
28
34
  }
29
35
 
30
- get center(): Point {
31
- return this.#center ?? new Point()
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
32
76
  }
33
77
 
34
- get squareRadius(): Fraction {
35
- return this.#squareRadius ?? new Fraction(0)
78
+ clone(): Circle {
79
+ return new Circle().fromCenterRadius(
80
+ this.center.clone(),
81
+ this.squareRadius.clone(),
82
+ true
83
+ )
36
84
  }
37
85
 
38
- get cartesian(): Equation {
39
- if (this.#cartesian === undefined) { throw new Error('Cartesian equation not defined') }
86
+ copy(circle: Circle): this {
87
+ this.#center = circle.center.clone()
88
+ this.#squareRadius = circle.squareRadius.clone()
40
89
 
41
- return this.#cartesian
42
- }
90
+ this.#calculateCartesian()
43
91
 
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
- }
92
+ return this
59
93
  }
60
94
 
61
95
  get tex(): string {
96
+ if (this.#output_style === CIRCLE_DISPLAY.CANONICAL) {
97
+ return this.equation.moveLeft().reduce().tex
98
+ }
62
99
 
63
100
  let cx, cy
64
101
  if (this.center.x.isZero()) {
@@ -74,11 +111,11 @@ export class Circle
74
111
  return `${cx}+${cy}=${this.squareRadius.tex}`
75
112
  }
76
113
 
77
- get developed(): string {
78
- return this.cartesian.tex
79
- }
80
-
81
114
  get display(): string {
115
+ if (this.#output_style === CIRCLE_DISPLAY.CANONICAL) {
116
+ return this.equation.moveLeft().reduce().display
117
+ }
118
+
82
119
  let cx, cy
83
120
  if (this.center.x.isZero()) {
84
121
  cx = 'x^2'
@@ -93,77 +130,106 @@ export class Circle
93
130
  return `${cx}+${cy}=${this.squareRadius.display}`
94
131
  }
95
132
 
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') }
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
+ }
103
142
 
104
- const distance = L.distanceTo(this.#center), radius = Math.sqrt(this.#squareRadius.value)
143
+ get center(): Point {
144
+ return this.#center ?? new Point()
145
+ }
105
146
 
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
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))
110
164
  } else {
111
- return 2 // secant
165
+ this.#squareRadius = new Fraction(radius).pow(2)
112
166
  }
167
+
168
+ this.#calculateCartesian()
169
+
170
+ return this
113
171
  }
114
172
 
115
- lineIntersection = (L: Line): Point[] => {
116
- const intersectionPoints: Point[] = []
117
- // let solX: Fraction
173
+ fromEquation(equ: Equation): this {
174
+ // Move everything to the left.
175
+ equ.moveLeft()
118
176
 
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')
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
122
181
 
123
- if (lineX instanceof Equation && lineY instanceof Equation) {
124
- equX.replaceBy('y', lineY.right).simplify()
125
- equX.solve()
182
+ // Both square monoms must have the same coefficient.
183
+ if (x2.coefficient.isEqual(y2.coefficient)) {
184
+ equ.divide(x2.coefficient)
126
185
 
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
- // }
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))
132
196
 
133
- // solX = new Fraction(x.exact === false ? x.value : x.exact)
134
- // intersectionPoints.push(new Point(solX.clone(), lineY.right.evaluate(solX)))
135
- // }
197
+ this.#calculateCartesian()
198
+
199
+ return this
200
+ } else {
201
+ // The circle is not a valid circle
202
+ this.#reset()
203
+ }
136
204
  }
137
205
 
138
- return intersectionPoints
206
+ return this
139
207
  }
140
208
 
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 !')
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
151
215
  }
152
- return []
153
- }
154
216
 
155
- isPointOnCircle = (P: Point): boolean => {
156
- return this.#cartesian?.test({ x: P.x, y: P.y }) ?? false
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
+ )
157
224
  }
158
225
 
159
- getPointsOnCircle = (numberIsInteger?: boolean): Point[] => {
160
- if (numberIsInteger === undefined) {
161
- numberIsInteger = false
162
- }
226
+ fromString(str: string): this {
227
+ return this.fromEquation(new Equation(str))
228
+ }
163
229
 
230
+ getPointsOnCircle(): Point[] {
164
231
  // It means searching for pythagorician triples that make a perfect square.
165
232
  // (x-4)^2 + (y+3)^2 = 15
166
-
167
233
  const triplets = Numeric.pythagoreanTripletsWithTarget(this.squareRadius.value, true)
168
234
 
169
235
  const points: Point[] = []
@@ -172,33 +238,119 @@ export class Circle
172
238
  // Allow positive / negative values
173
239
  // x-a = t => x = a + t
174
240
  // x-a = -t => x = a - t
175
-
176
241
  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
- // }
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
+
187
250
  }
188
251
  })
189
252
  return points
190
253
  }
191
254
 
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
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
202
354
  }
203
355
 
204
356
  setRadius(radius: Fraction | number, square?: boolean): this {
@@ -207,13 +359,48 @@ export class Circle
207
359
  } else {
208
360
  this.#squareRadius = new Fraction(radius).pow(2)
209
361
  }
362
+
210
363
  this.#calculateCartesian()
211
364
  return this
212
365
  }
213
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
+
214
401
  #tangentsThroughOnePointOnTheCircle = (P: Point): Line[] => {
215
402
  const CT = new Vector(this.center, P)
216
- return [new Line(P, CT, LinePropriety.Perpendicular)]
403
+ return [new Line().fromPointAndNormal(P, CT)]
217
404
  }
218
405
 
219
406
  #tangentsThroughOnePointOutsideTheCircle = (P: Point): Line[] => {
@@ -223,13 +410,16 @@ export class Circle
223
410
  // (m.cx - cy -m.px + py)^2 = r^2 * (m^2 + 1)
224
411
  // (m(cx-py) - (cy - py))^2 = r^2 * (m^2 + 1)
225
412
 
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')
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')
228
417
 
229
418
  polyLeft.multiply(cx_px).subtract(cy_py).pow(2)
230
419
  polyRight.multiply(this.squareRadius)
231
420
 
232
421
  const equ = new Equation(polyLeft, polyRight)
422
+
233
423
  const solutions = equ.solve()
234
424
 
235
425
  return solutions.map(sol => {
@@ -237,9 +427,9 @@ export class Circle
237
427
  let h: Fraction
238
428
  const equ = new Equation('y', 'x')
239
429
 
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)
430
+ if (sol.exact) {
431
+ h = P.x.clone().opposite().multiply(sol.fraction).add(P.y)
432
+ equ.right.multiply(sol.fraction).add(h)
243
433
  } else {
244
434
  h = P.x.clone().opposite().multiply(sol.value).add(P.y)
245
435
  equ.right.multiply(sol.value).add(h)
@@ -263,124 +453,4 @@ export class Circle
263
453
 
264
454
  return [new Line(a, b, x1), new Line(a, b, x2)]
265
455
  }
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
456
  }
@@ -1,7 +1,8 @@
1
- import { Fraction } from "../coefficients"
2
- import type { Vector } from "./vector"
1
+ import {Fraction} from "../coefficients"
2
+ import type {Vector} from "./vector"
3
+ import type {Point} from "./point"
3
4
 
4
- type V = Vector
5
+ type V = Vector | Point
5
6
  export function areVectorsEquals(v1: V, v2: V): boolean {
6
7
  return v1.dimension === v2.dimension &&
7
8
  v1.array.every(
@@ -1,4 +1,5 @@
1
1
  // Import / export every files from the geometry folder
2
+
2
3
  export * from './geomMath'
3
4
  export * from './circle'
4
5
  export * from './line'