pimath 0.0.131 → 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.
- package/dist/main.d.ts +39 -1
- package/package.json +2 -3
- package/dist/maths/pimath.d.ts +0 -39
- package/lib/main.ts +0 -1
- package/lib/maths/algebra/equation.ts +0 -891
- package/lib/maths/algebra/linearSystem.ts +0 -369
- package/lib/maths/algebra/logicalset.ts +0 -183
- package/lib/maths/algebra/monom.ts +0 -1027
- package/lib/maths/algebra/polynom.ts +0 -1537
- package/lib/maths/algebra/rational.ts +0 -244
- package/lib/maths/algebra/study/rationalStudy.ts +0 -287
- package/lib/maths/algebra/study.ts +0 -506
- package/lib/maths/coefficients/fraction.ts +0 -593
- package/lib/maths/coefficients/nthRoot.ts +0 -148
- package/lib/maths/geometry/circle.ts +0 -379
- package/lib/maths/geometry/line.ts +0 -604
- package/lib/maths/geometry/point.ts +0 -215
- package/lib/maths/geometry/triangle.ts +0 -368
- package/lib/maths/geometry/vector.ts +0 -243
- package/lib/maths/numeric.ts +0 -162
- package/lib/maths/numexp.ts +0 -198
- package/lib/maths/pimath.ts +0 -40
- package/lib/maths/randomization/random.ts +0 -80
- package/lib/maths/randomization/randomCore.ts +0 -19
- package/lib/maths/randomization/rndFraction.ts +0 -47
- package/lib/maths/randomization/rndGeometryCircle.ts +0 -50
- package/lib/maths/randomization/rndGeometryLine.ts +0 -53
- package/lib/maths/randomization/rndGeometryPoint.ts +0 -69
- package/lib/maths/randomization/rndHelpers.ts +0 -107
- package/lib/maths/randomization/rndMonom.ts +0 -57
- package/lib/maths/randomization/rndPolynom.ts +0 -90
- package/lib/maths/randomization/rndTypes.ts +0 -43
- package/lib/maths/shutingyard.ts +0 -496
|
@@ -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
|
-
}
|