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.
- package/dist/pimath.js +3106 -2873
- package/dist/pimath.js.map +1 -1
- package/package.json +13 -11
- package/src/algebra/equation.ts +113 -111
- package/src/algebra/equationSolver.ts +69 -120
- package/src/algebra/factor.ts +6 -7
- package/src/algebra/linearSystem.ts +97 -46
- package/src/algebra/logicalset.ts +51 -52
- package/src/algebra/monom.ts +23 -61
- package/src/algebra/operations.ts +0 -1
- package/src/algebra/polyFactor.ts +5 -5
- package/src/algebra/polynom.ts +69 -216
- package/src/analyze/index.ts +4 -0
- package/src/analyze/solution.ts +92 -29
- package/src/analyze/tableOfSigns.ts +1 -1
- package/src/coefficients/fraction.ts +189 -149
- package/src/coefficients/index.ts +1 -1
- package/src/coefficients/root.ts +66 -19
- package/src/geometry/TupleN.ts +128 -0
- package/src/geometry/circle.ts +308 -238
- package/src/geometry/geomMath.ts +4 -3
- package/src/geometry/index.ts +1 -0
- package/src/geometry/line.ts +221 -245
- package/src/geometry/line3.ts +78 -73
- package/src/geometry/plane3.ts +64 -55
- package/src/geometry/point.ts +57 -19
- package/src/geometry/triangle.ts +376 -248
- package/src/geometry/vector.ts +113 -229
- package/src/index.ts +13 -12
- package/src/numeric.ts +6 -9
- package/src/pimath.interface.ts +30 -28
- package/src/randomization/algebra/rndPolynom.ts +29 -15
- package/src/randomization/coefficient/rndFraction.ts +3 -3
- package/src/randomization/geometry/rndLine.ts +8 -10
- package/src/randomization/random.ts +11 -13
- package/src/randomization/rndTypes.ts +16 -12
- package/types/algebra/equation.d.ts +18 -17
- package/types/algebra/equation.d.ts.map +1 -1
- package/types/algebra/equationSolver.d.ts +5 -4
- package/types/algebra/equationSolver.d.ts.map +1 -1
- package/types/algebra/factor.d.ts +1 -1
- package/types/algebra/factor.d.ts.map +1 -1
- package/types/algebra/linearSystem.d.ts +23 -6
- package/types/algebra/linearSystem.d.ts.map +1 -1
- package/types/algebra/logicalset.d.ts +1 -1
- package/types/algebra/logicalset.d.ts.map +1 -1
- package/types/algebra/monom.d.ts +1 -6
- package/types/algebra/monom.d.ts.map +1 -1
- package/types/algebra/operations.d.ts.map +1 -1
- package/types/algebra/polyFactor.d.ts +4 -4
- package/types/algebra/polyFactor.d.ts.map +1 -1
- package/types/algebra/polynom.d.ts +10 -7
- package/types/algebra/polynom.d.ts.map +1 -1
- package/types/analyze/index.d.ts +2 -0
- package/types/analyze/index.d.ts.map +1 -0
- package/types/analyze/solution.d.ts +14 -8
- package/types/analyze/solution.d.ts.map +1 -1
- package/types/coefficients/fraction.d.ts +14 -12
- package/types/coefficients/fraction.d.ts.map +1 -1
- package/types/coefficients/index.d.ts +1 -1
- package/types/coefficients/index.d.ts.map +1 -1
- package/types/coefficients/root.d.ts +3 -0
- package/types/coefficients/root.d.ts.map +1 -1
- package/types/geometry/TupleAbstract.d.ts +22 -0
- package/types/geometry/TupleAbstract.d.ts.map +1 -0
- package/types/geometry/TupleN.d.ts +24 -0
- package/types/geometry/TupleN.d.ts.map +1 -0
- package/types/geometry/circle.d.ts +26 -17
- package/types/geometry/circle.d.ts.map +1 -1
- package/types/geometry/geomMath.d.ts +2 -1
- package/types/geometry/geomMath.d.ts.map +1 -1
- package/types/geometry/index.d.ts.map +1 -1
- package/types/geometry/line.d.ts +21 -30
- package/types/geometry/line.d.ts.map +1 -1
- package/types/geometry/line3.d.ts +19 -19
- package/types/geometry/line3.d.ts.map +1 -1
- package/types/geometry/matrix.d.ts +11 -11
- package/types/geometry/plane3.d.ts +10 -10
- package/types/geometry/plane3.d.ts.map +1 -1
- package/types/geometry/point.d.ts +11 -6
- package/types/geometry/point.d.ts.map +1 -1
- package/types/geometry/triangle.d.ts +68 -23
- package/types/geometry/triangle.d.ts.map +1 -1
- package/types/geometry/vector.d.ts +24 -44
- package/types/geometry/vector.d.ts.map +1 -1
- package/types/index.d.ts +5 -4
- package/types/index.d.ts.map +1 -1
- package/types/numeric.d.ts.map +1 -1
- package/types/pimath.interface.d.ts +18 -24
- package/types/pimath.interface.d.ts.map +1 -1
- package/types/randomization/algebra/rndPolynom.d.ts.map +1 -1
- package/types/randomization/coefficient/rndFraction.d.ts +1 -1
- package/types/randomization/coefficient/rndFraction.d.ts.map +1 -1
- package/types/randomization/geometry/rndLine.d.ts.map +1 -1
- package/types/randomization/random.d.ts +3 -2
- package/types/randomization/random.d.ts.map +1 -1
- package/types/randomization/rndTypes.d.ts +15 -10
- package/types/randomization/rndTypes.d.ts.map +1 -1
- package/src/coefficients/nthRoot.ts +0 -149
package/src/geometry/line.ts
CHANGED
|
@@ -3,35 +3,40 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import {Numeric} from "../numeric"
|
|
6
|
-
import {Fraction} from "../coefficients
|
|
7
|
-
import {Equation} from "../algebra
|
|
8
|
-
import {Polynom} from "../algebra/polynom"
|
|
9
|
-
import {Monom} from "../algebra/monom"
|
|
6
|
+
import {Fraction} from "../coefficients"
|
|
7
|
+
import {Equation, Monom, Polynom} from "../algebra"
|
|
10
8
|
import {Vector} from "./vector"
|
|
11
9
|
import {type InputValue, type IPiMathObject, LinePropriety} from "../pimath.interface"
|
|
12
10
|
import {randomIntSym} from "../randomization/rndHelpers"
|
|
13
11
|
import {Point} from "./point"
|
|
12
|
+
import {Root} from "../coefficients/root"
|
|
13
|
+
|
|
14
|
+
enum LINE_DISPLAY {
|
|
15
|
+
CARTESIAN,
|
|
16
|
+
CANONICAL,
|
|
17
|
+
MXH,
|
|
18
|
+
PARAMETRIC,
|
|
19
|
+
SYSTEM
|
|
20
|
+
}
|
|
14
21
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
point?: Point,
|
|
19
|
-
points?: Point[],
|
|
22
|
+
enum LINE_DIRECTION {
|
|
23
|
+
LEFT_TO_RIGHT = 'lr',
|
|
24
|
+
RIGHT_TO_LEFT = 'rl'
|
|
20
25
|
}
|
|
21
26
|
|
|
22
27
|
export class Line implements IPiMathObject<Line> {
|
|
23
28
|
static PARALLEL = LinePropriety.Parallel
|
|
24
|
-
// A line is defined as the canonical form
|
|
25
29
|
static PERPENDICULAR = LinePropriety.Perpendicular
|
|
26
30
|
#OA: Vector
|
|
27
31
|
// ax + by + c = 0
|
|
28
32
|
#a: Fraction
|
|
33
|
+
|
|
34
|
+
// A line is defined as the canonical form
|
|
29
35
|
#b: Fraction
|
|
30
36
|
#c: Fraction
|
|
31
|
-
#
|
|
32
|
-
|
|
33
|
-
#outputMode:
|
|
34
|
-
#reduceBeforeDisplay: boolean
|
|
37
|
+
#orientation: LINE_DIRECTION
|
|
38
|
+
// output mode.
|
|
39
|
+
#outputMode: LINE_DISPLAY = LINE_DISPLAY.CANONICAL
|
|
35
40
|
|
|
36
41
|
/**
|
|
37
42
|
* Value can be a mix of:
|
|
@@ -43,10 +48,7 @@ export class Line implements IPiMathObject<Line> {
|
|
|
43
48
|
this.#b = new Fraction().zero()
|
|
44
49
|
this.#c = new Fraction().zero()
|
|
45
50
|
this.#OA = new Vector()
|
|
46
|
-
this.#
|
|
47
|
-
this.#n = new Vector()
|
|
48
|
-
|
|
49
|
-
this.#reduceBeforeDisplay = true
|
|
51
|
+
this.#orientation = LINE_DIRECTION.LEFT_TO_RIGHT
|
|
50
52
|
|
|
51
53
|
if (values.length > 0) {
|
|
52
54
|
this.parse(...values)
|
|
@@ -72,53 +74,36 @@ export class Line implements IPiMathObject<Line> {
|
|
|
72
74
|
if (values[0] instanceof Line) {
|
|
73
75
|
// Already a Line
|
|
74
76
|
return this.fromCoefficient(values[0].a, values[0].b, values[0].c)
|
|
75
|
-
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (values[0] instanceof Equation) {
|
|
76
80
|
// It's an Equation
|
|
77
81
|
return this.fromEquation(values[0])
|
|
78
|
-
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (typeof values[0] === "string") {
|
|
79
85
|
// It's a string - create an Equation from it.
|
|
80
86
|
try {
|
|
81
87
|
const E = new Equation(values[0])
|
|
82
88
|
return this.parse(E)
|
|
83
89
|
} catch (e) {
|
|
90
|
+
console.warn(e)
|
|
84
91
|
return this
|
|
85
92
|
}
|
|
86
93
|
}
|
|
87
94
|
}
|
|
88
95
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (formattedValues[0].asPoint && formattedValues[1].asPoint) {
|
|
94
|
-
// Two points
|
|
95
|
-
return this.fromPointAndDirection(formattedValues[0], new Vector(formattedValues[0], formattedValues[1]))
|
|
96
|
+
if (values.length === 2) {
|
|
97
|
+
if (values[0] instanceof Point && values[1] instanceof Point) {
|
|
98
|
+
return this.fromPoints(values[0], values[1])
|
|
96
99
|
}
|
|
97
100
|
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
return this.fromPointAndDirection(formattedValues[0], formattedValues[1])
|
|
101
|
+
if (values[0] instanceof Point && values[1] instanceof Vector) {
|
|
102
|
+
return this.fromPointAndDirection(values[0], values[1])
|
|
101
103
|
}
|
|
102
|
-
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
if (values.length === 3) {
|
|
106
|
-
if (values[0] instanceof Vector && values[1] instanceof Vector) {
|
|
107
|
-
if (values[2] === LinePropriety.Perpendicular) {
|
|
108
|
-
return this.fromPointAndNormal(values[0], values[1])
|
|
109
|
-
} else if (values[2] === LinePropriety.Parallel) {
|
|
110
|
-
return this.fromPointAndDirection(values[0], values[1])
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (values[0] instanceof Vector && values[1] instanceof Line) {
|
|
115
|
-
if (values[2] === LinePropriety.Parallel || values[2] === null) {
|
|
116
|
-
return this.fromPointAndLine(values[0], values[1], LinePropriety.Parallel)
|
|
117
|
-
} else {
|
|
118
|
-
return this.fromPointAndLine(values[0], values[1], LinePropriety.Perpendicular)
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
106
|
+
if (values.length === 3 && values.every(x => Fraction.isFraction(x as InputValue<Fraction>))) {
|
|
122
107
|
return this.fromCoefficient(
|
|
123
108
|
values[0] as InputValue<Fraction>,
|
|
124
109
|
values[1] as InputValue<Fraction>,
|
|
@@ -126,24 +111,16 @@ export class Line implements IPiMathObject<Line> {
|
|
|
126
111
|
)
|
|
127
112
|
}
|
|
128
113
|
|
|
129
|
-
console.
|
|
130
|
-
console.
|
|
114
|
+
console.warn('Something wrong happened while creating the line')
|
|
115
|
+
console.warn(values)
|
|
131
116
|
return this
|
|
132
117
|
}
|
|
133
118
|
|
|
134
119
|
// ------------------------------------------
|
|
135
120
|
// Getter and setter
|
|
136
121
|
|
|
137
|
-
clone = ():
|
|
138
|
-
this.#a
|
|
139
|
-
this.#b = this.#b.clone()
|
|
140
|
-
this.#c = this.#c.clone()
|
|
141
|
-
|
|
142
|
-
this.#d = this.#d.clone()
|
|
143
|
-
this.#OA = this.#OA.clone()
|
|
144
|
-
this.#n = this.#n.clone()
|
|
145
|
-
|
|
146
|
-
return this
|
|
122
|
+
clone = (): Line => {
|
|
123
|
+
return new Line().fromCoefficient(this.#a, this.#b, this.#c)
|
|
147
124
|
}
|
|
148
125
|
|
|
149
126
|
get tex(): string {
|
|
@@ -151,45 +128,41 @@ export class Line implements IPiMathObject<Line> {
|
|
|
151
128
|
// mxh => y = -a/b x - c/b
|
|
152
129
|
// parametric => (xy) = OA + k*d
|
|
153
130
|
// equation => ax + by = -c
|
|
131
|
+
// system => \begin{}...
|
|
132
|
+
|
|
154
133
|
const output = this.#outputMode
|
|
155
|
-
this.#outputMode =
|
|
134
|
+
this.#outputMode = LINE_DISPLAY.CANONICAL
|
|
135
|
+
|
|
156
136
|
switch (output) {
|
|
157
|
-
case
|
|
137
|
+
case LINE_DISPLAY.CARTESIAN:
|
|
158
138
|
return this.getEquation().reorder().tex
|
|
159
|
-
case
|
|
139
|
+
case LINE_DISPLAY.MXH:
|
|
160
140
|
return this.slope.isInfinity() ?
|
|
161
141
|
'x=' + this.OA.x.tex :
|
|
162
142
|
'y=' + new Polynom().parse('x', this.slope, this.height).tex
|
|
163
|
-
case
|
|
164
|
-
case
|
|
165
|
-
const d = this
|
|
166
|
-
if (this.#reduceBeforeDisplay) {
|
|
167
|
-
d.simplify()
|
|
168
|
-
}
|
|
143
|
+
case LINE_DISPLAY.PARAMETRIC:
|
|
144
|
+
case LINE_DISPLAY.SYSTEM: {
|
|
145
|
+
const d = this.d.clone().simplify()
|
|
169
146
|
|
|
170
|
-
if (output ===
|
|
147
|
+
if (output === LINE_DISPLAY.PARAMETRIC) {
|
|
171
148
|
return `${Vector.asTex('x', 'y')} = ${Vector.asTex(this.#OA.x.tex, this.#OA.y.tex)} + k\\cdot ${Vector.asTex(d.x.tex, d.y.tex)}`
|
|
172
149
|
} else {
|
|
173
|
-
return `\\left\\{\\begin{aligned}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
.reorder('k', true)
|
|
181
|
-
.tex}
|
|
182
|
-
\\end{aligned}\\right.`
|
|
150
|
+
return `\\left\\{\\begin{aligned}\n\tx &= ${(new Polynom(this.#OA.x)
|
|
151
|
+
.add(new Monom(d.x).multiply(new Monom('k'))))
|
|
152
|
+
.reorder('k', true)
|
|
153
|
+
.tex}\\\\\n\ty &= ${(new Polynom(this.#OA.y)
|
|
154
|
+
.add(new Monom(d.y).multiply(new Monom('k'))))
|
|
155
|
+
.reorder('k', true)
|
|
156
|
+
.tex}\n\\end{aligned}\\right.`
|
|
183
157
|
}
|
|
184
158
|
}
|
|
185
|
-
default:
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
canonical.multiply(-1)
|
|
190
|
-
}
|
|
191
|
-
return canonical.tex
|
|
159
|
+
default: {
|
|
160
|
+
const canonical = this.getEquation()
|
|
161
|
+
if (canonical.left.monoms[0].coefficient.isNegative()) {
|
|
162
|
+
canonical.multiply(-1)
|
|
192
163
|
}
|
|
164
|
+
return canonical.tex
|
|
165
|
+
}
|
|
193
166
|
}
|
|
194
167
|
|
|
195
168
|
}
|
|
@@ -199,27 +172,33 @@ export class Line implements IPiMathObject<Line> {
|
|
|
199
172
|
// mxh => y = -a/b x - c/b
|
|
200
173
|
// parametric => (xy) = OA + k*d // not relevant in display mode.
|
|
201
174
|
const output = this.#outputMode
|
|
202
|
-
this.#outputMode =
|
|
175
|
+
this.#outputMode = LINE_DISPLAY.CANONICAL
|
|
203
176
|
|
|
204
177
|
switch (output) {
|
|
205
|
-
case
|
|
178
|
+
case LINE_DISPLAY.CARTESIAN:
|
|
206
179
|
return this.getEquation().reorder().display
|
|
207
|
-
case
|
|
180
|
+
case LINE_DISPLAY.MXH:
|
|
208
181
|
return this.slope.isInfinity() ?
|
|
209
182
|
'x=' + this.OA.x.display :
|
|
210
183
|
'y=' + new Polynom().parse('x', this.slope, this.height).display
|
|
211
|
-
case
|
|
212
|
-
const d = this
|
|
213
|
-
if (this.#reduceBeforeDisplay) {
|
|
214
|
-
d.simplify()
|
|
215
|
-
}
|
|
216
|
-
|
|
184
|
+
case LINE_DISPLAY.PARAMETRIC: {
|
|
185
|
+
const d = this.d.clone().simplify()
|
|
217
186
|
return `((x,y))=((${this.#OA.x.display},${this.#OA.y.display}))+k((${d.x.display},${d.y.display}))`
|
|
218
187
|
}
|
|
188
|
+
case LINE_DISPLAY.SYSTEM: {
|
|
189
|
+
const d = this.d.clone().simplify()
|
|
190
|
+
// {(2x,+,17y,=,23),(x,-,y,=,5):}
|
|
191
|
+
const px = (new Polynom(this.#OA.x).add(new Monom(d.x).multiply(new Monom('k'))))
|
|
192
|
+
.reorder('k', true)
|
|
193
|
+
const py = (new Polynom(this.#OA.y).add(new Monom(d.y).multiply(new Monom('k'))))
|
|
194
|
+
.reorder('k', true)
|
|
195
|
+
|
|
196
|
+
return `{(x,=,${px.display}),(y,=,${py.display}):}`
|
|
197
|
+
}
|
|
219
198
|
default: {
|
|
220
199
|
const canonical = this.getEquation()
|
|
221
200
|
// Make sur the first item is positive.
|
|
222
|
-
if (
|
|
201
|
+
if (canonical.left.monoms[0].coefficient.isNegative()) {
|
|
223
202
|
canonical.multiply(-1)
|
|
224
203
|
}
|
|
225
204
|
return canonical.display
|
|
@@ -232,8 +211,8 @@ export class Line implements IPiMathObject<Line> {
|
|
|
232
211
|
return this.#OA
|
|
233
212
|
}
|
|
234
213
|
|
|
235
|
-
set OA(value: Vector) {
|
|
236
|
-
this
|
|
214
|
+
set OA(value: Vector | Point) {
|
|
215
|
+
this.fromPointAndNormal(value, this.n)
|
|
237
216
|
}
|
|
238
217
|
|
|
239
218
|
get a(): Fraction {
|
|
@@ -244,6 +223,31 @@ export class Line implements IPiMathObject<Line> {
|
|
|
244
223
|
this.#a = value
|
|
245
224
|
}
|
|
246
225
|
|
|
226
|
+
get asCanonical(): this {
|
|
227
|
+
this.#outputMode = LINE_DISPLAY.CANONICAL
|
|
228
|
+
return this
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
get asCartesian(): this {
|
|
232
|
+
this.#outputMode = LINE_DISPLAY.CARTESIAN
|
|
233
|
+
return this
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
get asMxh(): this {
|
|
237
|
+
this.#outputMode = LINE_DISPLAY.MXH
|
|
238
|
+
return this
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
get asParametric(): this {
|
|
242
|
+
this.#outputMode = LINE_DISPLAY.PARAMETRIC
|
|
243
|
+
return this
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
get asSystem(): this {
|
|
247
|
+
this.#outputMode = LINE_DISPLAY.SYSTEM
|
|
248
|
+
return this
|
|
249
|
+
}
|
|
250
|
+
|
|
247
251
|
get b(): Fraction {
|
|
248
252
|
return this.#b
|
|
249
253
|
}
|
|
@@ -260,32 +264,8 @@ export class Line implements IPiMathObject<Line> {
|
|
|
260
264
|
this.#c = value
|
|
261
265
|
}
|
|
262
266
|
|
|
263
|
-
// get system(): { x: Equation, y: Equation } {
|
|
264
|
-
// const e1 = new Equation(
|
|
265
|
-
// new Polynom('x'),
|
|
266
|
-
// new Polynom(this.#OA.x)
|
|
267
|
-
// .add(new Monom('k').multiply(this.#d.x))
|
|
268
|
-
// ),
|
|
269
|
-
// e2 = new Equation(
|
|
270
|
-
// new Polynom('y'),
|
|
271
|
-
// new Polynom(this.#OA.y)
|
|
272
|
-
// .add(new Monom('k').multiply(this.#d.y))
|
|
273
|
-
// )
|
|
274
|
-
|
|
275
|
-
// return { x: e1, y: e2 }
|
|
276
|
-
// }
|
|
277
|
-
|
|
278
|
-
get canonical(): this {
|
|
279
|
-
this.#outputMode = 'canonical'
|
|
280
|
-
return this
|
|
281
|
-
}
|
|
282
|
-
|
|
283
267
|
// ------------------------------------------
|
|
284
|
-
canonicalAsFloatCoefficient(decimals
|
|
285
|
-
if (decimals === undefined) {
|
|
286
|
-
decimals = 2
|
|
287
|
-
}
|
|
288
|
-
|
|
268
|
+
canonicalAsFloatCoefficient(decimals = 2): string {
|
|
289
269
|
let canonical = ''
|
|
290
270
|
|
|
291
271
|
if (!this.#a.isZero()) {
|
|
@@ -317,69 +297,104 @@ export class Line implements IPiMathObject<Line> {
|
|
|
317
297
|
}
|
|
318
298
|
|
|
319
299
|
get d(): Vector {
|
|
320
|
-
|
|
300
|
+
const director = new Vector(this.#b.clone(), this.#a.clone().opposite())
|
|
301
|
+
|
|
302
|
+
if (
|
|
303
|
+
this.#orientation === LINE_DIRECTION.LEFT_TO_RIGHT && director.x.isNegative() ||
|
|
304
|
+
this.#orientation === LINE_DIRECTION.RIGHT_TO_LEFT && director.x.isPositive()
|
|
305
|
+
) {
|
|
306
|
+
director.opposite()
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return director
|
|
321
310
|
}
|
|
322
311
|
|
|
323
312
|
set d(value: Vector) {
|
|
324
|
-
this
|
|
313
|
+
this.fromPointAndDirection(this.OA, value)
|
|
325
314
|
}
|
|
326
315
|
|
|
327
316
|
get director(): Vector {
|
|
328
|
-
return this
|
|
317
|
+
return this.d
|
|
329
318
|
}
|
|
330
319
|
|
|
331
|
-
distanceTo(pt: Point):
|
|
320
|
+
distanceTo(pt: Point): Root {
|
|
332
321
|
const numerator = pt.x.clone().multiply(this.#a)
|
|
333
322
|
.add(pt.y.clone().multiply(this.#b))
|
|
334
|
-
.add(this.#c).abs()
|
|
335
|
-
|
|
323
|
+
.add(this.#c).abs()
|
|
324
|
+
const d2 = this.normal.normSquare
|
|
336
325
|
|
|
337
326
|
// The denominator is null - shouldn't be possible
|
|
338
327
|
if (d2.isZero()) {
|
|
339
|
-
return
|
|
340
|
-
value: NaN,
|
|
341
|
-
tex: 'Not a line',
|
|
342
|
-
fraction: new Fraction().infinite()
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
// The denominator is a perfect square - simplify the tex result
|
|
346
|
-
const value = numerator.value / Math.sqrt(d2.value),
|
|
347
|
-
F = numerator.clone().divide(d2.clone().sqrt())
|
|
348
|
-
|
|
349
|
-
// The denominator is a perfect square.
|
|
350
|
-
if (d2.isSquare()) {
|
|
351
|
-
return {
|
|
352
|
-
value,
|
|
353
|
-
tex: F.tex,
|
|
354
|
-
fraction: F
|
|
355
|
-
}
|
|
328
|
+
return new Root(0)
|
|
356
329
|
}
|
|
357
|
-
// Complete answer...
|
|
358
|
-
return {
|
|
359
|
-
value,
|
|
360
|
-
tex: `\\frac{${numerator.tex}}{\\sqrt{${d2.tex}}}`,
|
|
361
|
-
fraction: F
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
330
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
331
|
+
return new Root().from(2, d2.inverse(), numerator)
|
|
332
|
+
|
|
333
|
+
// The denominator is a perfect square - simplify the tex result
|
|
334
|
+
// const value = numerator.value / Math.sqrt(d2.value)
|
|
335
|
+
// const F = numerator.clone().divide(d2.clone().sqrt())
|
|
369
336
|
|
|
370
|
-
|
|
337
|
+
//
|
|
338
|
+
// if (d2.isSquare()) {
|
|
339
|
+
//
|
|
340
|
+
// return {
|
|
341
|
+
// value,
|
|
342
|
+
// tex: F.tex,
|
|
343
|
+
// fraction: F
|
|
344
|
+
// }
|
|
345
|
+
// }
|
|
346
|
+
// // Complete answer...
|
|
347
|
+
// return {
|
|
348
|
+
// value,
|
|
349
|
+
// tex: `\\frac{${numerator.tex}}{\\sqrt{${d2.tex}}}`,
|
|
350
|
+
// fraction: F
|
|
351
|
+
// }
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
fromCoefficient(a: InputValue<Fraction>, b: InputValue<Fraction>, c: InputValue<Fraction>): this {
|
|
371
355
|
this.#a = new Fraction(a)
|
|
372
356
|
this.#b = new Fraction(b)
|
|
373
357
|
this.#c = new Fraction(c)
|
|
374
358
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
359
|
+
// make sure the coefficients are relative...
|
|
360
|
+
const lcm = [this.#a, this.#b, this.#c].every(k => k.exact)
|
|
361
|
+
? Numeric.lcm(this.#a.denominator, this.#b.denominator, this.#c.denominator)
|
|
362
|
+
: 1
|
|
363
|
+
|
|
364
|
+
if (lcm > 1) {
|
|
365
|
+
this.#a.multiply(lcm).reduce()
|
|
366
|
+
this.#b.multiply(lcm).reduce()
|
|
367
|
+
this.#c.multiply(lcm).reduce()
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (this.#b.isZero()) {
|
|
371
|
+
// ax+c=0 => x = -c/a
|
|
372
|
+
this.#OA = new Vector(this.#c.clone().divide(this.#a).opposite(), 0)
|
|
373
|
+
return this
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// ax+by+c=0 => x=0 => y = a/b x - c/b = (ax-c)/b
|
|
377
|
+
for (let x = 0; x < this.#b.value; x++) {
|
|
378
|
+
const y = this.#a.clone().divide(this.#b)
|
|
379
|
+
.multiply(x)
|
|
380
|
+
.subtract(this.#c.clone().divide(this.#b))
|
|
381
|
+
.reduce()
|
|
382
|
+
|
|
383
|
+
this.#OA = new Vector(x, y)
|
|
384
|
+
|
|
385
|
+
if (y.isRelative()) {
|
|
386
|
+
return this
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// no "nice" point... do it with 'x=0'
|
|
391
|
+
const y = this.#c.clone().divide(this.#b).opposite().reduce()
|
|
392
|
+
this.#OA = new Vector(0, y)
|
|
378
393
|
|
|
379
394
|
return this
|
|
380
395
|
}
|
|
381
396
|
|
|
382
|
-
fromEquation
|
|
397
|
+
fromEquation(equ: Equation): this {
|
|
383
398
|
// Reorder the equation
|
|
384
399
|
equ.reorder(true)
|
|
385
400
|
|
|
@@ -410,66 +425,60 @@ export class Line implements IPiMathObject<Line> {
|
|
|
410
425
|
)
|
|
411
426
|
}
|
|
412
427
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
// y = py + kdy * dx
|
|
417
|
-
// ------------------
|
|
418
|
-
// dy * x = px * dy + kdxdy
|
|
419
|
-
// dx * y = py * dx + kdxdy
|
|
420
|
-
// ------------------
|
|
421
|
-
// dy * x - dx * y = px * dy - py * dx
|
|
422
|
-
// dy * x - dx * y - (px * dy - py * dx) = 0
|
|
423
|
-
this.fromCoefficient(
|
|
424
|
-
d.y,
|
|
425
|
-
d.x.clone().opposite(),
|
|
426
|
-
P.x.clone().multiply(d.y).subtract(P.y.clone().multiply(d.x)).opposite()
|
|
427
|
-
)
|
|
428
|
-
|
|
429
|
-
// Choose the current values as point and direction vector instead of the automatic version.
|
|
430
|
-
this.#OA = P.clone()
|
|
431
|
-
this.#d = d.clone()
|
|
432
|
-
this.#n = this.#d.clone().normal()
|
|
428
|
+
fromParallel(parallel: Line, point: Point): this {
|
|
429
|
+
return this.fromPointAndNormal(point, parallel.n)
|
|
430
|
+
}
|
|
433
431
|
|
|
434
|
-
|
|
432
|
+
fromPerpendicular(perpendicular: Line, point: Point): this {
|
|
433
|
+
return this.fromPointAndNormal(point, perpendicular.d)
|
|
435
434
|
}
|
|
436
435
|
|
|
437
|
-
|
|
436
|
+
fromPointAndDirection(P: Point | Vector, d: Vector): this {
|
|
437
|
+
this.#orientation = d.x.isPositive()
|
|
438
|
+
? LINE_DIRECTION.LEFT_TO_RIGHT
|
|
439
|
+
: LINE_DIRECTION.RIGHT_TO_LEFT
|
|
438
440
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
441
|
+
return this.fromPointAndNormal(P, d.clone().normal())
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
fromPointAndLine(P: Vector, L: Line, orientation: LinePropriety = LinePropriety.Parallel): this {
|
|
442
445
|
|
|
443
|
-
if (orientation === LinePropriety.
|
|
444
|
-
return this.fromPointAndNormal(P, L.normal)
|
|
445
|
-
} else if (orientation === LinePropriety.Perpendicular) {
|
|
446
|
+
if (orientation === LinePropriety.Perpendicular) {
|
|
446
447
|
return this.fromPointAndNormal(P, L.director)
|
|
447
448
|
}
|
|
448
449
|
|
|
449
|
-
return this
|
|
450
|
+
return this.fromPointAndNormal(P, L.normal)
|
|
450
451
|
}
|
|
451
452
|
|
|
452
|
-
fromPointAndNormal = (P: Point, n: Vector): this => {
|
|
453
|
-
|
|
453
|
+
fromPointAndNormal = (P: Point | Vector, n: Vector): this => {
|
|
454
|
+
if (n.isZero()) {
|
|
455
|
+
console.warn('Normal vector is null.')
|
|
456
|
+
return this
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
this.fromCoefficient(
|
|
454
460
|
n.x,
|
|
455
461
|
n.y,
|
|
456
462
|
P.x.clone().multiply(n.x)
|
|
457
463
|
.add(P.y.clone().multiply(n.y)).opposite()
|
|
458
464
|
)
|
|
465
|
+
|
|
466
|
+
this.#OA = new Vector(P.clone())
|
|
467
|
+
|
|
468
|
+
return this
|
|
459
469
|
}
|
|
460
470
|
|
|
461
|
-
|
|
462
|
-
|
|
471
|
+
// ------------------------------------------
|
|
472
|
+
// Creation / parsing functions
|
|
473
|
+
|
|
474
|
+
fromPoints(A: Point, B: Point) {
|
|
475
|
+
return this.fromPointAndNormal(A, new Vector(A, B).normal())
|
|
463
476
|
}
|
|
464
477
|
|
|
465
478
|
// ------------------------------------------
|
|
466
479
|
getEquation(): Equation {
|
|
467
480
|
const equ = new Equation(new Polynom().parse('xy', this.#a, this.#b, this.#c), new Polynom('0'))
|
|
468
|
-
|
|
469
|
-
return equ.simplify()
|
|
470
|
-
} else {
|
|
471
|
-
return equ
|
|
472
|
-
}
|
|
481
|
+
return equ.simplify()
|
|
473
482
|
}
|
|
474
483
|
|
|
475
484
|
getValueAtX = (value: Fraction | number): Fraction => {
|
|
@@ -477,20 +486,17 @@ export class Line implements IPiMathObject<Line> {
|
|
|
477
486
|
F = new Fraction(value)
|
|
478
487
|
|
|
479
488
|
if (equ instanceof Equation) {
|
|
480
|
-
return equ.right.evaluate({
|
|
489
|
+
return equ.right.evaluate({x: F}) as Fraction
|
|
481
490
|
}
|
|
482
491
|
return new Fraction().invalid()
|
|
483
492
|
}
|
|
484
493
|
|
|
485
|
-
// ------------------------------------------
|
|
486
|
-
// Creation / parsing functions
|
|
487
|
-
|
|
488
494
|
getValueAtY = (value: Fraction | number): Fraction => {
|
|
489
495
|
const equ = this.getEquation().isolate('x'),
|
|
490
496
|
F = new Fraction(value)
|
|
491
497
|
|
|
492
498
|
if (equ instanceof Equation) {
|
|
493
|
-
return equ.right.evaluate({
|
|
499
|
+
return equ.right.evaluate({y: F}) as Fraction
|
|
494
500
|
}
|
|
495
501
|
|
|
496
502
|
return new Fraction().invalid()
|
|
@@ -516,6 +522,7 @@ export class Line implements IPiMathObject<Line> {
|
|
|
516
522
|
}
|
|
517
523
|
|
|
518
524
|
intersection = (line: Line): { point: Point, hasIntersection: boolean, isParallel: boolean, isSame: boolean } => {
|
|
525
|
+
// TODO: rework Line.intersection
|
|
519
526
|
const Pt = new Point()
|
|
520
527
|
let isParallel = false, isSame = false
|
|
521
528
|
|
|
@@ -562,8 +569,12 @@ export class Line implements IPiMathObject<Line> {
|
|
|
562
569
|
}
|
|
563
570
|
}
|
|
564
571
|
|
|
572
|
+
isHorizontal(): boolean {
|
|
573
|
+
return this.slope.value === 0
|
|
574
|
+
}
|
|
575
|
+
|
|
565
576
|
// ------------------------------------------
|
|
566
|
-
isOnLine
|
|
577
|
+
isOnLine(pt: Point): boolean {
|
|
567
578
|
return this.#a.clone()
|
|
568
579
|
.multiply(pt.x)
|
|
569
580
|
.add(
|
|
@@ -586,31 +597,19 @@ export class Line implements IPiMathObject<Line> {
|
|
|
586
597
|
isSameAs = (line: Line): boolean => {
|
|
587
598
|
return this.slope.isEqual(line.slope) && this.height.isEqual(line.height)
|
|
588
599
|
}
|
|
589
|
-
// ------------------------------------------
|
|
590
|
-
// Mathematical operations
|
|
591
600
|
|
|
592
601
|
isVertical = (): boolean => {
|
|
593
602
|
return this.slope.isInfinity()
|
|
594
603
|
}
|
|
595
604
|
|
|
596
|
-
get mxh(): this {
|
|
597
|
-
this.#outputMode = 'mxh'
|
|
598
|
-
return this
|
|
599
|
-
}
|
|
600
|
-
|
|
601
605
|
get n(): Vector {
|
|
602
|
-
return this
|
|
606
|
+
return this.d.normal()
|
|
603
607
|
}
|
|
604
608
|
|
|
605
609
|
get normal(): Vector {
|
|
606
610
|
return new Vector(this.#a, this.#b)
|
|
607
611
|
}
|
|
608
612
|
|
|
609
|
-
get parametric(): this {
|
|
610
|
-
this.#outputMode = 'parametric'
|
|
611
|
-
return this
|
|
612
|
-
}
|
|
613
|
-
|
|
614
613
|
randomNearPoint = (k?: number): Point => {
|
|
615
614
|
const pt = this.randomPoint(k)
|
|
616
615
|
|
|
@@ -627,22 +626,12 @@ export class Line implements IPiMathObject<Line> {
|
|
|
627
626
|
|
|
628
627
|
randomPoint = (k?: number): Point => {
|
|
629
628
|
// Return a random point on the line.
|
|
630
|
-
const pt = this
|
|
629
|
+
const pt = this.d
|
|
631
630
|
.clone()
|
|
632
631
|
.multiplyByScalar(randomIntSym((k === undefined || k <= 1) ? 3 : k, false))
|
|
633
632
|
.add(this.#OA)
|
|
634
633
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
return pt
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
get reduceBeforeDisplay(): boolean {
|
|
641
|
-
return this.#reduceBeforeDisplay
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
set reduceBeforeDisplay(value: boolean) {
|
|
645
|
-
this.#reduceBeforeDisplay = value
|
|
634
|
+
return new Point(pt)
|
|
646
635
|
}
|
|
647
636
|
|
|
648
637
|
simplify = (): this => {
|
|
@@ -658,20 +647,7 @@ export class Line implements IPiMathObject<Line> {
|
|
|
658
647
|
return this
|
|
659
648
|
}
|
|
660
649
|
|
|
661
|
-
simplifyDirection = (): this => {
|
|
662
|
-
this.#d.simplify()
|
|
663
|
-
return this
|
|
664
|
-
}
|
|
665
|
-
|
|
666
650
|
get slope(): Fraction {
|
|
667
651
|
return this.#a.clone().opposite().divide(this.#b)
|
|
668
652
|
}
|
|
669
|
-
|
|
670
|
-
// ------------------------------------------
|
|
671
|
-
// Special functions
|
|
672
|
-
|
|
673
|
-
get system(): this {
|
|
674
|
-
this.#outputMode = 'system'
|
|
675
|
-
return this
|
|
676
|
-
}
|
|
677
653
|
}
|