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/triangle.ts
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import type {remarquableLines} from "../pimath.interface"
|
|
1
|
+
import {Fraction} from "../coefficients"
|
|
2
|
+
import {Line} from "./line"
|
|
3
|
+
import {Vector} from "./vector"
|
|
4
|
+
import {Point} from "./point"
|
|
5
|
+
import type {InputValue, remarquableLines} from "../pimath.interface"
|
|
6
|
+
import {Numeric} from "../numeric"
|
|
6
7
|
|
|
8
|
+
type TRIANGLE_SIDES = 'AB' | 'AC' | 'BC'
|
|
9
|
+
|
|
10
|
+
// TODO: add a check if it's a triangle or not.
|
|
7
11
|
export class Triangle {
|
|
12
|
+
// This defines the triangle
|
|
8
13
|
#A: Point = new Point()
|
|
9
14
|
#B: Point = new Point()
|
|
10
15
|
#C: Point = new Point()
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
'AB': new Point(),
|
|
18
|
-
'AC': new Point(),
|
|
19
|
-
'BC': new Point()
|
|
16
|
+
#isValid = false
|
|
17
|
+
// This is calculated
|
|
18
|
+
#lines: Record<TRIANGLE_SIDES, Line> | null = null
|
|
19
|
+
#radians = true
|
|
20
|
+
#remarquables: remarquableLines = {
|
|
21
|
+
mediators: null, medians: null, heights: null, externalBisectors: null, bisectors: null
|
|
20
22
|
}
|
|
21
|
-
#remarquables: remarquableLines | null = null
|
|
22
23
|
|
|
23
24
|
constructor(...values: unknown[]) {
|
|
24
|
-
|
|
25
25
|
if (values.length > 0) {
|
|
26
26
|
this.parse(...values)
|
|
27
27
|
}
|
|
@@ -29,26 +29,99 @@ export class Triangle {
|
|
|
29
29
|
return this
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
// Getter and setters
|
|
34
|
-
// ------------------------------------------
|
|
32
|
+
parse = (...values: unknown[]): this => {
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
if (values.length === 1) {
|
|
35
|
+
if (values[0] instanceof Triangle) {
|
|
36
|
+
return this.copy(values[0])
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (values.length === 3) {
|
|
41
|
+
// Possibilities:
|
|
42
|
+
// - Three points (or part of points, only dict for example, or array
|
|
43
|
+
// - Three lines
|
|
44
|
+
// - Three lines as text.
|
|
45
|
+
if (values.every((x: unknown) => typeof x === 'string')) {
|
|
46
|
+
// Three lines as text.
|
|
47
|
+
const [a, b, c] = values
|
|
48
|
+
return this.fromLines(a, b, c)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (values.every((x: unknown) => x instanceof Line)) {
|
|
52
|
+
// We have three lines
|
|
53
|
+
return this.fromLines(values[0], values[1], values[2])
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (values.every((x: unknown) => (x instanceof Point))) {
|
|
57
|
+
return this.fromPoints(values[0], values[1], values[2])
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (values.length === 6) {
|
|
62
|
+
const v: Fraction[] = values.map((x: unknown) => new Fraction(x as string))
|
|
63
|
+
|
|
64
|
+
if (v.some(x => x.isNaN())) {
|
|
65
|
+
throw new Error('One of the values is not a valid number')
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return this.fromCoordinates(v[0], v[1], v[2], v[3], v[4], v[5])
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return this
|
|
38
72
|
}
|
|
39
73
|
|
|
40
|
-
|
|
41
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Clone the Triangle class
|
|
76
|
+
*/
|
|
77
|
+
clone = (): Triangle => {
|
|
78
|
+
return new Triangle(
|
|
79
|
+
this.#A.clone(),
|
|
80
|
+
this.#B.clone(),
|
|
81
|
+
this.#C.clone()
|
|
82
|
+
)
|
|
42
83
|
}
|
|
43
84
|
|
|
44
|
-
|
|
45
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Copy the values from another triangle
|
|
87
|
+
* @param value
|
|
88
|
+
*/
|
|
89
|
+
copy(value: Triangle): this {
|
|
90
|
+
this.#A = value.A.clone()
|
|
91
|
+
this.#B = value.B.clone()
|
|
92
|
+
this.#C = value.C.clone()
|
|
93
|
+
|
|
94
|
+
return this
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get A(): Point {
|
|
98
|
+
return this.#A
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
set A(value: Point) {
|
|
102
|
+
this.#A = value
|
|
103
|
+
this.#A.onChange = () => this.reset()
|
|
104
|
+
this.reset()
|
|
46
105
|
}
|
|
47
106
|
|
|
48
107
|
get AB(): Vector {
|
|
49
108
|
return this.#getSegment('A', 'B')
|
|
50
109
|
}
|
|
51
110
|
|
|
111
|
+
get AC(): Vector {
|
|
112
|
+
return this.#getSegment('A', 'C')
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
get B(): Point {
|
|
116
|
+
return this.#B
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
set B(value: Point) {
|
|
120
|
+
this.#B = value
|
|
121
|
+
this.#B.onChange = () => this.reset()
|
|
122
|
+
this.reset()
|
|
123
|
+
}
|
|
124
|
+
|
|
52
125
|
get BA(): Vector {
|
|
53
126
|
return this.#getSegment('B', 'A')
|
|
54
127
|
}
|
|
@@ -57,298 +130,353 @@ export class Triangle {
|
|
|
57
130
|
return this.#getSegment('B', 'C')
|
|
58
131
|
}
|
|
59
132
|
|
|
60
|
-
get
|
|
61
|
-
return this.#
|
|
133
|
+
get C(): Point {
|
|
134
|
+
return this.#C
|
|
62
135
|
}
|
|
63
136
|
|
|
64
|
-
|
|
65
|
-
|
|
137
|
+
set C(value: Point) {
|
|
138
|
+
this.#C = value
|
|
139
|
+
this.#C.onChange = () => this.reset()
|
|
140
|
+
this.reset()
|
|
66
141
|
}
|
|
67
142
|
|
|
68
143
|
get CA(): Vector {
|
|
69
144
|
return this.#getSegment('C', 'A')
|
|
70
145
|
}
|
|
71
146
|
|
|
72
|
-
get
|
|
73
|
-
|
|
74
|
-
|
|
147
|
+
get CB(): Vector {
|
|
148
|
+
return this.#getSegment('C', 'B')
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
get asDegree(): this {
|
|
152
|
+
this.#radians = false
|
|
153
|
+
return this
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
get asRadians(): this {
|
|
157
|
+
this.#radians = true
|
|
158
|
+
return this
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
fromCoordinates(
|
|
162
|
+
x1: InputValue<Fraction>, y1: InputValue<Fraction>,
|
|
163
|
+
x2: InputValue<Fraction>, y2: InputValue<Fraction>,
|
|
164
|
+
x3: InputValue<Fraction>, y3: InputValue<Fraction>): this {
|
|
165
|
+
|
|
166
|
+
return this.fromPoints(
|
|
167
|
+
new Point(x1, y1),
|
|
168
|
+
new Point(x2, y2),
|
|
169
|
+
new Point(x3, y3),
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
fromLines(line1: Line | string, line2: Line | string, line3: Line | string): this {
|
|
174
|
+
const AB: Line = new Line(line1).clone()
|
|
175
|
+
const BC: Line = new Line(line2).clone()
|
|
176
|
+
const AC: Line = new Line(line3).clone()
|
|
177
|
+
|
|
178
|
+
// Get the intersection points -> build the triangle using these intersection points.
|
|
179
|
+
let intersect = AB.intersection(BC)
|
|
180
|
+
if (intersect.hasIntersection) {
|
|
181
|
+
this.#B = intersect.point
|
|
182
|
+
} else {
|
|
183
|
+
this.#isValid = false
|
|
184
|
+
return this
|
|
75
185
|
}
|
|
76
|
-
|
|
77
|
-
|
|
186
|
+
|
|
187
|
+
intersect = BC.intersection(AC)
|
|
188
|
+
if (intersect.hasIntersection) {
|
|
189
|
+
this.#C = intersect.point
|
|
190
|
+
} else {
|
|
191
|
+
this.#isValid = false
|
|
192
|
+
return this
|
|
78
193
|
}
|
|
79
|
-
|
|
80
|
-
|
|
194
|
+
|
|
195
|
+
intersect = AC.intersection(AB)
|
|
196
|
+
if (intersect.hasIntersection) {
|
|
197
|
+
this.#A = intersect.point
|
|
198
|
+
} else {
|
|
199
|
+
this.#isValid = false
|
|
200
|
+
return this
|
|
81
201
|
}
|
|
82
202
|
|
|
83
|
-
|
|
84
|
-
|
|
203
|
+
// reset the remarquables lines.
|
|
204
|
+
this.reset()
|
|
85
205
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
206
|
+
// Force the use of the given lines.
|
|
207
|
+
this.#lines = {AB, AC, BC}
|
|
208
|
+
|
|
209
|
+
return this
|
|
90
210
|
|
|
91
|
-
get isIsocele(): boolean {
|
|
92
|
-
return this.AB.normSquare.isEqual(this.BC.normSquare) ||
|
|
93
|
-
this.AB.normSquare.isEqual(this.AC.normSquare) ||
|
|
94
|
-
this.BC.normSquare.isEqual(this.AC.normSquare)
|
|
95
211
|
}
|
|
96
212
|
|
|
97
|
-
|
|
98
|
-
|
|
213
|
+
fromPoints(A: Point, B: Point, C: Point): this {
|
|
214
|
+
// We have three points.
|
|
215
|
+
this.#A = A.clone()
|
|
216
|
+
this.#B = B.clone()
|
|
217
|
+
this.#C = C.clone()
|
|
218
|
+
|
|
219
|
+
this.reset()
|
|
220
|
+
|
|
221
|
+
return this
|
|
99
222
|
}
|
|
100
223
|
|
|
101
|
-
|
|
102
|
-
|
|
224
|
+
getAngle(name: 'A' | 'B' | 'C'): number {
|
|
225
|
+
const a = this.BC.norm
|
|
226
|
+
const b = this.AC.norm
|
|
227
|
+
const c = this.AB.norm
|
|
228
|
+
|
|
229
|
+
if (name === 'A') {
|
|
230
|
+
return this.#cosThm(a, b, c)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (name === 'C') {
|
|
234
|
+
return this.#cosThm(c, b, a)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return this.#cosThm(b, a, c)
|
|
103
238
|
}
|
|
104
239
|
|
|
105
|
-
// ------------------------------------------
|
|
106
|
-
// Creation / parsing functions
|
|
107
|
-
// ------------------------------------------
|
|
108
240
|
|
|
109
|
-
|
|
110
|
-
* Parse values to a triangle. Supported formats:
|
|
111
|
-
* Vector2D, Vector2D, Vector2D
|
|
112
|
-
* x1, y1, x2, y2, x3, y3
|
|
113
|
-
* @param values
|
|
114
|
-
*/
|
|
115
|
-
parse = (...values: unknown[]): Triangle => {
|
|
116
|
-
if (values.length === 6) {
|
|
117
|
-
// Check if all values are number or fractions.
|
|
118
|
-
const v: Fraction[] = values.map((x: unknown) => new Fraction(x as string))
|
|
241
|
+
getBisectors(internal = true): { 'A': Line, 'B': Line, 'C': Line, 'intersection': Point | null } {
|
|
119
242
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
243
|
+
if (!this.#remarquables.bisectors) {
|
|
244
|
+
const A = this.#calculateBisectors('A', internal)
|
|
245
|
+
const B = this.#calculateBisectors('B', internal)
|
|
246
|
+
const C = this.#calculateBisectors('C', internal)
|
|
123
247
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
new Vector(v[2], v[3]),
|
|
127
|
-
new Vector(v[4], v[5]),
|
|
128
|
-
)
|
|
129
|
-
} else if (values.length === 3) {
|
|
130
|
-
// Possibilities:
|
|
131
|
-
// - Three points (or part of points, only dict for example, or array
|
|
132
|
-
// - Three lines
|
|
133
|
-
// - Three lines as text.
|
|
134
|
-
if (values.every((x: unknown) => typeof x === 'string')) {
|
|
135
|
-
// Three lines as text.
|
|
136
|
-
return this.parse(
|
|
137
|
-
...values.map((x) => {
|
|
138
|
-
return new Line(x)
|
|
139
|
-
})
|
|
140
|
-
)
|
|
141
|
-
} else if (values.every((x: unknown) => x instanceof Line)) {
|
|
142
|
-
// We have three lines
|
|
143
|
-
const AB: Line = (values[0]).clone()
|
|
144
|
-
const BC: Line = (values[1]).clone()
|
|
145
|
-
const AC: Line = (values[2]).clone()
|
|
146
|
-
this.#lines = { AB, BC, AC }
|
|
147
|
-
|
|
148
|
-
// Get the intersection points -> build the triangle using these intersection points.
|
|
149
|
-
let intersect = AB.intersection(BC)
|
|
150
|
-
if (intersect.hasIntersection) {
|
|
151
|
-
this.#B = intersect.point.clone()
|
|
152
|
-
} else {
|
|
153
|
-
throw new Error('Lines do not intersect !')
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
intersect = BC.intersection(AC)
|
|
157
|
-
if (intersect.hasIntersection) {
|
|
158
|
-
this.#C = intersect.point.clone()
|
|
159
|
-
} else {
|
|
160
|
-
throw new Error('Lines do not intersect !')
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
intersect = AC.intersection(AB)
|
|
164
|
-
if (intersect.hasIntersection) {
|
|
165
|
-
this.#A = intersect.point.clone()
|
|
166
|
-
} else {
|
|
167
|
-
throw new Error('Lines do not intersect !')
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
} else if (values.every((x: unknown) => (x instanceof Point))) {
|
|
171
|
-
// We have three points.
|
|
172
|
-
this.#A = (values[0]).clone()
|
|
173
|
-
this.#B = (values[1]).clone()
|
|
174
|
-
this.#C = (values[2]).clone()
|
|
175
|
-
this.#lines = {
|
|
176
|
-
'AB': new Line(this.#A, this.#B),
|
|
177
|
-
'BC': new Line(this.#B, this.#C),
|
|
178
|
-
'AC': new Line(this.#A, this.#C)
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
} else if (values.length === 1) {
|
|
182
|
-
if (values[0] instanceof Triangle) {
|
|
183
|
-
return values[0].clone()
|
|
184
|
-
}
|
|
248
|
+
const intersection = A.intersection(B).point
|
|
249
|
+
this.#remarquables.bisectors = {A, B, C, intersection}
|
|
185
250
|
}
|
|
186
251
|
|
|
187
|
-
this.#
|
|
188
|
-
return this
|
|
252
|
+
return this.#remarquables.bisectors
|
|
189
253
|
}
|
|
190
254
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
this.#A
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
255
|
+
getHeights(): { 'A': Line, 'B': Line, 'C': Line, 'intersection': Point | null } {
|
|
256
|
+
|
|
257
|
+
if (!this.#remarquables.heights) {
|
|
258
|
+
const A = new Line().fromPointAndNormal(this.#A, new Vector(this.#B, this.#C))
|
|
259
|
+
const B = new Line().fromPointAndNormal(this.#B, new Vector(this.#A, this.#C))
|
|
260
|
+
const C = new Line().fromPointAndNormal(this.#C, new Vector(this.#A, this.#B))
|
|
261
|
+
|
|
262
|
+
const intersection = A.intersection(B).point
|
|
263
|
+
this.#remarquables.heights = {A, B, C, intersection}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return this.#remarquables.heights
|
|
200
267
|
}
|
|
201
268
|
|
|
269
|
+
getMedians(): { 'A': Line, 'B': Line, 'C': Line, 'intersection': Point | null } {
|
|
270
|
+
const middles = this.getMiddles()
|
|
202
271
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
272
|
+
if (!this.#remarquables.medians) {
|
|
273
|
+
const A = new Line().fromPoints(this.#A, middles.BC)
|
|
274
|
+
const B = new Line().fromPoints(this.#B, middles.AC)
|
|
275
|
+
const C = new Line().fromPoints(this.#C, middles.AB)
|
|
206
276
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
this.#
|
|
212
|
-
|
|
213
|
-
|
|
277
|
+
const intersection = A.intersection(B).point
|
|
278
|
+
this.#remarquables.medians = {A, B, C, intersection}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return this.#remarquables.medians
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
getMediators(): { 'a': Line, 'b': Line, 'c': Line, 'intersection': Point | null } {
|
|
285
|
+
const middles = this.getMiddles()
|
|
214
286
|
|
|
215
|
-
this.#
|
|
287
|
+
if (!this.#remarquables.mediators) {
|
|
288
|
+
const a = new Line().fromPointAndNormal(middles.BC, new Vector(this.#B, this.#C))
|
|
289
|
+
const b = new Line().fromPointAndNormal(middles.AC, new Vector(this.#A, this.#C))
|
|
290
|
+
const c = new Line().fromPointAndNormal(middles.AB, new Vector(this.#A, this.#B))
|
|
291
|
+
|
|
292
|
+
const intersection = a.intersection(b).point
|
|
293
|
+
this.#remarquables.mediators = {a, b, c, intersection}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return this.#remarquables.mediators
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
getMiddles() {
|
|
300
|
+
return {
|
|
216
301
|
'AB': new Point().middleOf(this.#A, this.#B),
|
|
217
302
|
'AC': new Point().middleOf(this.#A, this.#C),
|
|
218
303
|
'BC': new Point().middleOf(this.#B, this.#C)
|
|
219
304
|
}
|
|
305
|
+
}
|
|
220
306
|
|
|
221
|
-
|
|
307
|
+
getPoints(): Point[] {
|
|
308
|
+
return [this.A, this.B, this.C]
|
|
222
309
|
}
|
|
223
310
|
|
|
311
|
+
getSortedPoints(): Point[] {
|
|
312
|
+
return this.getPoints().sort((a, b) => {
|
|
313
|
+
return a.x.value === b.x.value
|
|
314
|
+
? a.y.value - b.y.value
|
|
315
|
+
: a.x.value - b.x.value
|
|
316
|
+
})
|
|
317
|
+
}
|
|
224
318
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
case 'B':
|
|
234
|
-
return this.#B
|
|
235
|
-
case 'C':
|
|
236
|
-
return this.#C
|
|
237
|
-
}
|
|
319
|
+
isEqual(T: Triangle): boolean {
|
|
320
|
+
if (!this.#isValid || !T.isValid) return false
|
|
321
|
+
|
|
322
|
+
// TODO: compare points in a particular order.
|
|
323
|
+
const tri1 = this.getSortedPoints()
|
|
324
|
+
const tri2 = T.getSortedPoints()
|
|
325
|
+
|
|
326
|
+
return tri1.every((_, index) => tri1[index].isEqual(tri2[index]))
|
|
238
327
|
|
|
239
|
-
// Something went wrong ! Return the first point
|
|
240
|
-
return this.#A
|
|
241
328
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
)
|
|
329
|
+
|
|
330
|
+
isEquilateral(): boolean {
|
|
331
|
+
if (!this.#isValid) return false
|
|
332
|
+
|
|
333
|
+
const dAB = this.AB.normSquare.value
|
|
334
|
+
const dBC = this.BC.normSquare.value
|
|
335
|
+
const dAC = this.AC.normSquare.value
|
|
336
|
+
|
|
337
|
+
return (dAB === dBC) && (dAB === dAC)
|
|
252
338
|
}
|
|
253
339
|
|
|
254
|
-
|
|
340
|
+
isIsocele(): boolean {
|
|
341
|
+
if (!this.#isValid) return false
|
|
255
342
|
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
'C': new Line().fromPoints(this.#C, this.#middles.AB),
|
|
260
|
-
'intersection': null
|
|
261
|
-
}
|
|
343
|
+
const dAB = this.AB.normSquare.value
|
|
344
|
+
const dBC = this.BC.normSquare.value
|
|
345
|
+
const dAC = this.AC.normSquare.value
|
|
262
346
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
'intersection': null
|
|
268
|
-
}
|
|
347
|
+
return dAB === dBC ||
|
|
348
|
+
dAB === dAC ||
|
|
349
|
+
dBC === dAC
|
|
350
|
+
}
|
|
269
351
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
'B': new Line().fromPointAndNormal(this.#B, new Vector(this.#A, this.#C).normal()),
|
|
273
|
-
'C': new Line().fromPointAndNormal(this.#C, new Vector(this.#A, this.#B).normal()),
|
|
274
|
-
'intersection': null
|
|
275
|
-
}
|
|
352
|
+
isRectangle(): boolean {
|
|
353
|
+
if (!this.#isValid) return false
|
|
276
354
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
355
|
+
return this.AB.isNormalTo(this.BC) ||
|
|
356
|
+
this.AB.isNormalTo(this.AC) ||
|
|
357
|
+
this.BC.isNormalTo(this.AC)
|
|
358
|
+
}
|
|
280
359
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
'C': bB.internal,
|
|
285
|
-
'intersection': null
|
|
286
|
-
}
|
|
360
|
+
get isValid(): boolean {
|
|
361
|
+
return this.#isValid
|
|
362
|
+
}
|
|
287
363
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
'C': bC.external,
|
|
292
|
-
'intersection': null
|
|
293
|
-
}
|
|
364
|
+
set isValid(value: boolean) {
|
|
365
|
+
this.#isValid = value
|
|
366
|
+
}
|
|
294
367
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
368
|
+
get lines(): Record<TRIANGLE_SIDES, Line> {
|
|
369
|
+
if (this.#lines === null) {
|
|
370
|
+
this.#lines = {
|
|
371
|
+
'AB': new Line(this.#A, this.#B),
|
|
372
|
+
'BC': new Line(this.#B, this.#C),
|
|
373
|
+
'AC': new Line(this.#A, this.#C)
|
|
374
|
+
}
|
|
301
375
|
}
|
|
302
376
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
remarquables.mediators.intersection = remarquables.mediators.AB.intersection(remarquables.mediators.BC).point
|
|
306
|
-
remarquables.heights.intersection = remarquables.heights.A.intersection(remarquables.heights.B).point
|
|
307
|
-
remarquables.bisectors.intersection = remarquables.bisectors.A.intersection(remarquables.bisectors.B).point
|
|
377
|
+
return this.#lines
|
|
378
|
+
}
|
|
308
379
|
|
|
309
|
-
|
|
310
|
-
return
|
|
380
|
+
medianA(): Line {
|
|
381
|
+
return this.getMedians().A
|
|
311
382
|
}
|
|
312
383
|
|
|
313
|
-
|
|
384
|
+
medianB(): Line {
|
|
385
|
+
return this.getMedians().B
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
medianC(): Line {
|
|
389
|
+
return this.getMedians().C
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
get remarquables(): remarquableLines | null {
|
|
393
|
+
return this.#remarquables
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
public reset(): this {
|
|
397
|
+
// Check if the triangle is valid
|
|
398
|
+
// the three points must NOT be aligned.
|
|
399
|
+
this.#isValid = !this.AB.isColinearTo(this.AC)
|
|
400
|
+
|
|
401
|
+
this.#lines = null
|
|
402
|
+
this.#remarquables = {
|
|
403
|
+
mediators: null,
|
|
404
|
+
medians: null,
|
|
405
|
+
heights: null,
|
|
406
|
+
externalBisectors: null,
|
|
407
|
+
bisectors: null
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return this
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
#calculateBisectors(pt: string, internal = true): Line {
|
|
314
414
|
const tlines = this.lines
|
|
315
|
-
let d1
|
|
415
|
+
let d1: Vector = new Vector()
|
|
416
|
+
let d2: Vector = new Vector()
|
|
417
|
+
let P: Point = new Point()
|
|
316
418
|
|
|
317
419
|
if (pt === 'A') {
|
|
318
|
-
|
|
319
|
-
|
|
420
|
+
P = this.A.clone()
|
|
421
|
+
d1 = tlines.AB.clone().d
|
|
422
|
+
d2 = tlines.AC.clone().d
|
|
320
423
|
} else if (pt === 'B') {
|
|
321
|
-
|
|
322
|
-
|
|
424
|
+
P = this.B.clone()
|
|
425
|
+
d1 = tlines.AB.clone().d.opposite()
|
|
426
|
+
d2 = tlines.BC.clone().d
|
|
323
427
|
} else if (pt === 'C') {
|
|
324
|
-
|
|
325
|
-
|
|
428
|
+
P = this.C.clone()
|
|
429
|
+
d1 = tlines.BC.clone().d.opposite()
|
|
430
|
+
d2 = tlines.AC.clone().d.opposite()
|
|
326
431
|
}
|
|
327
432
|
|
|
328
433
|
if (d1 === undefined || d2 === undefined) {
|
|
329
434
|
throw new Error(`The point ${pt} does not exist`)
|
|
330
435
|
}
|
|
331
436
|
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
const d2Equ = d2.getEquation().multiply(d1n)
|
|
437
|
+
const director = internal
|
|
438
|
+
? d1.unit().add(d2.unit())
|
|
439
|
+
: d1.unit().subtract(d2.unit())
|
|
336
440
|
|
|
337
|
-
|
|
338
|
-
|
|
441
|
+
return new Line().fromPointAndDirection(P, director)
|
|
442
|
+
}
|
|
339
443
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
444
|
+
#cosThm(opposite: number, adjacent1: number, adjacent2: number): number {
|
|
445
|
+
const ratio = ((adjacent1 ** 2 + adjacent2 ** 2) - opposite ** 2) / (2 * adjacent1 * adjacent2)
|
|
446
|
+
|
|
447
|
+
return this.#radians
|
|
448
|
+
? Math.acos(ratio)
|
|
449
|
+
: Numeric.numberCorrection(Math.acos(ratio) * 180 / Math.PI)
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Get the Point class for the given name
|
|
454
|
+
* @param ptName
|
|
455
|
+
*/
|
|
456
|
+
#getPointByName = (ptName: string): Point => {
|
|
457
|
+
switch (ptName.toUpperCase()) {
|
|
458
|
+
case 'A':
|
|
459
|
+
return this.#A
|
|
460
|
+
case 'B':
|
|
461
|
+
return this.#B
|
|
462
|
+
case 'C':
|
|
463
|
+
return this.#C
|
|
349
464
|
}
|
|
350
465
|
|
|
351
|
-
//
|
|
352
|
-
return
|
|
466
|
+
// Something went wrong ! Return the first point
|
|
467
|
+
return this.#A
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Get the vector for the segment given by name.
|
|
472
|
+
* @param ptName1
|
|
473
|
+
* @param ptName2
|
|
474
|
+
*/
|
|
475
|
+
#getSegment = (ptName1: string, ptName2: string): Vector => {
|
|
476
|
+
return new Vector(
|
|
477
|
+
this.#getPointByName(ptName1),
|
|
478
|
+
this.#getPointByName(ptName2)
|
|
479
|
+
)
|
|
353
480
|
}
|
|
354
|
-
|
|
481
|
+
|
|
482
|
+
}
|